Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ecd6c1c authored by Alec Mouri's avatar Alec Mouri Committed by Android (Google) Code Review
Browse files

Merge "Correctly pass screenshot fences to transaction callbacks" into main

parents 56cc4141 9892aac6
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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>
@@ -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_; }
};
+1 −0
Original line number Diff line number Diff line
@@ -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
+38 −0
Original line number Diff line number Diff line
@@ -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
+43 −1
Original line number Diff line number Diff line
@@ -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;

@@ -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
@@ -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);
    }
@@ -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);
+15 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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