Second Patch for async RenderEngine

- pass a vector of <LayerSettings> instead of a vector of pointers to
drawLayers function to ensure lifecycle safety.
- capture all local variables to call drawLayerInternals in the render
engine thread to avoid of pointers being invalidated if it takes long
time to pop mFunctions calls.
- change renderScreenImplLocked return type as a shared_future
object to unblock SF main thread for screen capture events.
- block region sampling thread only when SF main thread hasn't
completed capture screen event.

Bug: 180657548
Test: SurfaceFlinger_test, android.hardware.graphics.composer@2.2-vts, libcompositionengine_test, librenderengine_test, libsurfaceflinger_unittest pass
Change-Id: I615f2927d30524988fb12df22fe331e7217c3058
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f98681e..6c60e53 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -48,7 +48,9 @@
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 
-void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+void BufferQueueLayer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
+    sp<Fence> releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence));
     mConsumer->setReleaseFence(releaseFence);
 
     // Prevent tracing the same release multiple times.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index a3bd725..dfdb5c0 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -42,7 +42,8 @@
     // Implements Layer.
     const char* getType() const override { return "BufferQueueLayer"; }
 
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
 
     // If a buffer was replaced this frame, release the former buffer
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 132ee9d..454363a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -70,69 +70,11 @@
     }
 }
 
-status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
-                                           const sp<Fence>& fence) {
-    if (ch == nullptr) {
-        return OK;
-    }
-    ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
-    if (!ch->previousReleaseFence.get()) {
-        ch->previousReleaseFence = fence;
-        return OK;
-    }
-
-    // Below logic is lifted from ConsumerBase.cpp:
-    // Check status of fences first because merging is expensive.
-    // Merging an invalid fence with any other fence results in an
-    // invalid fence.
-    auto currentStatus = ch->previousReleaseFence->getStatus();
-    if (currentStatus == Fence::Status::Invalid) {
-        ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
-        return BAD_VALUE;
-    }
-
-    auto incomingStatus = fence->getStatus();
-    if (incomingStatus == Fence::Status::Invalid) {
-        ALOGE("New fence has invalid state, layer: %s", mName.c_str());
-        ch->previousReleaseFence = fence;
-        return BAD_VALUE;
-    }
-
-    // If both fences are signaled or both are unsignaled, we need to merge
-    // them to get an accurate timestamp.
-    if (currentStatus == incomingStatus) {
-        char fenceName[32] = {};
-        snprintf(fenceName, 32, "%.28s", mName.c_str());
-        sp<Fence> mergedFence = Fence::merge(
-                fenceName, ch->previousReleaseFence, fence);
-        if (!mergedFence.get()) {
-            ALOGE("failed to merge release fences, layer: %s", mName.c_str());
-            // synchronization is broken, the best we can do is hope fences
-            // signal in order so the new fence will act like a union
-            ch->previousReleaseFence = fence;
-            return BAD_VALUE;
-        }
-        ch->previousReleaseFence = mergedFence;
-    } else if (incomingStatus == Fence::Status::Unsignaled) {
-        // If one fence has signaled and the other hasn't, the unsignaled
-        // fence will approximately correspond with the correct timestamp.
-        // There's a small race if both fences signal at about the same time
-        // and their statuses are retrieved with unfortunate timing. However,
-        // by this point, they will have both signaled and only the timestamp
-        // will be slightly off; any dependencies after this point will
-        // already have been met.
-        ch->previousReleaseFence = fence;
-    }
-    // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
-
-    return OK;
-}
-
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-
+void BufferStateLayer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
     // If a layer has been displayed again we may need to clear
     // the mLastClientComposition fence that we use for early release in setBuffer
     // (as we now have a new fence which won't pass through the client composition path in some cases
@@ -146,9 +88,6 @@
         mLastClientCompositionDisplayed = true;
     }
 
-    if (!releaseFence->isValid()) {
-        return;
-    }
     // The previous release fence notifies the client that SurfaceFlinger is done with the previous
     // buffer that was presented on this layer. The first transaction that came in this frame that
     // replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -173,17 +112,19 @@
             break;
         }
     }
