SF: Do not duplicate fences per layer per frame
Convert the unique_fd of RenderEngineResult (and futures thereof) into
sp<Fence> such that postFramebuffer does not duplicate release/present
fences.
Remove a few copies of shared futures/pointers with std::move.
Bug: 232436803
Test: simpleperf (-33% cycles in sys_dup)
Change-Id: Ia7c6c8333a712441f3612fb5c720ea2932799636
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e72e21c..d8a2696 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6410,10 +6410,10 @@
traverseLayersInLayerStack(layerStack, args.uid, visitor);
};
- auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
- reqSize, args.pixelFormat, args.allowProtected,
- args.grayscale, captureListener);
- return captureResultFuture.get().status;
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, args.allowProtected, args.grayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -6452,11 +6452,14 @@
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;
+
+ constexpr bool kAllowProtected = false;
+ constexpr bool kGrayscale = false;
+
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+ ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6568,13 +6571,13 @@
return BAD_VALUE;
}
- auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
- reqSize, args.pixelFormat, args.allowProtected,
- args.grayscale, captureListener);
- return captureResultFuture.get().status;
+ auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, args.allowProtected, args.grayscale,
+ captureListener);
+ return fenceStatus(future.get());
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+std::shared_future<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>& captureListener) {
@@ -6584,7 +6587,7 @@
ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
") that exceeds render target size limit.",
bufferSize.getWidth(), bufferSize.getHeight());
- return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
+ return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share();
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6626,7 +6629,7 @@
false /* regionSampling */, grayscale, captureListener);
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+std::shared_future<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
@@ -6634,59 +6637,53 @@
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
- auto scheduleResultFuture = mScheduler->schedule([=,
- renderAreaFuture =
- std::move(renderAreaFuture)]() mutable
- -> std::shared_future<
- renderengine::RenderEngineResult> {
+ auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable
+ -> std::shared_future<FenceResult> {
ScreenCaptureResults captureResults;
std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
if (!renderArea) {
ALOGW("Skipping screen capture because of invalid render area.");
captureResults.result = NO_MEMORY;
captureListener->onScreenCaptureCompleted(captureResults);
- return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
- .share();
+ return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
- std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
-
+ std::shared_future<FenceResult> renderFuture;
renderArea->render([&] {
- renderEngineResultFuture =
- renderScreenImpl(*renderArea, traverseLayers, buffer,
- canCaptureBlackoutContent, regionSampling, grayscale,
- captureResults);
+ renderFuture =
+ renderScreenImpl(*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) {
+
+ if (captureListener) {
+ // TODO: The future returned by std::async blocks the main thread. Return a chain of
+ // futures to the Binder thread instead.
std::async([=]() mutable {
ATRACE_NAME("captureListener is nonnull!");
- auto& [status, drawFence] = renderEngineResultFuture.get();
- captureResults.result = status;
- captureResults.fence = new Fence(dup(drawFence));
+ auto fenceResult = renderFuture.get();
+ // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult.
+ captureResults.result = fenceStatus(fenceResult);
+ captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
captureListener->onScreenCaptureCompleted(captureResults);
});
}
- return renderEngineResultFuture;
+ return renderFuture;
});
- // flatten scheduleResultFuture object to single shared_future object
- if (captureListener == nullptr) {
- 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();
- } else {
- return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}).share();
+ if (captureListener) {
+ return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
+
+ // Flatten nested futures.
+ std::future<FenceResult> chain =
+ ftl::chain(std::move(future)).then([](std::shared_future<FenceResult> future) {
+ return future.get();
+ });
+
+ return chain.share();
}
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImpl(
+std::shared_future<FenceResult> SurfaceFlinger::renderScreenImpl(
const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6705,8 +6702,7 @@
// the impetus on WindowManager to not persist them.
if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
ALOGW("FB is protected: PERMISSION_DENIED");
- return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
- .share();
+ return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
}
captureResults.buffer = buffer->getBuffer();
@@ -6827,23 +6823,22 @@
base::unique_fd bufferFence;
getRenderEngine().useProtectedContext(useProtected);
- const constexpr bool kUseFramebufferCache = false;
- std::future<renderengine::RenderEngineResult> drawLayersResult =
- getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
- kUseFramebufferCache, std::move(bufferFence));
+ constexpr bool kUseFramebufferCache = false;
+ std::future<FenceResult> chain =
+ ftl::chain(getRenderEngine().drawLayers(clientCompositionDisplay,
+ clientRenderEngineLayers, buffer,
+ kUseFramebufferCache, std::move(bufferFence)))
+ .then(&toFenceResult);
- std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
- drawLayersResult.share(); // drawLayersResult will be moved to shared one
-
+ const auto future = chain.share();
for (auto* layer : renderedLayers) {
- // make a copy of shared_future object for each layer
- layer->onLayerDisplayed(drawLayersResultFuture);
+ layer->onLayerDisplayed(future);
}
// Always switch back to unprotected context.
getRenderEngine().useProtectedContext(false);
- return drawLayersResultFuture;
+ return future;
}
void SurfaceFlinger::windowInfosReported() {