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

Commit 2ffccbfc authored by Huihong Luo's avatar Huihong Luo Committed by Android (Google) Code Review
Browse files

Merge "Revert "Generate texture pool asynchronously"" into main

parents 5cf32a94 b7f9d639
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ public:
    TexturePool(renderengine::RenderEngine& renderEngine)
          : mRenderEngine(renderEngine), mEnabled(false) {}

    virtual ~TexturePool();
    virtual ~TexturePool() = default;

    // Sets the display size for the texture pool.
    // This will trigger a reallocation for all remaining textures in the pool.
@@ -83,10 +83,11 @@ public:
    // be held by the pool. This is useful when the active display changes.
    void setEnabled(bool enable);

    void dump(std::string& out) const EXCLUDES(mMutex);
    void dump(std::string& out) const;

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 {
@@ -95,20 +96,16 @@ protected:
    };

    std::deque<Entry> mPool;
    std::future<std::shared_ptr<renderengine::ExternalTexture>> mGenTextureFuture;

private:
    std::shared_ptr<renderengine::ExternalTexture> genTexture(ui::Size size);
    std::shared_ptr<renderengine::ExternalTexture> genTexture();
    // Returns a previously borrowed texture to the pool.
    void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
                       const sp<Fence>& fence);
    void genTextureAsyncIfNeeded() REQUIRES(mMutex);
    void resetPool() REQUIRES(mMutex);
    renderengine::RenderEngine& mRenderEngine GUARDED_BY(mRenderEngineMutex);
    ui::Size mSize GUARDED_BY(mMutex);
    void allocatePool();
    renderengine::RenderEngine& mRenderEngine;
    ui::Size mSize;
    bool mEnabled;
    mutable std::mutex mMutex;
    mutable std::mutex mRenderEngineMutex;
};

} // namespace android::compositionengine::impl::planner
+14 −50
Original line number Diff line number Diff line
@@ -25,61 +25,31 @@

namespace android::compositionengine::impl::planner {

TexturePool::~TexturePool() {
    if (mGenTextureFuture.valid()) {
        mGenTextureFuture.get();
    }
}

void TexturePool::resetPool() {
    if (mGenTextureFuture.valid()) {
        mGenTextureFuture.get();
    }
void TexturePool::allocatePool() {
    mPool.clear();
    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);
    if (mEnabled && mSize.isValid()) {
        mPool.resize(kMinPoolSize);
        std::generate_n(mPool.begin(), kMinPoolSize, [&]() {
            return Entry{genTexture(), nullptr};
        });
    }
}

void TexturePool::setDisplaySize(ui::Size size) {
    std::lock_guard lock(mMutex);
    if (mSize == size) {
        return;
    }
    mSize = size;
    resetPool();
    allocatePool();
}

std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
    if (mPool.empty()) {
        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;
        return std::make_shared<AutoTexture>(*this, genTexture(), nullptr);
    }

    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);
}

@@ -90,8 +60,6 @@ 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()) {
@@ -112,14 +80,13 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&&
    mPool.push_back({std::move(texture), fence});
}

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");
std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() {
    LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size");
    return std::make_shared<
            renderengine::impl::
                    ExternalTexture>(sp<GraphicBuffer>::
                                             make(static_cast<uint32_t>(size.getWidth()),
                                                  static_cast<uint32_t>(size.getHeight()),
                                             make(static_cast<uint32_t>(mSize.getWidth()),
                                                  static_cast<uint32_t>(mSize.getHeight()),
                                                  HAL_PIXEL_FORMAT_RGBA_8888, 1U,
                                                  static_cast<uint64_t>(
                                                          GraphicBuffer::USAGE_HW_RENDER |
@@ -133,13 +100,10 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size

void TexturePool::setEnabled(bool enabled) {
    mEnabled = enabled;

    std::lock_guard lock(mMutex);
    resetPool();
    allocatePool();
}

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);
+22 −11
Original line number Diff line number Diff line
@@ -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,8 +56,16 @@ struct TexturePoolTest : public testing::Test {
    TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine);
};

TEST_F(TexturePoolTest, preallocatesZeroSizePool) {
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
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, cyclesUpToMaxPoolSize) {
@@ -111,10 +119,10 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) {
              static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
    mTexturePool.setDisplaySize(kDisplaySizeTwo);

    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
    EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
    texture.reset();
    // When the texture is returned to the pool, the pool now destroys it.
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
    EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());

    texture = mTexturePool.borrowTexture();
    EXPECT_EQ(kDisplaySizeTwo.getWidth(),
@@ -124,11 +132,14 @@ 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 < 2; i++) {
    for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
        textures.emplace_back(mTexturePool.borrowTexture());
    }

    EXPECT_EQ(mTexturePool.getPoolSize(), 1u);
    mTexturePool.setEnabled(false);
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);

@@ -137,11 +148,12 @@ 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 < 2; i++) {
    for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
        textures.emplace_back(mTexturePool.borrowTexture());
    }

@@ -150,13 +162,12 @@ TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) {
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
}

TEST_F(TexturePoolTest, genFutureWhenReEnabled) {
TEST_F(TexturePoolTest, reallocatesWhenReEnabled) {
    EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
    mTexturePool.setEnabled(false);
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
    EXPECT_FALSE(mTexturePool.isGenTextureFutureValid());
    mTexturePool.setEnabled(true);
    EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
    EXPECT_TRUE(mTexturePool.isGenTextureFutureValid());
    EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
}

} // namespace