-    auto status = addReleaseFence(ch, releaseFence);
-    if (status != OK) {
-        ALOGE("Failed to add release fence for layer %s", getName().c_str());
-    }
 
-    mPreviousReleaseFence = releaseFence;
+    mListPreviousReleaseFences.emplace_back(futureRenderEngineResult);
 
     // Prevent tracing the same release multiple times.
     if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
         mPreviousReleasedFrameNumber = mPreviousFrameNumber;
     }
+
+    if (ch != nullptr) {
+        ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
+        ch->previousReleaseFences.emplace_back(futureRenderEngineResult);
+        ch->name = mName;
+    }
 }
 
 void BufferStateLayer::onSurfaceFrameCreated(
@@ -231,9 +172,18 @@
     mFlinger->getTransactionCallbackInvoker().addCallbackHandles(
             mDrawingState.callbackHandles, jankData);
 
+    sp<Fence> releaseFence = Fence::NO_FENCE;
+    for (auto& handle : mDrawingState.callbackHandles) {
+        if (handle->releasePreviousBuffer &&
+            mDrawingState.releaseBufferEndpoint == handle->listener) {
+            releaseFence =
+                    handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE;
+            break;
+        }
+    }
+
     mDrawingState.callbackHandles = {};
 
-    const sp<Fence>& releaseFence(mPreviousReleaseFence);
     std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 87b68ea..6cb9b35 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,9 @@
     // Implements Layer.
     const char* getType() const override { return "BufferStateLayer"; }
 
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
     void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -115,8 +117,6 @@
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
                                  nsecs_t requestedPresentTime);
 
-    status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
-
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
@@ -139,7 +139,7 @@
     std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData(
             const BufferData& bufferData);
 
-    sp<Fence> mPreviousReleaseFence;
+    std::vector<std::shared_future<renderengine::RenderEngineResult>> mListPreviousReleaseFences;
     ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
     uint64_t mPreviousReleasedFrameNumber = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f7b71cf..ac243c0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <future>
 #include <optional>
 #include <ostream>
 #include <unordered_set>
@@ -26,6 +27,7 @@
 #pragma clang diagnostic ignored "-Wextra"
 
 #include <renderengine/LayerSettings.h>
+#include <renderengine/RenderEngine.h>
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -151,7 +153,7 @@
             ClientCompositionTargetSettings&) = 0;
 
     // Called after the layer is displayed to update the presentation fence
-    virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+    virtual void onLayerDisplayed(std::shared_future<renderengine::RenderEngineResult>) = 0;
 
     // Gets some kind of identifier for the layer for debug purposes.
     virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index d215bda..16aebef 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -39,7 +39,7 @@
                  std::vector<compositionengine::LayerFE::LayerSettings>(
                          compositionengine::LayerFE::ClientCompositionTargetSettings&));
 
-    MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
+    MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<renderengine::RenderEngineResult>));
 
     MOCK_CONST_METHOD0(getDebugName, const char*());
     MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 048d7c2..7ea1aa2 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -27,6 +27,7 @@
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/impl/planner/Planner.h>
+#include <ftl/future.h>
 
 #include <thread>
 
@@ -1097,12 +1098,12 @@
         setExpensiveRenderingExpected(true);
     }
 
-    std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
-    clientCompositionLayerPointers.reserve(clientCompositionLayers.size());
+    std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+    clientRenderEngineLayers.reserve(clientCompositionLayers.size());
     std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
-                   std::back_inserter(clientCompositionLayerPointers),
-                   [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* {
-                       return &settings;
+                   std::back_inserter(clientRenderEngineLayers),
+                   [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings {
+                       return settings;
                    });
 
     const nsecs_t renderEngineStart = systemTime();
@@ -1115,7 +1116,7 @@
     const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
     auto [status, drawFence] =
             renderEngine
-                    .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
+                    .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
                                 useFramebufferCache, std::move(fd))
                     .get();
 
@@ -1295,8 +1296,10 @@
             releaseFence =
                     Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
         }
