diff options
| author | 2023-08-07 22:02:03 +0000 | |
|---|---|---|
| committer | 2023-08-07 22:02:03 +0000 | |
| commit | 52ead047fe8da2605fc99f57a99ad153e68cf9f7 (patch) | |
| tree | fe372fec6698b3f937be87e21f0b45ae2fe95cc8 | |
| parent | f8a255424adb9dac9412ef982c3a215f70288b4a (diff) | |
| parent | 568661186f0ffddf98a18a1bf53af242776d1e2b (diff) | |
Merge "Generate texture pool asynchronously" into udc-qpr-dev
3 files changed, 71 insertions, 43 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h index d607c75325..9f6141a1b1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h @@ -66,7 +66,7 @@ public: TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine), mEnabled(false) {} - virtual ~TexturePool() = default; + virtual ~TexturePool(); // Sets the display size for the texture pool. // This will trigger a reallocation for all remaining textures in the pool. @@ -83,11 +83,10 @@ public: // be held by the pool. This is useful when the active display changes. void setEnabled(bool enable); - void dump(std::string& out) const; + void dump(std::string& out) const EXCLUDES(mMutex); protected: // Proteted visibility so that they can be used for testing - const static constexpr size_t kMinPoolSize = 3; const static constexpr size_t kMaxPoolSize = 4; struct Entry { @@ -96,16 +95,20 @@ protected: }; std::deque<Entry> mPool; + std::future<std::shared_ptr<renderengine::ExternalTexture>> mGenTextureFuture; private: - std::shared_ptr<renderengine::ExternalTexture> genTexture(); + std::shared_ptr<renderengine::ExternalTexture> genTexture(ui::Size size); // Returns a previously borrowed texture to the pool. void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture, const sp<Fence>& fence); - void allocatePool(); - renderengine::RenderEngine& mRenderEngine; - ui::Size mSize; + void genTextureAsyncIfNeeded() REQUIRES(mMutex); + void resetPool() REQUIRES(mMutex); + renderengine::RenderEngine& mRenderEngine GUARDED_BY(mRenderEngineMutex); + ui::Size mSize GUARDED_BY(mMutex); bool mEnabled; + mutable std::mutex mMutex; + mutable std::mutex mRenderEngineMutex; }; } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp index 54ecb5691d..10f58cea5d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp @@ -25,31 +25,61 @@ namespace android::compositionengine::impl::planner { -void TexturePool::allocatePool() { +TexturePool::~TexturePool() { + if (mGenTextureFuture.valid()) { + mGenTextureFuture.get(); + } +} + +void TexturePool::resetPool() { + if (mGenTextureFuture.valid()) { + mGenTextureFuture.get(); + } mPool.clear(); - if (mEnabled && mSize.isValid()) { - mPool.resize(kMinPoolSize); - std::generate_n(mPool.begin(), kMinPoolSize, [&]() { - return Entry{genTexture(), nullptr}; - }); + genTextureAsyncIfNeeded(); +} + +// Generate a new texture asynchronously so it will not require allocation on the main +// thread. +void TexturePool::genTextureAsyncIfNeeded() { + if (mEnabled && mSize.isValid() && !mGenTextureFuture.valid()) { + mGenTextureFuture = std::async( + std::launch::async, [&](ui::Size size) { return genTexture(size); }, mSize); } } void TexturePool::setDisplaySize(ui::Size size) { + std::lock_guard lock(mMutex); if (mSize == size) { return; } mSize = size; - allocatePool(); + resetPool(); } std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() { if (mPool.empty()) { - return std::make_shared<AutoTexture>(*this, genTexture(), nullptr); + std::lock_guard lock(mMutex); + std::shared_ptr<TexturePool::AutoTexture> tex; + if (mGenTextureFuture.valid()) { + tex = std::make_shared<AutoTexture>(*this, mGenTextureFuture.get(), nullptr); + } else { + tex = std::make_shared<AutoTexture>(*this, genTexture(mSize), nullptr); + } + // Speculatively generate a new texture, so that the next call does not need + // to wait for allocation. + genTextureAsyncIfNeeded(); + return tex; } const auto entry = mPool.front(); mPool.pop_front(); + if (mPool.empty()) { + std::lock_guard lock(mMutex); + // Similiarly generate a new texture when lending out the last entry, so that + // the next call does not need to wait for allocation. + genTextureAsyncIfNeeded(); + } return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence); } @@ -60,6 +90,8 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& return; } + std::lock_guard lock(mMutex); + // Or the texture on the floor if the pool is no longer tracking textures of the same size. if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() || static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) { @@ -80,13 +112,14 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& mPool.push_back({std::move(texture), fence}); } -std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { - LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size"); +std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size size) { + std::lock_guard lock(mRenderEngineMutex); + LOG_ALWAYS_FATAL_IF(!size.isValid(), "Attempted to generate texture with invalid size"); return std::make_shared< renderengine::impl:: ExternalTexture>(sp<GraphicBuffer>:: - make(static_cast<uint32_t>(mSize.getWidth()), - static_cast<uint32_t>(mSize.getHeight()), + make(static_cast<uint32_t>(size.getWidth()), + static_cast<uint32_t>(size.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1U, static_cast<uint64_t>( GraphicBuffer::USAGE_HW_RENDER | @@ -100,13 +133,16 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { void TexturePool::setEnabled(bool enabled) { mEnabled = enabled; - allocatePool(); + + std::lock_guard lock(mMutex); + resetPool(); } void TexturePool::dump(std::string& out) const { + std::lock_guard lock(mMutex); base::StringAppendF(&out, "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n", mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height); } -} // namespace android::compositionengine::impl::planner
\ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp index 6fc90fe5e5..494a9f4df0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp @@ -32,9 +32,9 @@ class TestableTexturePool : public TexturePool { public: TestableTexturePool(renderengine::RenderEngine& renderEngine) : TexturePool(renderEngine) {} - size_t getMinPoolSize() const { return kMinPoolSize; } size_t getMaxPoolSize() const { return kMaxPoolSize; } size_t getPoolSize() const { return mPool.size(); } + size_t isGenTextureFutureValid() const { return mGenTextureFuture.valid(); } }; struct TexturePoolTest : public testing::Test { @@ -56,16 +56,8 @@ struct TexturePoolTest : public testing::Test { TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine); }; -TEST_F(TexturePoolTest, preallocatesMinPool) { - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); -} - -TEST_F(TexturePoolTest, doesNotAllocateBeyondMinPool) { - for (size_t i = 0; i < mTexturePool.getMinPoolSize() + 1; i++) { - auto texture = mTexturePool.borrowTexture(); - } - - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); +TEST_F(TexturePoolTest, preallocatesZeroSizePool) { + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } TEST_F(TexturePoolTest, cyclesUpToMaxPoolSize) { @@ -119,10 +111,10 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { static_cast<int32_t>(texture->get()->getBuffer()->getHeight())); mTexturePool.setDisplaySize(kDisplaySizeTwo); - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); texture.reset(); // When the texture is returned to the pool, the pool now destroys it. - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); texture = mTexturePool.borrowTexture(); EXPECT_EQ(kDisplaySizeTwo.getWidth(), @@ -132,14 +124,11 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { } TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); - std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; - for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + for (size_t i = 0; i < 2; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } - EXPECT_EQ(mTexturePool.getPoolSize(), 1u); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); @@ -148,12 +137,11 @@ TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { } TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; - for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + for (size_t i = 0; i < 2; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } @@ -162,12 +150,13 @@ TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } -TEST_F(TexturePoolTest, reallocatesWhenReEnabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); +TEST_F(TexturePoolTest, genFutureWhenReEnabled) { mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + EXPECT_FALSE(mTexturePool.isGenTextureFutureValid()); mTexturePool.setEnabled(true); - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + EXPECT_TRUE(mTexturePool.isGenTextureFutureValid()); } } // namespace |