Merge "Add a TexturePool class into layer caching" into sc-dev
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 08147ed..d738ccd 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -57,6 +57,7 @@
"src/planner/LayerState.cpp",
"src/planner/Planner.cpp",
"src/planner/Predictor.cpp",
+ "src/planner/TexturePool.cpp",
"src/ClientCompositionRequestCache.cpp",
"src/CompositionEngine.cpp",
"src/Display.cpp",
@@ -107,6 +108,7 @@
"tests/planner/FlattenerTest.cpp",
"tests/planner/LayerStateTest.cpp",
"tests/planner/PredictorTest.cpp",
+ "tests/planner/TexturePoolTest.cpp",
"tests/CompositionEngineTest.cpp",
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2c18a60..a4356c5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -19,6 +19,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/ProjectionSpace.h>
#include <compositionengine/impl/planner/LayerState.h>
+#include <compositionengine/impl/planner/TexturePool.h>
#include <renderengine/RenderEngine.h>
#include <chrono>
@@ -64,9 +65,12 @@
size_t getLayerCount() const { return mLayers.size(); }
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
+ Rect getTextureBounds() const { return mOutputSpace.content; }
const Region& getVisibleRegion() const { return mVisibleRegion; }
size_t getAge() const { return mAge; }
- const std::shared_ptr<renderengine::ExternalTexture>& getBuffer() const { return mTexture; }
+ std::shared_ptr<renderengine::ExternalTexture> getBuffer() const {
+ return mTexture ? mTexture->get() : nullptr;
+ }
const sp<Fence>& getDrawFence() const { return mDrawFence; }
const ProjectionSpace& getOutputSpace() const { return mOutputSpace; }
ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
@@ -89,7 +93,7 @@
void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; }
void append(const CachedSet& other) {
- mTexture = nullptr;
+ mTexture.reset();
mOutputDataspace = ui::Dataspace::UNKNOWN;
mDrawFence = nullptr;
mBlurLayer = nullptr;
@@ -105,7 +109,8 @@
void incrementAge() { ++mAge; }
// Renders the cached set with the supplied output composition state.
- void render(renderengine::RenderEngine& re, const OutputCompositionState& outputState);
+ void render(renderengine::RenderEngine& re, TexturePool& texturePool,
+ const OutputCompositionState& outputState);
void dump(std::string& result) const;
@@ -151,7 +156,9 @@
Region mVisibleRegion;
size_t mAge = 0;
- std::shared_ptr<renderengine::ExternalTexture> mTexture;
+ // TODO(b/190411067): This is a shared pointer only because CachedSets are copied into different
+ // containers in the Flattener. Logically this should have unique ownership otherwise.
+ std::shared_ptr<TexturePool::AutoTexture> mTexture;
sp<Fence> mDrawFence;
ProjectionSpace mOutputSpace;
ui::Dataspace mOutputDataspace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index c76078d..94a169e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -37,16 +37,18 @@
class Flattener {
public:
- Flattener(bool enableHolePunch = false);
+ Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false);
- void setDisplaySize(ui::Size size) { mDisplaySize = size; }
+ void setDisplaySize(ui::Size size) {
+ mDisplaySize = size;
+ mTexturePool.setDisplaySize(size);
+ }
NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash,
std::chrono::steady_clock::time_point now);
// Renders the newest cached sets with the supplied output composition state
- void renderCachedSets(renderengine::RenderEngine& re,
- const OutputCompositionState& outputState);
+ void renderCachedSets(const OutputCompositionState& outputState);
void dump(std::string& result) const;
void dumpLayers(std::string& result) const;
@@ -145,8 +147,11 @@
void buildCachedSets(std::chrono::steady_clock::time_point now);
+ renderengine::RenderEngine& mRenderEngine;
const bool mEnableHolePunch;
+ TexturePool mTexturePool;
+
ui::Size mDisplaySize;
NonBufferHash mCurrentGeometry;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index 4365b93..fd1ddfc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -41,7 +41,7 @@
// as a more efficient representation of parts of the layer stack.
class Planner {
public:
- Planner();
+ Planner(renderengine::RenderEngine& renderengine);
void setDisplaySize(ui::Size);
@@ -59,8 +59,7 @@
compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers);
// The planner will call to the Flattener to render any pending cached set
- void renderCachedSets(renderengine::RenderEngine& re,
- const OutputCompositionState& outputState);
+ void renderCachedSets(const OutputCompositionState& outputState);
void dump(const Vector<String16>& args, std::string&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
new file mode 100644
index 0000000..fb53ee0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/Output.h>
+#include <compositionengine/ProjectionSpace.h>
+#include <compositionengine/impl/planner/LayerState.h>
+#include <renderengine/RenderEngine.h>
+
+#include <renderengine/ExternalTexture.h>
+#include <chrono>
+#include "android-base/macros.h"
+
+namespace android::compositionengine::impl::planner {
+
+// A pool of textures that only manages textures of a single size.
+// While it is possible to define a texture pool supporting variable-sized textures to save on
+// memory, it is a simpler implementation to only manage screen-sized textures. The texture pool is
+// unbounded - there are a minimum number of textures preallocated. Under heavy system load, new
+// textures may be allocated, but only a maximum number of retained once those textures are no
+// longer necessary.
+class TexturePool {
+public:
+ // RAII class helping with managing textures from the texture pool
+ // Textures once they're no longer used should be returned to the pool instead of outright
+ // deleted.
+ class AutoTexture {
+ public:
+ AutoTexture(TexturePool& texturePool,
+ std::shared_ptr<renderengine::ExternalTexture> texture, const sp<Fence>& fence)
+ : mTexturePool(texturePool), mTexture(texture), mFence(fence) {}
+
+ ~AutoTexture() { mTexturePool.returnTexture(std::move(mTexture), mFence); }
+
+ sp<Fence> getReadyFence() { return mFence; }
+
+ void setReadyFence(const sp<Fence>& fence) { mFence = fence; }
+
+ // Disable copying and assigning
+ AutoTexture(const AutoTexture&) = delete;
+ AutoTexture& operator=(const AutoTexture&) = delete;
+
+ // Gets a pointer to the underlying external texture
+ const std::shared_ptr<renderengine::ExternalTexture>& get() const { return mTexture; }
+
+ private:
+ TexturePool& mTexturePool;
+ std::shared_ptr<renderengine::ExternalTexture> mTexture;
+ sp<Fence> mFence;
+ };
+
+ TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine) {}
+
+ virtual ~TexturePool() = default;
+
+ // Sets the display size for the texture pool.
+ // This will trigger a reallocation for all remaining textures in the pool.
+ // setDisplaySize must be called for the texture pool to be used.
+ void setDisplaySize(ui::Size size);
+
+ // Borrows a new texture from the pool.
+ // If the pool is currently starved of textures, then a new texture is generated.
+ // When the AutoTexture object is destroyed, the scratch texture is automatically returned
+ // to the pool.
+ std::shared_ptr<AutoTexture> borrowTexture();
+
+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 {
+ std::shared_ptr<renderengine::ExternalTexture> texture;
+ sp<Fence> fence;
+ };
+
+ std::deque<Entry> mPool;
+
+private:
+ 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);
+ renderengine::RenderEngine& mRenderEngine;
+ ui::Size mSize;
+};
+
+} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e9a8b91..cd2f742 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -129,7 +129,7 @@
}
if (enabled) {
- mPlanner = std::make_unique<planner::Planner>();
+ mPlanner = std::make_unique<planner::Planner>(getCompositionEngine().getRenderEngine());
if (mRenderSurface) {
mPlanner->setDisplaySize(mRenderSurface->getSize());
}
@@ -1314,7 +1314,7 @@
void Output::renderCachedSets() {
if (mPlanner) {
- mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine(), getState());
+ mPlanner->renderCachedSets(getState());
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index dcfb05d..69e8c7d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -134,7 +134,7 @@
}
bool CachedSet::hasReadyBuffer() const {
- return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
+ return mTexture && mDrawFence->getStatus() == Fence::Status::Signaled;
}
std::vector<CachedSet> CachedSet::decompose() const {
@@ -156,7 +156,7 @@
}
}
-void CachedSet::render(renderengine::RenderEngine& renderEngine,
+void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
const OutputCompositionState& outputState) {
ATRACE_CALL();
const Rect& viewport = outputState.layerStackSpace.content;
@@ -165,10 +165,7 @@
ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
renderengine::DisplaySettings displaySettings{
- .physicalDisplay = Rect(-mBounds.left + outputState.framebufferSpace.content.left,
- -mBounds.top + outputState.framebufferSpace.content.top,
- -mBounds.left + outputState.framebufferSpace.content.right,
- -mBounds.top + outputState.framebufferSpace.content.bottom),
+ .physicalDisplay = outputState.framebufferSpace.content,
.clip = viewport,
.outputDataspace = outputDataspace,
.orientation = orientation,
@@ -255,30 +252,33 @@
layerSettingsPointers.emplace_back(&highlight);
}
- const uint64_t usageFlags = GraphicBuffer::USAGE_HW_RENDER | GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE;
- sp<GraphicBuffer> buffer = new GraphicBuffer(static_cast<uint32_t>(mBounds.getWidth()),
- static_cast<uint32_t>(mBounds.getHeight()),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags);
- const auto texture = std::make_shared<
- renderengine::ExternalTexture>(buffer, renderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
- LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK);
- base::unique_fd drawFence;
+ auto texture = texturePool.borrowTexture();
+ LOG_ALWAYS_FATAL_IF(texture->get()->getBuffer()->initCheck() != OK);
- status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture,
- false, base::unique_fd(), &drawFence);
+ base::unique_fd bufferFence;
+ if (texture->getReadyFence()) {
+ // Bail out if the buffer is not ready, because there is some pending GPU work left.
+ if (texture->getReadyFence()->getStatus() != Fence::Status::Signaled) {
+ return;
+ }
+ bufferFence.reset(texture->getReadyFence()->dup());
+ }
+
+ base::unique_fd drawFence;
+ status_t result =
+ renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture->get(), false,
+ std::move(bufferFence), &drawFence);
if (result == NO_ERROR) {
mDrawFence = new Fence(drawFence.release());
mOutputSpace = outputState.framebufferSpace;
- mTexture = std::move(texture);
+ mTexture = texture;
+ mTexture->setReadyFence(mDrawFence);
mOutputSpace.orientation = outputState.framebufferSpace.orientation;
mOutputDataspace = outputDataspace;
mOrientation = orientation;
} else {
- mTexture = nullptr;
+ mTexture.reset();
}
}
@@ -363,7 +363,7 @@
base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n",
mFingerprint, durationString(lastUpdate).c_str(), mAge);
{
- const auto b = mTexture ? mTexture->getBuffer().get() : nullptr;
+ const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
base::StringAppendF(&result, " Override buffer: %p\n", b);
}
base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 48fb51f..192c411 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -60,7 +60,10 @@
} // namespace
-Flattener::Flattener(bool enableHolePunch) : mEnableHolePunch(enableHolePunch) {
+Flattener::Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch)
+ : mRenderEngine(renderEngine),
+ mEnableHolePunch(enableHolePunch),
+ mTexturePool(mRenderEngine) {
const int timeoutInMs =
base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
if (timeoutInMs != 0) {
@@ -102,14 +105,13 @@
return hash;
}
-void Flattener::renderCachedSets(renderengine::RenderEngine& renderEngine,
- const OutputCompositionState& outputState) {
+void Flattener::renderCachedSets(const OutputCompositionState& outputState) {
ATRACE_CALL();
if (!mNewCachedSet || mNewCachedSet->hasRenderedBuffer()) {
return;
}
- mNewCachedSet->render(renderEngine, outputState);
+ mNewCachedSet->render(mRenderEngine, mTexturePool, outputState);
}
void Flattener::dumpLayers(std::string& result) const {
@@ -285,7 +287,7 @@
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getBounds(),
+ .displayFrame = mNewCachedSet->getTextureBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -325,7 +327,7 @@
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getBounds(),
+ .displayFrame = currentLayerIter->getTextureBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 297c0b2..711a634 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -29,12 +29,13 @@
namespace android::compositionengine::impl::planner {
-Planner::Planner()
+Planner::Planner(renderengine::RenderEngine& renderEngine)
// Implicitly, layer caching must also be enabled for the hole punch or
// predictor to have any effect.
// E.g., setprop debug.sf.enable_layer_caching 1, or
// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
- : mFlattener(base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true)) {
+ : mFlattener(renderEngine,
+ base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true)) {
mPredictorEnabled =
base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
}
@@ -160,10 +161,9 @@
finalPlan);
}
-void Planner::renderCachedSets(renderengine::RenderEngine& renderEngine,
- const OutputCompositionState& outputState) {
+void Planner::renderCachedSets(const OutputCompositionState& outputState) {
ATRACE_CALL();
- mFlattener.renderCachedSets(renderEngine, outputState);
+ mFlattener.renderCachedSets(outputState);
}
void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
new file mode 100644
index 0000000..e3772a2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "Planner"
+
+#include <compositionengine/impl/planner/TexturePool.h>
+#include <utils/Log.h>
+
+namespace android::compositionengine::impl::planner {
+
+void TexturePool::setDisplaySize(ui::Size size) {
+ if (mSize == size) {
+ return;
+ }
+ mSize = size;
+ mPool.clear();
+ mPool.resize(kMinPoolSize);
+ std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; });
+}
+
+std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
+ if (mPool.empty()) {
+ return std::make_shared<AutoTexture>(*this, genTexture(), nullptr);
+ }
+
+ const auto entry = mPool.front();
+ mPool.pop_front();
+ return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence);
+}
+
+void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
+ const sp<Fence>& fence) {
+ // Drop 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()) {
+ ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), "
+ "current: (%dx%d))",
+ texture->getBuffer()->getWidth(), texture->getBuffer()->getHeight(), mSize.getWidth(),
+ mSize.getHeight());
+ return;
+ }
+
+ // Also ensure the pool does not grow beyond a maximum size.
+ if (mPool.size() == kMaxPoolSize) {
+ ALOGD("Deallocating texture from Planner's pool - max size [%" PRIu64 "] reached",
+ static_cast<uint64_t>(kMaxPoolSize));
+ return;
+ }
+
+ 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");
+ return std::make_shared<
+ renderengine::ExternalTexture>(sp<GraphicBuffer>::
+ make(mSize.getWidth(), mSize.getHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GraphicBuffer::USAGE_HW_RENDER |
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ "Planner"),
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+}
+
+} // namespace android::compositionengine::impl::planner
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 52e0428..c381081 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -143,6 +143,7 @@
mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
mOutput->editState().displaySpace.bounds = kDefaultDisplaySize;
+ EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
}
void injectOutputLayer(InjectedLayer& layer) {
@@ -156,6 +157,7 @@
static const Rect kDefaultDisplaySize;
StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
std::shared_ptr<Output> mOutput = createOutput(mCompositionEngine);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 8eeb0bf..b15e4f3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -40,6 +40,7 @@
using impl::planner::CachedSet;
using impl::planner::LayerState;
using impl::planner::LayerStateField;
+using impl::planner::TexturePool;
namespace {
@@ -50,6 +51,7 @@
return expectedBlurSetting == arg.blurSetting;
}
+static const ui::Size kOutputSize = ui::Size(1, 1);
class CachedSetTest : public testing::Test {
public:
@@ -76,9 +78,11 @@
impl::OutputCompositionState mOutputState;
android::renderengine::mock::RenderEngine mRenderEngine;
+ TexturePool mTexturePool = TexturePool(mRenderEngine);
};
void CachedSetTest::SetUp() {
+ mTexturePool.setDisplaySize(kOutputSize);
for (size_t i = 0; i < kNumLayers; i++) {
auto testLayer = std::make_unique<TestLayer>();
auto pos = static_cast<int32_t>(i);
@@ -319,7 +323,7 @@
const std::vector<const renderengine::LayerSettings*>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(Rect(-1, -1, 9, 4), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
displaySettings.orientation);
@@ -333,10 +337,11 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+ EXPECT_EQ(mOutputState.framebufferSpace.content, cachedSet.getTextureBounds());
// Now check that appending a new cached set properly cleans up RenderEngine resources.
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
@@ -367,7 +372,7 @@
const std::vector<const renderengine::LayerSettings*>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(Rect(1, 2, 9, 4), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
displaySettings.orientation);
@@ -381,7 +386,7 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -554,7 +559,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
TEST_F(CachedSetTest, addHolePunch_noBuffer) {
@@ -604,7 +609,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
TEST_F(CachedSetTest, append_removesHolePunch) {
@@ -741,7 +746,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 8b03964..e176c98 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -46,13 +46,14 @@
class TestableFlattener : public Flattener {
public:
- TestableFlattener(bool enableHolePunch) : Flattener(enableHolePunch) {}
+ TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch)
+ : Flattener(renderEngine, enableHolePunch) {}
const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; }
};
class FlattenerTest : public testing::Test {
public:
- FlattenerTest() : mFlattener(std::make_unique<TestableFlattener>(true)) {}
+ FlattenerTest() : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true)) {}
void SetUp() override;
protected:
@@ -60,7 +61,7 @@
void initializeFlattener(const std::vector<const LayerState*>& layers);
void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
- // mRenderEngine may be held as a pointer to mFlattener, so mFlattener must be destroyed first.
+ // mRenderEngine is held as a reference in mFlattener, so mFlattener must be destroyed first.
renderengine::mock::RenderEngine mRenderEngine;
std::unique_ptr<TestableFlattener> mFlattener;
@@ -84,6 +85,7 @@
};
void FlattenerTest::SetUp() {
+ mFlattener->setDisplaySize({1, 1});
for (size_t i = 0; i < kNumLayers; i++) {
auto testLayer = std::make_unique<TestLayer>();
auto pos = static_cast<int32_t>(i);
@@ -146,13 +148,13 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// same geometry, update the internal layer stack
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
}
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -162,7 +164,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -172,7 +174,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
EXPECT_NE(nullptr, buffer);
@@ -207,7 +209,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
}
TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
@@ -253,7 +255,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -358,7 +360,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -395,7 +397,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -404,7 +406,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -417,7 +419,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -426,7 +428,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -468,7 +470,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -482,7 +484,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -495,7 +497,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_180;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -510,7 +512,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -522,7 +524,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_270;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -561,7 +563,7 @@
// This will render a CachedSet.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -574,7 +576,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -623,7 +625,7 @@
// This will render a CachedSet.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -636,7 +638,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -680,7 +682,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -690,7 +692,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
EXPECT_EQ(nullptr, overrideBuffer3);
@@ -724,7 +726,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -735,7 +737,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
}
@@ -776,7 +778,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -786,7 +788,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
EXPECT_NE(nullptr, overrideBuffer3);
@@ -823,7 +825,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
const auto& cachedSet = mFlattener->getNewCachedSetForTesting();
ASSERT_NE(std::nullopt, cachedSet);
@@ -837,7 +839,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
@@ -864,7 +866,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -872,12 +874,12 @@
// Simulate attempting to render prior to merging the new cached set with the layer stack.
// Here we should not try to re-render.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We provide the override buffer now that it's rendered
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
new file mode 100644
index 0000000..b802e51
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TexturePoolTest"
+
+#include <compositionengine/impl/planner/TexturePool.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <renderengine/mock/RenderEngine.h>
+
+namespace android::compositionengine::impl::planner {
+namespace {
+
+const ui::Size kDisplaySize(1, 1);
+const ui::Size kDisplaySizeTwo(2, 2);
+
+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(); }
+};
+
+struct TexturePoolTest : public testing::Test {
+ TexturePoolTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ mTexturePool.setDisplaySize(kDisplaySize);
+ }
+
+ ~TexturePoolTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ renderengine::mock::RenderEngine mRenderEngine;
+ 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, cyclesUpToMaxPoolSize) {
+ std::unordered_set<uint64_t> bufferIds;
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMaxPoolSize(); i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), bufferIds.size());
+
+ for (size_t i = 0; i < 3; i++) {
+ textures.pop_front();
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), bufferIds.size());
+}
+
+TEST_F(TexturePoolTest, goesPastMaxSizeAndRebounds) {
+ std::unordered_set<uint64_t> bufferIds;
+ std::vector<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMaxPoolSize() + 2; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize() + 2, bufferIds.size());
+
+ // Return the textures to the pool.
+ // Now when we cycle through the pool it's again bounded by max textures.
+ textures.clear();
+
+ std::unordered_set<uint64_t> newBufferIds;
+ for (size_t i = 0; i < 2 * mTexturePool.getMaxPoolSize(); i++) {
+ auto texture = mTexturePool.borrowTexture();
+ newBufferIds.insert(texture->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), newBufferIds.size());
+}
+
+TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) {
+ auto texture = mTexturePool.borrowTexture();
+
+ EXPECT_EQ(kDisplaySize.getWidth(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getWidth()));
+ EXPECT_EQ(kDisplaySize.getHeight(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
+ mTexturePool.setDisplaySize(kDisplaySizeTwo);
+
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+ texture.reset();
+ // When the texture is returned to the pool, the pool now destroys it.
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+
+ texture = mTexturePool.borrowTexture();
+ EXPECT_EQ(kDisplaySizeTwo.getWidth(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getWidth()));
+ EXPECT_EQ(kDisplaySizeTwo.getHeight(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
+}
+
+} // namespace
+} // namespace android::compositionengine::impl::planner