-
-        layer->getLayerFE().onLayerDisplayed(releaseFence);
+        layer->getLayerFE().onLayerDisplayed(
+                ftl::yield<renderengine::RenderEngineResult>(
+                        {NO_ERROR, base::unique_fd(releaseFence->dup())})
+                        .share());
     }
 
     // We've got a list of layers needing fences, that are disjoint with
@@ -1304,7 +1307,9 @@
     // supply them with the present fence.
     for (auto& weakLayer : mReleasedLayers) {
         if (auto layer = weakLayer.promote(); layer != nullptr) {
-            layer->onLayerDisplayed(frame.presentFence);
+            layer->onLayerDisplayed(ftl::yield<renderengine::RenderEngineResult>(
+                                            {NO_ERROR, base::unique_fd(frame.presentFence->dup())})
+                                            .share());
         }
     }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index e6b716e..ec52e59 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -193,11 +193,6 @@
                              clientCompositionList.cend());
     }
 
-    std::vector<const renderengine::LayerSettings*> layerSettingsPointers;
-    std::transform(layerSettings.cbegin(), layerSettings.cend(),
-                   std::back_inserter(layerSettingsPointers),
-                   [](const renderengine::LayerSettings& settings) { return &settings; });
-
     renderengine::LayerSettings blurLayerSettings;
     if (mBlurLayer) {
         auto blurSettings = targetSettings;
@@ -212,7 +207,7 @@
         blurLayerSettings.name = std::string("blur layer");
         // Clear out the shadow settings
         blurLayerSettings.shadow = {};
-        layerSettingsPointers.push_back(&blurLayerSettings);
+        layerSettings.push_back(blurLayerSettings);
     }
 
     renderengine::LayerSettings holePunchSettings;
@@ -230,7 +225,7 @@
         holePunchSettings.disableBlending = true;
         holePunchSettings.alpha = 0.0f;
         holePunchSettings.name = std::string("hole punch layer");
-        layerSettingsPointers.push_back(&holePunchSettings);
+        layerSettings.push_back(holePunchSettings);
 
         // Add a solid background as the first layer in case there is no opaque
         // buffer behind the punch hole
@@ -239,7 +234,7 @@
         holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries;
         holePunchBackgroundSettings.geometry.positionTransform =
                 holePunchSettings.geometry.positionTransform;
-        layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings);
+        layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings);
     }
 
     if (sDebugHighlighLayers) {
@@ -257,7 +252,7 @@
                 .alpha = half(0.05f),
         };
 
-        layerSettingsPointers.emplace_back(&highlight);
+        layerSettings.emplace_back(highlight);
     }
 
     auto texture = texturePool.borrowTexture();
@@ -273,8 +268,8 @@
     }
 
     auto [status, drawFence] = renderEngine
-                                       .drawLayers(displaySettings, layerSettingsPointers,
-                                                   texture->get(), false, std::move(bufferFence))
+                                       .drawLayers(displaySettings, layerSettings, texture->get(),
+                                                   false, std::move(bufferFence))
                                        .get();
 
     if (status == NO_ERROR) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 8f0028c..cf63ef5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -24,6 +24,7 @@
 #include <compositionengine/mock/LayerFE.h>
 #include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
+#include <ftl/future.h>
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <ui/Rect.h>
@@ -2884,12 +2885,24 @@
     // are passed. This happens to work with the current implementation, but
     // would not survive certain calls like Fence::merge() which would return a
     // new instance.
-    EXPECT_CALL(*mLayer1.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer1Fence.get()))));
-    EXPECT_CALL(*mLayer2.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer2Fence.get()))));
-    EXPECT_CALL(*mLayer3.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer3Fence.get()))));
+    base::unique_fd layer1FD(layer1Fence->dup());
+    base::unique_fd layer2FD(layer2Fence->dup());
+    base::unique_fd layer3FD(layer3Fence->dup());
+    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer1FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer2FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer3FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence);
+            });
 
     mOutput.postFramebuffer();
 }
@@ -2915,9 +2928,9 @@
     // Fence::merge is called, and since none of the fences are actually valid,
     // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call.
     // This is the best we can do without creating a real kernel fence object.
-    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE));
-    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE));
-    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE));
+    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return());
+    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return());
+    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return());
 
     mOutput.postFramebuffer();
 }
