Loading include/ftl/details/future.h +19 −0 Original line number Diff line number Diff line Loading @@ -73,8 +73,18 @@ class BaseFuture<Self, T, std::future> { return std::get<Impl>(self()).get(); } template <class Rep, class Period> std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const { if (std::holds_alternative<T>(self())) { return std::future_status::ready; } return std::get<Impl>(self()).wait_for(timeout_duration); } private: auto& self() { return static_cast<Self&>(*this).future_; } const auto& self() const { return static_cast<const Self&>(*this).future_; } }; template <typename Self, typename T> Loading @@ -90,6 +100,15 @@ class BaseFuture<Self, T, std::shared_future> { return std::get<Impl>(self()).get(); } template <class Rep, class Period> std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const { if (std::holds_alternative<T>(self())) { return std::future_status::ready; } return std::get<Impl>(self()).wait_for(timeout_duration); } private: const auto& self() const { return static_cast<const Self&>(*this).future_; } }; Loading include/ftl/future.h +1 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, Future // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the // following are defined for either FutureImpl: using Base::get; using Base::wait_for; // Attaches a continuation to the future. The continuation is a function that maps T to either R // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by Loading libs/ftl/future_test.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -102,4 +102,42 @@ TEST(Future, Chain) { decrement_thread.join(); } TEST(Future, WaitFor) { using namespace std::chrono_literals; { auto future = ftl::yield(42); // Check that we can wait_for multiple times without invalidating the future EXPECT_EQ(future.wait_for(1s), std::future_status::ready); EXPECT_EQ(future.wait_for(1s), std::future_status::ready); EXPECT_EQ(future.get(), 42); } { std::condition_variable cv; std::mutex m; bool ready = false; std::packaged_task<int32_t()> get_int([&] { std::unique_lock lk(m); cv.wait(lk, [&] { return ready; }); return 24; }); auto get_future = ftl::Future(get_int.get_future()); std::thread get_thread(std::move(get_int)); EXPECT_EQ(get_future.wait_for(0s), std::future_status::timeout); { std::unique_lock lk(m); ready = true; } cv.notify_one(); EXPECT_EQ(get_future.wait_for(1s), std::future_status::ready); EXPECT_EQ(get_future.get(), 24); get_thread.join(); } } } // namespace android::test services/surfaceflinger/Layer.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -78,11 +78,13 @@ #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "Utils/FenceUtils.h" #define DEBUG_RESIZE 0 #define EARLY_RELEASE_ENABLED false namespace android { using namespace std::chrono_literals; namespace { constexpr int kDumpTableRowLength = 159; Loading Loading @@ -2911,7 +2913,8 @@ void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& l } void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, ui::LayerStack layerStack) { ui::LayerStack layerStack, std::function<FenceResult(FenceResult)>&& continuation) { // If we are displayed on multiple displays in a single composition cycle then we would // need to do careful tracking to enable the use of the mLastClientCompositionFence. // For example we can only use it if all the displays are client comp, and we need Loading Loading @@ -2946,11 +2949,41 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, break; } } if (!FlagManager::getInstance().screenshot_fence_preservation() && continuation) { futureFenceResult = ftl::Future(futureFenceResult).then(std::move(continuation)).share(); } if (ch != nullptr) { ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); ch->name = mName; } else if (FlagManager::getInstance().screenshot_fence_preservation()) { // If we didn't get a release callback yet, e.g. some scenarios when capturing screenshots // asynchronously, then make sure we don't drop the fence. mAdditionalPreviousReleaseFences.emplace_back(std::move(futureFenceResult), std::move(continuation)); std::vector<FenceAndContinuation> mergedFences; sp<Fence> prevFence = nullptr; // For a layer that's frequently screenshotted, try to merge fences to make sure we don't // grow unbounded. for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) { auto result = futureAndContinution.future.wait_for(0s); if (result != std::future_status::ready) { mergedFences.emplace_back(futureAndContinution); continue; } mergeFence(getDebugName(), futureAndContinution.chain().get().value_or(Fence::NO_FENCE), prevFence); } if (prevFence != nullptr) { mergedFences.emplace_back(ftl::yield(FenceResult(std::move(prevFence))).share()); } mAdditionalPreviousReleaseFences.swap(mergedFences); } if (mBufferInfo.mBuffer) { mPreviouslyPresentedLayerStacks.push_back(layerStack); } Loading Loading @@ -3440,6 +3473,15 @@ bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; handle->frameNumber = mDrawingState.frameNumber; handle->previousFrameNumber = mDrawingState.previousFrameNumber; if (FlagManager::getInstance().screenshot_fence_preservation() && mPreviousReleaseBufferEndpoint == handle->listener) { // Add fences from previous screenshots now so that they can be dispatched to the // client. for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) { handle->previousReleaseFences.emplace_back(futureAndContinution.chain()); } mAdditionalPreviousReleaseFences.clear(); } // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); Loading services/surfaceflinger/Layer.h +15 −1 Original line number Diff line number Diff line Loading @@ -555,7 +555,8 @@ public: const compositionengine::LayerFECompositionState* getCompositionState() const; bool fenceHasSignaled() const; void onPreComposition(nsecs_t refreshStartTime); void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack); void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack, std::function<FenceResult(FenceResult)>&& continuation = nullptr); void setWasClientComposed(const sp<Fence>& fence) { mLastClientCompositionFence = fence; Loading Loading @@ -932,6 +933,19 @@ public: // the release fences from the correct displays when we release the last buffer // from the layer. std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks; struct FenceAndContinuation { ftl::SharedFuture<FenceResult> future; std::function<FenceResult(FenceResult)> continuation; ftl::SharedFuture<FenceResult> chain() const { if (continuation) { return ftl::Future(future).then(continuation).share(); } else { return future; } } }; std::vector<FenceAndContinuation> mAdditionalPreviousReleaseFences; // Exposed so SurfaceFlinger can assert that it's held const sp<SurfaceFlinger> mFlinger; Loading Loading
include/ftl/details/future.h +19 −0 Original line number Diff line number Diff line Loading @@ -73,8 +73,18 @@ class BaseFuture<Self, T, std::future> { return std::get<Impl>(self()).get(); } template <class Rep, class Period> std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const { if (std::holds_alternative<T>(self())) { return std::future_status::ready; } return std::get<Impl>(self()).wait_for(timeout_duration); } private: auto& self() { return static_cast<Self&>(*this).future_; } const auto& self() const { return static_cast<const Self&>(*this).future_; } }; template <typename Self, typename T> Loading @@ -90,6 +100,15 @@ class BaseFuture<Self, T, std::shared_future> { return std::get<Impl>(self()).get(); } template <class Rep, class Period> std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const { if (std::holds_alternative<T>(self())) { return std::future_status::ready; } return std::get<Impl>(self()).wait_for(timeout_duration); } private: const auto& self() const { return static_cast<const Self&>(*this).future_; } }; Loading
include/ftl/future.h +1 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, Future // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the // following are defined for either FutureImpl: using Base::get; using Base::wait_for; // Attaches a continuation to the future. The continuation is a function that maps T to either R // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by Loading
libs/ftl/future_test.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -102,4 +102,42 @@ TEST(Future, Chain) { decrement_thread.join(); } TEST(Future, WaitFor) { using namespace std::chrono_literals; { auto future = ftl::yield(42); // Check that we can wait_for multiple times without invalidating the future EXPECT_EQ(future.wait_for(1s), std::future_status::ready); EXPECT_EQ(future.wait_for(1s), std::future_status::ready); EXPECT_EQ(future.get(), 42); } { std::condition_variable cv; std::mutex m; bool ready = false; std::packaged_task<int32_t()> get_int([&] { std::unique_lock lk(m); cv.wait(lk, [&] { return ready; }); return 24; }); auto get_future = ftl::Future(get_int.get_future()); std::thread get_thread(std::move(get_int)); EXPECT_EQ(get_future.wait_for(0s), std::future_status::timeout); { std::unique_lock lk(m); ready = true; } cv.notify_one(); EXPECT_EQ(get_future.wait_for(1s), std::future_status::ready); EXPECT_EQ(get_future.get(), 24); get_thread.join(); } } } // namespace android::test
services/surfaceflinger/Layer.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -78,11 +78,13 @@ #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "Utils/FenceUtils.h" #define DEBUG_RESIZE 0 #define EARLY_RELEASE_ENABLED false namespace android { using namespace std::chrono_literals; namespace { constexpr int kDumpTableRowLength = 159; Loading Loading @@ -2911,7 +2913,8 @@ void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& l } void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, ui::LayerStack layerStack) { ui::LayerStack layerStack, std::function<FenceResult(FenceResult)>&& continuation) { // If we are displayed on multiple displays in a single composition cycle then we would // need to do careful tracking to enable the use of the mLastClientCompositionFence. // For example we can only use it if all the displays are client comp, and we need Loading Loading @@ -2946,11 +2949,41 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, break; } } if (!FlagManager::getInstance().screenshot_fence_preservation() && continuation) { futureFenceResult = ftl::Future(futureFenceResult).then(std::move(continuation)).share(); } if (ch != nullptr) { ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); ch->name = mName; } else if (FlagManager::getInstance().screenshot_fence_preservation()) { // If we didn't get a release callback yet, e.g. some scenarios when capturing screenshots // asynchronously, then make sure we don't drop the fence. mAdditionalPreviousReleaseFences.emplace_back(std::move(futureFenceResult), std::move(continuation)); std::vector<FenceAndContinuation> mergedFences; sp<Fence> prevFence = nullptr; // For a layer that's frequently screenshotted, try to merge fences to make sure we don't // grow unbounded. for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) { auto result = futureAndContinution.future.wait_for(0s); if (result != std::future_status::ready) { mergedFences.emplace_back(futureAndContinution); continue; } mergeFence(getDebugName(), futureAndContinution.chain().get().value_or(Fence::NO_FENCE), prevFence); } if (prevFence != nullptr) { mergedFences.emplace_back(ftl::yield(FenceResult(std::move(prevFence))).share()); } mAdditionalPreviousReleaseFences.swap(mergedFences); } if (mBufferInfo.mBuffer) { mPreviouslyPresentedLayerStacks.push_back(layerStack); } Loading Loading @@ -3440,6 +3473,15 @@ bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; handle->frameNumber = mDrawingState.frameNumber; handle->previousFrameNumber = mDrawingState.previousFrameNumber; if (FlagManager::getInstance().screenshot_fence_preservation() && mPreviousReleaseBufferEndpoint == handle->listener) { // Add fences from previous screenshots now so that they can be dispatched to the // client. for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) { handle->previousReleaseFences.emplace_back(futureAndContinution.chain()); } mAdditionalPreviousReleaseFences.clear(); } // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); Loading
services/surfaceflinger/Layer.h +15 −1 Original line number Diff line number Diff line Loading @@ -555,7 +555,8 @@ public: const compositionengine::LayerFECompositionState* getCompositionState() const; bool fenceHasSignaled() const; void onPreComposition(nsecs_t refreshStartTime); void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack); void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack, std::function<FenceResult(FenceResult)>&& continuation = nullptr); void setWasClientComposed(const sp<Fence>& fence) { mLastClientCompositionFence = fence; Loading Loading @@ -932,6 +933,19 @@ public: // the release fences from the correct displays when we release the last buffer // from the layer. std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks; struct FenceAndContinuation { ftl::SharedFuture<FenceResult> future; std::function<FenceResult(FenceResult)> continuation; ftl::SharedFuture<FenceResult> chain() const { if (continuation) { return ftl::Future(future).then(continuation).share(); } else { return future; } } }; std::vector<FenceAndContinuation> mAdditionalPreviousReleaseFences; // Exposed so SurfaceFlinger can assert that it's held const sp<SurfaceFlinger> mFlinger; Loading