@@ -2949,12 +2962,22 @@
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
     // Each released layer should be given the presentFence.
-    EXPECT_CALL(*releasedLayer1,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
-    EXPECT_CALL(*releasedLayer2,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
-    EXPECT_CALL(*releasedLayer3,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
+    base::unique_fd layerFD(presentFence.get()->dup());
+    EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
 
     mOutput.postFramebuffer();
 
@@ -3131,9 +3154,9 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3161,11 +3184,11 @@
                     }));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3196,11 +3219,11 @@
                     }));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3226,7 +3249,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .Times(2)
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
@@ -3258,7 +3281,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -3294,11 +3317,11 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
             .WillOnce(Return(mOutputBuffer))
             .WillOnce(Return(otherOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3330,10 +3353,10 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
 
@@ -3487,9 +3510,9 @@
         EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
                 .WillRepeatedly(
                         [&](const renderengine::DisplaySettings&,
-                            const std::vector<const renderengine::LayerSettings*>&,
+                            const std::vector<renderengine::LayerSettings>&,
                             const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                            base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                            base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                             return futureOf<renderengine::RenderEngineResult>(
                                     {NO_ERROR, base::unique_fd()});
                         });
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index ecb05f8..42b3d97 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -346,15 +346,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
     };
@@ -398,15 +398,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -453,15 +453,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -656,26 +656,26 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
         {
-            const auto* holePunchSettings = layers[3];
-            EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
-            EXPECT_TRUE(holePunchSettings->disableBlending);
-            EXPECT_EQ(0.0f, holePunchSettings->alpha);
+            const auto holePunchSettings = layers[3];
+            EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+            EXPECT_TRUE(holePunchSettings.disableBlending);
+            EXPECT_EQ(0.0f, holePunchSettings.alpha);
         }
 
         {
-            const auto* holePunchBackgroundSettings = layers[0];
-            EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
-            EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
-            EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+            const auto holePunchBackgroundSettings = layers[0];
+            EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+            EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+            EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -717,27 +717,27 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
 
         {
-            const auto* holePunchSettings = layers[3];
-            EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
-            EXPECT_TRUE(holePunchSettings->disableBlending);
-            EXPECT_EQ(0.0f, holePunchSettings->alpha);
+            const auto holePunchSettings = layers[3];
+            EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+            EXPECT_TRUE(holePunchSettings.disableBlending);
+            EXPECT_EQ(0.0f, holePunchSettings.alpha);
         }
 
         {
-            const auto* holePunchBackgroundSettings = layers[0];
-            EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
-            EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
-            EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+            const auto holePunchBackgroundSettings = layers[0];
+            EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+            EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+            EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -867,16 +867,16 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 3u);
-        const auto* blurSettings = layers[2];
-        EXPECT_TRUE(blurSettings->skipContentDraw);
-        EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor);
-        EXPECT_EQ(0.0f, blurSettings->alpha);
+        const auto blurSettings = layers[2];
+        EXPECT_TRUE(blurSettings.skipContentDraw);
+        EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor);
+        EXPECT_EQ(0.0f, blurSettings.alpha);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
     };
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5707c67..d68cf97 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -221,7 +221,8 @@
  * Layer.  So, the implementation is done in BufferLayer.  When called on a
  * EffectLayer object, it's essentially a NOP.
  */
-void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
+void Layer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> /*futureRenderEngineResult*/) {}
 
 void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
     if (mDrawingState.zOrderRelativeOf == nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 07b2eb5..4569f9a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -616,7 +616,8 @@
     void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
     std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
 
     void setWasClientComposed(const sp<Fence>& fence) override {
         mLastClientCompositionFence = fence;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index aa2fec5..d0f56b5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -356,10 +356,13 @@
                                                renderengine::ExternalTexture::Usage::WRITEABLE);
     }
 
-    const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-    mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                                 true /* regionSampling */, false /* grayscale */, captureListener);
-    ScreenCaptureResults captureResults = captureListener->waitForResults();
+    auto captureScreenResultFuture =
+            mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+                                         true /* regionSampling */, false /* grayscale */, nullptr);
+    auto& captureScreenResult = captureScreenResultFuture.get();
+    if (captureScreenResult.drawFence.ok()) {
+        sync_wait(captureScreenResult.drawFence.get(), -1);
+    }
 
     std::vector<Descriptor> activeDescriptors;
     for (const auto& descriptor : descriptors) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index acb81dc..638458c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5972,9 +5972,10 @@
         traverseLayersInLayerStack(layerStack, args.uid, visitor);
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, args.grayscale,
-                               captureListener);
+    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+                                                   reqSize, args.pixelFormat, args.allowProtected,
+                                                   args.grayscale, captureListener);
+    return captureResultFuture.get().status;
 }
 
 status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -6009,9 +6010,15 @@
         traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                               ui::PixelFormat::RGBA_8888, false /* allowProtected */,
-                               false /* grayscale */, captureListener);
+    if (captureListener == nullptr) {
+        ALOGE("capture screen must provide a capture listener callback");
+        return BAD_VALUE;
+    }
+    auto captureResultFuture =
+            captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+                                ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+                                false /* grayscale */, captureListener);
+    return captureResultFuture.get().status;
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6138,23 +6145,28 @@
         });
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, args.grayscale,
-                               captureListener);
+    if (captureListener == nullptr) {
+        ALOGE("capture screen must provide a capture listener callback");
+        return BAD_VALUE;
+    }
+
+    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+                                                   reqSize, args.pixelFormat, args.allowProtected,
+                                                   args.grayscale, captureListener);
+    return captureResultFuture.get().status;
 }
 
-status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
-                                             TraverseLayersFunction traverseLayers,
-                                             ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
-                                             bool allowProtected, bool grayscale,
-                                             const sp<IScreenCaptureListener>& captureListener) {
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+        RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
+        ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
+        const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
     if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
         ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
               ") that exceeds render target size limit.",
               bufferSize.getWidth(), bufferSize.getHeight());
-        return BAD_VALUE;
+        return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
     }
 
     // Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6194,25 +6206,23 @@
                                false /* regionSampling */, grayscale, captureListener);
 }
 
-status_t SurfaceFlinger::captureScreenCommon(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
         bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
-    if (captureListener == nullptr) {
-        ALOGE("capture screen must provide a capture listener callback");
-        return BAD_VALUE;
-    }
-
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
-    static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
+    auto scheduleResultFuture = schedule([=,
+                                          renderAreaFuture = std::move(renderAreaFuture)]() mutable
+                                         -> std::shared_future<renderengine::RenderEngineResult> {
         if (mRefreshPending) {
             ALOGW("Skipping screenshot for now");
             captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
                                 grayscale, captureListener);
-            return;
+            return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
+                    .share();
         }
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
@@ -6220,24 +6230,44 @@
             ALOGW("Skipping screen capture because of invalid render area.");
             captureResults.result = NO_MEMORY;
             captureListener->onScreenCaptureCompleted(captureResults);
-            return;
+            return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
+                    .share();
         }
 
-        status_t result = NO_ERROR;
+        std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
+
         renderArea->render([&] {
-            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
-                                            canCaptureBlackoutContent, regionSampling, grayscale,
-                                            captureResults);
+            renderEngineResultFuture =
+                    renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+                                           canCaptureBlackoutContent, regionSampling, grayscale,
+                                           captureResults);
         });
+        // spring up a thread to unblock SF main thread and wait for
+        // RenderEngineResult to be available
+        if (captureListener != nullptr) {
+            std::async([=]() mutable {
+                ATRACE_NAME("captureListener is nonnull!");
+                auto& [status, drawFence] = renderEngineResultFuture.get();
+                captureResults.result = status;
+                captureResults.fence = new Fence(dup(drawFence));
+                captureListener->onScreenCaptureCompleted(captureResults);
+            });
+        }
+        return renderEngineResultFuture;
+    });
 
-        captureResults.result = result;
-        captureListener->onScreenCaptureCompleted(captureResults);
-    }));
-
-    return NO_ERROR;
+    // flatten scheduleResultFuture object to single shared_future object
+    std::future<renderengine::RenderEngineResult> captureScreenResultFuture =
+            ftl::chain(std::move(scheduleResultFuture))
+                    .then([=](std::shared_future<renderengine::RenderEngineResult> futureObject)
+                                  -> renderengine::RenderEngineResult {
+                        auto& [status, drawFence] = futureObject.get();
+                        return {status, base::unique_fd(dup(drawFence))};
+                    });
+    return captureScreenResultFuture.share();
 }
 
-status_t SurfaceFlinger::renderScreenImplLocked(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImplLocked(
         const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6256,7 +6286,8 @@
     // the impetus on WindowManager to not persist them.
     if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
         ALOGW("FB is protected: PERMISSION_DENIED");
-        return PERMISSION_DENIED;
+        return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
+                .share();
     }
 
     captureResults.buffer = buffer->getBuffer();
@@ -6338,11 +6369,12 @@
 
     });
 
-    std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers(
-            clientCompositionLayers.size());
+    std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+    clientRenderEngineLayers.reserve(clientCompositionLayers.size());
     std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
-                   clientCompositionLayerPointers.begin(),
-                   std::pointer_traits<renderengine::LayerSettings*>::pointer_to);
+                   std::back_inserter(clientRenderEngineLayers),
+                   [](compositionengine::LayerFE::LayerSettings& settings)
+                           -> renderengine::LayerSettings { return settings; });
 
     // Use an empty fence for the buffer fence, since we just created the buffer so
     // there is no need for synchronization with the GPU.
@@ -6350,24 +6382,22 @@
     getRenderEngine().useProtectedContext(useProtected);
 
     const constexpr bool kUseFramebufferCache = false;
-    auto [status, drawFence] =
-            getRenderEngine()
-                    .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
-                                kUseFramebufferCache, std::move(bufferFence))
-                    .get();
+    std::future<renderengine::RenderEngineResult> drawLayersResult =
+            getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
+                                         kUseFramebufferCache, std::move(bufferFence));
 
-    if (drawFence >= 0) {
-        sp<Fence> releaseFence = new Fence(dup(drawFence));
-        for (auto* layer : renderedLayers) {
-            layer->onLayerDisplayed(releaseFence);
-        }
+    std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
+            drawLayersResult.share(); // drawLayersResult will be moved to shared one
+
+    for (auto* layer : renderedLayers) {
+        // make a copy of shared_future object for each layer
+        layer->onLayerDisplayed(drawLayersResultFuture);
     }
 
-    captureResults.fence = new Fence(drawFence.release());
     // Always switch back to unprotected context.
     getRenderEngine().useProtectedContext(false);
 
-    return status;
+    return drawLayersResultFuture;
 }
 
 void SurfaceFlinger::windowInfosReported() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1f0e42d..45fd94e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -906,17 +906,17 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
-                                 ui::PixelFormat, bool allowProtected, bool grayscale,
-                                 const sp<IScreenCaptureListener>&);
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
-                                 const std::shared_ptr<renderengine::ExternalTexture>&,
-                                 bool regionSampling, bool grayscale,
-                                 const sp<IScreenCaptureListener>&);
-    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
-                                    const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    bool canCaptureBlackoutContent, bool regionSampling,
-                                    bool grayscale, ScreenCaptureResults&);
+    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+            RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat,
+            bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&);
+    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+            RenderAreaFuture, TraverseLayersFunction,
+            const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
+            bool grayscale, const sp<IScreenCaptureListener>&);
+    std::shared_future<renderengine::RenderEngineResult> renderScreenImplLocked(
+            const RenderArea&, TraverseLayersFunction,
+            const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
+            bool regionSampling, bool grayscale, ScreenCaptureResults&);
 
     // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
     // matching ownerUid
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index c1eb896..8fbf0b4 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -154,6 +154,38 @@
     // destroyed the client side is dead and there won't be anyone to send the callback to.
     sp<IBinder> surfaceControl = handle->surfaceControl.promote();
     if (surfaceControl) {
+        sp<Fence> prevFence = nullptr;
+
+        for (const auto& futureStruct : handle->previousReleaseFences) {
+            sp<Fence> currentFence = sp<Fence>::make(dup(futureStruct.get().drawFence));
+            if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
+                prevFence = currentFence;
+                handle->previousReleaseFence = prevFence;
+            } else if (prevFence != nullptr) {
+                // If both fences are signaled or both are unsignaled, we need to merge
+                // them to get an accurate timestamp.
+                if (prevFence->getStatus() != Fence::Status::Invalid &&
+                    prevFence->getStatus() == currentFence->getStatus()) {
+                    char fenceName[32] = {};
+                    snprintf(fenceName, 32, "%.28s", handle->name.c_str());
+                    sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
+                    if (mergedFence->isValid()) {
+                        handle->previousReleaseFence = mergedFence;
+                        prevFence = handle->previousReleaseFence;
+                    }
+                } else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
+                    // If one fence has signaled and the other hasn't, the unsignaled
+                    // fence will approximately correspond with the correct timestamp.
+                    // There's a small race if both fences signal at about the same time
+                    // and their statuses are retrieved with unfortunate timing. However,
+                    // by this point, they will have both signaled and only the timestamp
+                    // will be slightly off; any dependencies after this point will
+                    // already have been met.
+                    handle->previousReleaseFence = currentFence;
+                }
+            }
+        }
+        handle->previousReleaseFences = {};
         FrameEventHistoryStats eventStats(handle->frameNumber,
                                           handle->gpuCompositionDoneFence->getSnapshot().fence,
                                           handle->compositorTiming, handle->refreshStartTime,
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 7e879e1..100dbfa 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,8 +18,9 @@
 
 #include <condition_variable>
 #include <deque>
-#include <queue>
+#include <future>
 #include <mutex>
+#include <queue>
 #include <thread>
 #include <unordered_map>
 #include <unordered_set>
@@ -28,6 +29,7 @@
 
 #include <binder/IBinder.h>
 #include <gui/ITransactionCompletedListener.h>
+#include <renderengine/RenderEngine.h>
 #include <ui/Fence.h>
 
 namespace android {
@@ -42,7 +44,9 @@
     wp<IBinder> surfaceControl;
 
     bool releasePreviousBuffer = false;
+    std::string name;
     sp<Fence> previousReleaseFence;
+    std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
     nsecs_t acquireTime = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 5135ff9..61c7c39 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -247,10 +247,16 @@
                                                              "screenshot"),
                                            *mRenderEngine, true);
 
-    status_t result =
-            mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
-                                            forSystem, regionSampling);
-    EXPECT_EQ(NO_ERROR, result);
+    auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
+                                                  forSystem, regionSampling);
+    EXPECT_TRUE(result.valid());
+
+    auto& [status, drawFence] = result.get();
+
+    EXPECT_EQ(NO_ERROR, status);
+    if (drawFence.ok()) {
+        sync_wait(drawFence.get(), -1);
+    }
 
     LayerCase::cleanup(this);
 }
@@ -346,9 +352,9 @@
     static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
-                                    const std::vector<const renderengine::LayerSettings*>&,
+                                    const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd &&)
+                                    const bool, base::unique_fd&&)
                                         -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -397,9 +403,9 @@
                                 Return(0)));
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
-                                    const std::vector<const renderengine::LayerSettings*>&,
+                                    const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd &&)
+                                    const bool, base::unique_fd&&)
                                         -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -633,9 +639,9 @@
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -652,16 +658,16 @@
                                          "verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
-                    EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
-                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
-                    EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
-                    EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
-                    EXPECT_EQ(false, layer->source.buffer.isOpaque);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
+                    EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
+                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
+                    EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
+                    EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
+                    EXPECT_EQ(false, layer.source.buffer.isOpaque);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
                 });
     }
@@ -685,9 +691,9 @@
     static void setupREColorCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -704,14 +710,14 @@
                                    "setupREColorCompositionCallExpectations verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
                     EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                     LayerProperties::COLOR[2]),
-                              layer->source.solidColor);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+                              layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
                 });
     }
@@ -765,9 +771,9 @@
     static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -784,12 +790,12 @@
                                          "verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
-                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(1.0f, layer->alpha);
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(1.0f, layer.alpha);
                     return resultFuture;
                 });
     }