summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vishnu Nair <vishnun@google.com> 2020-01-21 14:36:08 -0800
committer Vishnu Nair <vishnun@google.com> 2020-01-21 21:17:50 -0800
commit9b079a2fef76ed1dfa69b158889edd0af5e6e52c (patch)
tree0072ca6810ee57122aa5b56abf52b18032b0f6f1
parent0a4b951a590910bab35f20f03d25316426dbf8ae (diff)
Skip client composition requests
Keep track of client compositions requests in CompositionEngine and the buffer used to render the request. If the requests do not change and the buffer matches, reuse the buffer instead of going to client composition. Certain layers properties (buffer format, rounded corner or shadows) will force the device to go into GPU or mixed composition. In mixed composition scenarios, we can avoid redundant client composition requests by reusing the RenderSurface buffers. If the device goes into GPU composition then all the layers will be composited and there will be no performance benefit. Bug: b/136561771, b/144690120 Test: dump SurfaceFlinger --timestats -dump Test: manual testing with mixed and gpu composition scenarios Test: atest libcompositionengine_test libsurfaceflinger_unittest SurfaceFlinger_test Change-Id: I466d5dcded0c9fcfa64bc72fd91dfaddd795f315
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.cpp68
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h3
-rw-r--r--libs/renderengine/include/renderengine/LayerSettings.h4
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h2
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h2
-rw-r--r--libs/renderengine/tests/RenderEngineTest.cpp89
-rw-r--r--services/surfaceflinger/BufferLayer.cpp14
-rw-r--r--services/surfaceflinger/BufferLayer.h2
-rw-r--r--services/surfaceflinger/ColorLayer.cpp2
-rw-r--r--services/surfaceflinger/ColorLayer.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/Android.bp1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h4
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h31
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h5
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h66
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h11
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h3
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h5
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h5
-rw-r--r--services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp126
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Display.cpp4
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Output.cpp63
-rw-r--r--services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp1
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp236
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp6
-rw-r--r--services/surfaceflinger/Layer.cpp17
-rw-r--r--services/surfaceflinger/Layer.h6
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp30
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h8
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.cpp10
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.h2
-rw-r--r--services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp1
-rw-r--r--services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h1
-rw-r--r--services/surfaceflinger/tests/unittests/CompositionTest.cpp60
-rw-r--r--services/surfaceflinger/tests/unittests/TimeStatsTest.cpp26
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockTimeStats.h1
38 files changed, 704 insertions, 215 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 09659fe209..e257704750 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -960,7 +960,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer
}
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<LayerSettings>& layers,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* const buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence,
base::unique_fd* drawFence) {
@@ -985,9 +985,9 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
// Blurs in multiple layers are not supported, given the cost of the shader.
const LayerSettings* blurLayer = nullptr;
if (CC_LIKELY(mBlurFilter != nullptr)) {
- for (auto const& layer : layers) {
- if (layer.backgroundBlurRadius > 0) {
- blurLayer = &layer;
+ for (auto const layer : layers) {
+ if (layer->backgroundBlurRadius > 0) {
+ blurLayer = layer;
}
}
}
@@ -1035,9 +1035,9 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
.setTexCoords(2 /* size */)
.setCropCoords(2 /* size */)
.build();
- for (auto const& layer : layers) {
- if (blurLayer == &layer) {
- auto status = mBlurFilter->prepare(layer.backgroundBlurRadius);
+ for (auto const layer : layers) {
+ if (blurLayer == layer) {
+ auto status = mBlurFilter->prepare(layer->backgroundBlurRadius);
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->handle);
@@ -1065,40 +1065,40 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
}
}
- mState.maxMasteringLuminance = layer.source.buffer.maxMasteringLuminance;
- mState.maxContentLuminance = layer.source.buffer.maxContentLuminance;
- mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+ mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance;
+ mState.maxContentLuminance = layer->source.buffer.maxContentLuminance;
+ mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
- const FloatRect bounds = layer.geometry.boundaries;
+ const FloatRect bounds = layer->geometry.boundaries;
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = vec2(bounds.left, bounds.top);
position[1] = vec2(bounds.left, bounds.bottom);
position[2] = vec2(bounds.right, bounds.bottom);
position[3] = vec2(bounds.right, bounds.top);
- setupLayerCropping(layer, mesh);
- setColorTransform(display.colorTransform * layer.colorTransform);
+ setupLayerCropping(*layer, mesh);
+ setColorTransform(display.colorTransform * layer->colorTransform);
bool usePremultipliedAlpha = true;
bool disableTexture = true;
bool isOpaque = false;
- if (layer.source.buffer.buffer != nullptr) {
+ if (layer->source.buffer.buffer != nullptr) {
disableTexture = false;
- isOpaque = layer.source.buffer.isOpaque;
+ isOpaque = layer->source.buffer.isOpaque;
- sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
- bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
- layer.source.buffer.fence);
+ sp<GraphicBuffer> gBuf = layer->source.buffer.buffer;
+ bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf,
+ layer->source.buffer.fence);
- usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
- Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
- mat4 texMatrix = layer.source.buffer.textureTransform;
+ usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha;
+ Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName);
+ mat4 texMatrix = layer->source.buffer.textureTransform;
texture.setMatrix(texMatrix.asArray());
- texture.setFiltering(layer.source.buffer.useTextureFiltering);
+ texture.setFiltering(layer->source.buffer.useTextureFiltering);
texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
- setSourceY410BT2020(layer.source.buffer.isY410BT2020);
+ setSourceY410BT2020(layer->source.buffer.isY410BT2020);
renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
texCoords[0] = vec2(0.0, 0.0);
@@ -1108,32 +1108,32 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
setupLayerTexturing(texture);
}
- const half3 solidColor = layer.source.solidColor;
- const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+ const half3 solidColor = layer->source.solidColor;
+ const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha);
// Buffer sources will have a black solid color ignored in the shader,
// so in that scenario the solid color passed here is arbitrary.
setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
- layer.geometry.roundedCornersRadius);
- if (layer.disableBlending) {
+ layer->geometry.roundedCornersRadius);
+ if (layer->disableBlending) {
glDisable(GL_BLEND);
}
- setSourceDataSpace(layer.sourceDataspace);
+ setSourceDataSpace(layer->sourceDataspace);
- if (layer.shadow.length > 0.0f) {
- handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
- layer.shadow);
+ if (layer->shadow.length > 0.0f) {
+ handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius,
+ layer->shadow);
}
// We only want to do a special handling for rounded corners when having rounded corners
// is the only reason it needs to turn on blending, otherwise, we handle it like the
// usual way since it needs to turn on blending anyway.
- else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
- handleRoundedCorners(display, layer, mesh);
+ else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+ handleRoundedCorners(display, *layer, mesh);
} else {
drawMesh(mesh);
}
// Cleanup if there's a buffer source
- if (layer.source.buffer.buffer != nullptr) {
+ if (layer->source.buffer.buffer != nullptr) {
disableBlending();
setSourceY410BT2020(false);
disableTexturing();
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 547235a90d..45c85de51e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,7 +71,8 @@ public:
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
- status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+ status_t drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 3dc198f398..95e9367fea 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -52,7 +52,7 @@ struct Buffer {
// Transform matrix to apply to texture coordinates.
mat4 textureTransform = mat4();
- // Wheteher to use pre-multiplied alpha
+ // Whether to use pre-multiplied alpha.
bool usePremultipliedAlpha = true;
// Override flag that alpha for each pixel in the buffer *must* be 1.0.
@@ -153,6 +153,8 @@ struct LayerSettings {
int backgroundBlurRadius = 0;
};
+// Keep in sync with custom comparison function in
+// compositionengine/impl/ClientCompositionRequestCache.cpp
static inline bool operator==(const Buffer& lhs, const Buffer& rhs) {
return lhs.buffer == rhs.buffer && lhs.fence == rhs.fence &&
lhs.textureName == rhs.textureName &&
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e3c2d84e86..46f3fc6de0 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -154,7 +154,7 @@ public:
// @return An error code indicating whether drawing was successful. For
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
- const std::vector<LayerSettings>& layers,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0750e86988..3358c69fb9 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -56,7 +56,7 @@ public:
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
MOCK_METHOD6(drawLayers,
- status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+ status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
};
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index e676740c6a..afcbc50584 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -249,7 +249,8 @@ struct RenderEngineTest : public ::testing::Test {
}
void invokeDraw(renderengine::DisplaySettings settings,
- std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
+ std::vector<const renderengine::LayerSettings*> layers,
+ sp<GraphicBuffer> buffer) {
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
base::unique_fd(), &fence);
@@ -269,7 +270,7 @@ struct RenderEngineTest : public ::testing::Test {
void drawEmptyLayers() {
renderengine::DisplaySettings settings;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// Meaningless buffer since we don't do any drawing
sp<GraphicBuffer> buffer = new GraphicBuffer();
invokeDraw(settings, layers, buffer);
@@ -440,14 +441,14 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -482,14 +483,14 @@ void RenderEngineTest::fillRedOffsetBuffer() {
settings.physicalDisplay = offsetRect();
settings.clip = offsetRectAtZero();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -515,7 +516,7 @@ void RenderEngineTest::fillBufferCheckers(mat4 transform) {
settings.clip = Rect(2, 2);
settings.globalTransform = transform;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layerOne;
Rect rectOne(0, 0, 1, 1);
@@ -535,9 +536,9 @@ void RenderEngineTest::fillBufferCheckers(mat4 transform) {
SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
layerThree.alpha = 1.0f;
- layers.push_back(layerOne);
- layers.push_back(layerTwo);
- layers.push_back(layerThree);
+ layers.push_back(&layerOne);
+ layers.push_back(&layerTwo);
+ layers.push_back(&layerThree);
invokeDraw(settings, layers, mBuffer);
}
@@ -616,7 +617,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() {
// Here logical space is 2x2
settings.clip = Rect(2, 2);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -626,7 +627,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() {
layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -647,7 +648,7 @@ void RenderEngineTest::fillBufferWithColorTransform() {
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -663,7 +664,7 @@ void RenderEngineTest::fillBufferWithColorTransform() {
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -680,7 +681,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
@@ -689,7 +690,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() {
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -726,26 +727,26 @@ void RenderEngineTest::fillBufferAndBlurBackground() {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings backgroundLayer;
backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
backgroundLayer.alpha = 1.0f;
- layers.push_back(backgroundLayer);
+ layers.push_back(&backgroundLayer);
renderengine::LayerSettings leftLayer;
leftLayer.geometry.boundaries =
Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
leftLayer.alpha = 1.0f;
- layers.push_back(leftLayer);
+ layers.push_back(&leftLayer);
renderengine::LayerSettings blurLayer;
blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
blurLayer.backgroundBlurRadius = blurRadius;
blurLayer.alpha = 0;
- layers.push_back(blurLayer);
+ layers.push_back(&blurLayer);
invokeDraw(settings, layers, mBuffer);
@@ -761,7 +762,7 @@ void RenderEngineTest::overlayCorners() {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layersFirst;
+ std::vector<const renderengine::LayerSettings*> layersFirst;
renderengine::LayerSettings layerOne;
layerOne.geometry.boundaries =
@@ -769,14 +770,14 @@ void RenderEngineTest::overlayCorners() {
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 0.2;
- layersFirst.push_back(layerOne);
+ layersFirst.push_back(&layerOne);
invokeDraw(settings, layersFirst, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
- std::vector<renderengine::LayerSettings> layersSecond;
+ std::vector<const renderengine::LayerSettings*> layersSecond;
renderengine::LayerSettings layerTwo;
layerTwo.geometry.boundaries =
FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
@@ -784,7 +785,7 @@ void RenderEngineTest::overlayCorners() {
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
- layersSecond.push_back(layerTwo);
+ layersSecond.push_back(&layerTwo);
invokeDraw(settings, layersSecond, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
@@ -798,7 +799,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() {
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
// Here will allocate a checker board texture, but transform texture
@@ -833,7 +834,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() {
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -849,7 +850,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
@@ -872,7 +873,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -888,7 +889,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
@@ -911,7 +912,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -928,10 +929,10 @@ void RenderEngineTest::clearLeftRegion() {
settings.clip = Rect(4, 4);
settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
settings.clearRegion = Region(Rect(1, 1));
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// dummy layer, without bounds should not render anything
renderengine::LayerSettings layer;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -952,7 +953,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// add background layer
renderengine::LayerSettings bgLayer;
@@ -960,20 +961,20 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye
ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
backgroundColor.b / 255.0f, this);
bgLayer.alpha = backgroundColor.a / 255.0f;
- layers.push_back(bgLayer);
+ layers.push_back(&bgLayer);
// add shadow layer
renderengine::LayerSettings shadowLayer;
shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries;
shadowLayer.alpha = castingLayer.alpha;
shadowLayer.shadow = shadow;
- layers.push_back(shadowLayer);
+ layers.push_back(&shadowLayer);
// add layer casting the shadow
renderengine::LayerSettings layer = castingLayer;
SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f,
casterColor.b / 255.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -984,11 +985,11 @@ TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
TEST_F(RenderEngineTest, drawLayers_nullOutputBuffer) {
renderengine::DisplaySettings settings;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
@@ -1000,12 +1001,12 @@ TEST_F(RenderEngineTest, drawLayers_nullOutputFence) {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(layer);
+ layers.push_back(&layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
base::unique_fd(), nullptr);
@@ -1019,12 +1020,12 @@ TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(layer);
+ layers.push_back(&layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
base::unique_fd(), nullptr);
@@ -1223,13 +1224,13 @@ TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 7845cab397..35d0215fa1 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -144,11 +144,12 @@ static constexpr mat4 inverseOrientation(uint32_t transform) {
return inverse(tr);
}
-std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- auto result = Layer::prepareClientComposition(targetSettings);
+ std::optional<compositionengine::LayerFE::LayerSettings> result =
+ Layer::prepareClientComposition(targetSettings);
if (!result) {
return result;
}
@@ -183,7 +184,7 @@ std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
- auto& layer = *result;
+ LayerFE::LayerSettings& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mBufferInfo.mBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -199,6 +200,9 @@ std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition
layer.source.buffer.maxContentLuminance = hasCta861_3
? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
: defaultMaxContentLuminance;
+ layer.frameNumber = mCurrentFrameNumber;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
@@ -264,9 +268,11 @@ std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition
// layer.
layer.source.buffer.buffer = nullptr;
layer.alpha = 1.0;
+ layer.frameNumber = 0;
+ layer.bufferId = 0;
}
- return result;
+ return layer;
}
bool BufferLayer::isHdrY410() const {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 5f5532ef41..b2398a8ef7 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -177,7 +177,7 @@ protected:
*/
bool onPreComposition(nsecs_t) override;
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 6aea88abd6..04854d0803 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,7 +50,7 @@ ColorLayer::ColorLayer(const LayerCreationArgs& args)
ColorLayer::~ColorLayer() = default;
-std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
auto result = Layer::prepareClientComposition(targetSettings);
if (!result) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 634a80003a..9246eb2ed2 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -46,7 +46,7 @@ protected:
* compositionengine::LayerFE overrides
*/
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 42d9875f55..a634f2f83c 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -44,6 +44,7 @@ cc_library {
name: "libcompositionengine",
defaults: ["libcompositionengine_defaults"],
srcs: [
+ "src/ClientCompositionRequestCache.cpp",
"src/CompositionEngine.cpp",
"src/Display.cpp",
"src/DisplayColorProfile.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 9193dc0e3f..a38d1f3c99 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -52,6 +52,10 @@ public:
// Creates a render surface for the display
virtual void createRenderSurface(const RenderSurfaceCreationArgs&) = 0;
+ // Creates a cache to cache duplicate client composition requests and skip
+ // similar requests if needed.
+ virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
+
protected:
~Display() = default;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e432b1cb72..f34509f48f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -89,16 +89,26 @@ public:
Region& clearRegion;
};
+ // A superset of LayerSettings required by RenderEngine to compose a layer
+ // and buffer info to determine duplicate client composition requests.
+ struct LayerSettings : renderengine::LayerSettings {
+ // Currently latched buffer if, 0 if invalid.
+ uint64_t bufferId = 0;
+
+ // Currently latched frame number, 0 if invalid.
+ uint64_t frameNumber = 0;
+ };
+
// Returns the LayerSettings to pass to RenderEngine::drawLayers, or
// nullopt_t if the layer does not render
- virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ virtual std::optional<LayerSettings> prepareClientComposition(
ClientCompositionTargetSettings&) = 0;
// Returns the LayerSettings used to draw shadows around a layer. It is passed
// to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render
// shadows.
- virtual std::optional<renderengine::LayerSettings> prepareShadowClientComposition(
- const renderengine::LayerSettings& layerSettings, const Rect& displayViewport,
+ virtual std::optional<LayerSettings> prepareShadowClientComposition(
+ const LayerSettings& layerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) = 0;
// Called after the layer is displayed to update the presentation fence
@@ -125,6 +135,13 @@ static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lh
lhs.clearRegion.hasSameRects(rhs.clearRegion);
}
+static inline bool operator==(const LayerFE::LayerSettings& lhs,
+ const LayerFE::LayerSettings& rhs) {
+ return static_cast<const renderengine::LayerSettings&>(lhs) ==
+ static_cast<const renderengine::LayerSettings&>(rhs) &&
+ lhs.bufferId == rhs.bufferId && lhs.frameNumber == rhs.frameNumber;
+}
+
// Defining PrintTo helps with Google Tests.
static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& settings,
::std::ostream* os) {
@@ -140,5 +157,13 @@ static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& setti
*os << "\n}";
}
+static inline void PrintTo(const LayerFE::LayerSettings& settings, ::std::ostream* os) {
+ *os << "LayerFE::LayerSettings{";
+ PrintTo(static_cast<const renderengine::LayerSettings&>(settings), os);
+ *os << "\n .bufferId = " << settings.bufferId;
+ *os << "\n .frameNumber = " << settings.frameNumber;
+ *os << "\n}";
+}
+
} // namespace compositionengine
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 076fdad708..7a10c043c4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -271,12 +271,13 @@ protected:
virtual void chooseCompositionStrategy() = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
- virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) = 0;
virtual void appendRegionFlashRequests(
const Region& flashRegion,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+ std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+ virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h
new file mode 100644
index 0000000000..c14a6e8d99
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 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 <cstdint>
+#include <deque>
+
+#include <compositionengine/LayerFE.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+// The cache is used to skip duplicate client composition requests. We do so by keeping track
+// of every composition request and the buffer that the request is rendered into. During the
+// next composition request, if the request matches what was rendered into the buffer, then
+// we can skip of the request, pass back an empty fence, and let HWC use the previous render
+// result.
+//
+// The cache is a mapping of the RenderSurface buffer id (unique per process) and a snapshot of
+// the composition request. We need to make sure the request, including the order of the
+// layers, do not change from call to call. The snapshot removes strong references to the
+// client buffer id so we don't extend the lifetime of the buffer by storing it in the cache.
+class ClientCompositionRequestCache {
+public:
+ explicit ClientCompositionRequestCache(uint32_t cacheSize) : mMaxCacheSize(cacheSize){};
+ ~ClientCompositionRequestCache() = default;
+ bool exists(uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) const;
+ void add(uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings);
+ void remove(uint64_t bufferId);
+
+private:
+ uint32_t mMaxCacheSize;
+ struct ClientCompositionRequest {
+ renderengine::DisplaySettings display;
+ std::vector<LayerFE::LayerSettings> layerSettings;
+ ClientCompositionRequest(const renderengine::DisplaySettings& _display,
+ const std::vector<LayerFE::LayerSettings>& _layerSettings);
+ bool equals(const renderengine::DisplaySettings& _display,
+ const std::vector<LayerFE::LayerSettings>& _layerSettings) const;
+ };
+
+ // Cache of requests, keyed by corresponding GraphicBuffer ID.
+ std::deque<std::pair<uint64_t /* bufferId */, ClientCompositionRequest>> mCache;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index ace876c310..39acb37e0d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -60,6 +60,7 @@ public:
void createDisplayColorProfile(
const compositionengine::DisplayColorProfileCreationArgs&) override;
void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
+ void createClientCompositionCache(uint32_t cacheSize) override;
// Internal helpers used by chooseCompositionStrategy()
using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 3a9776d57a..240aea85e2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -18,8 +18,10 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Output.h>
+#include <compositionengine/impl/ClientCompositionRequestCache.h>
#include <compositionengine/impl/OutputCompositionState.h>
-
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
#include <memory>
#include <utility>
#include <vector>
@@ -83,6 +85,7 @@ public:
void finishFrame(const CompositionRefreshArgs&) override;
std::optional<base::unique_fd> composeSurfaces(const Region&) override;
void postFramebuffer() override;
+ void cacheClientCompositionRequests(uint32_t) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
@@ -96,11 +99,10 @@ protected:
void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
- std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion,
ui::Dataspace outputDataspace) override;
- void appendRegionFlashRequests(const Region&,
- std::vector<renderengine::LayerSettings>&) override;
+ void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
@@ -128,6 +130,7 @@ private:
ReleasedLayers mReleasedLayers;
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
+ std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 17d3d3fb7d..34dadb5425 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -45,6 +45,9 @@ struct OutputCompositionState {
// composition
bool flipClientTarget{false};
+ // If true, the current frame reused the buffer from a previous client composition
+ bool reusedClientComposition{false};
+
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 57f33ae818..3a4c70fd64 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -40,6 +40,7 @@ public:
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
+ MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 739490fe8e..163e302d88 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -36,11 +36,10 @@ public:
void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset));
MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
MOCK_METHOD1(prepareClientComposition,
- std::optional<renderengine::LayerSettings>(
+ std::optional<LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD3(prepareShadowClientComposition,
- std::optional<renderengine::LayerSettings>(const renderengine::LayerSettings&,
- const Rect&, ui::Dataspace));
+ std::optional<LayerSettings>(const LayerSettings&, const Rect&, ui::Dataspace));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7f5bd0603c..9135765650 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -107,10 +107,11 @@ public:
MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<renderengine::LayerSettings>(bool, Region&, ui::Dataspace));
+ std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
- void(const Region&, std::vector<renderengine::LayerSettings>&));
+ void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+ MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
new file mode 100644
index 0000000000..acaaf4e1b9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <algorithm>
+
+#include <compositionengine/impl/ClientCompositionRequestCache.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android::compositionengine::impl {
+
+namespace {
+LayerFE::LayerSettings getLayerSettingsSnapshot(const LayerFE::LayerSettings& settings) {
+ LayerFE::LayerSettings snapshot = settings;
+ snapshot.source.buffer.buffer = nullptr;
+ snapshot.source.buffer.fence = nullptr;
+ return snapshot;
+}
+
+inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs,
+ const renderengine::LayerSettings& rhs) {
+ return lhs.geometry == rhs.geometry && lhs.alpha == rhs.alpha &&
+ lhs.sourceDataspace == rhs.sourceDataspace &&
+ lhs.colorTransform == rhs.colorTransform &&
+ lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow;
+}
+
+inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) {
+ return lhs.textureName == rhs.textureName &&
+ lhs.useTextureFiltering == rhs.useTextureFiltering &&
+ lhs.textureTransform == rhs.textureTransform &&
+ lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
+ lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
+ lhs.maxMasteringLuminance == rhs.maxMasteringLuminance &&
+ lhs.maxContentLuminance == rhs.maxContentLuminance;
+}
+
+inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs,
+ const renderengine::LayerSettings& rhs) {
+ // compare LayerSettings without LayerSettings.PixelSource
+ return equalIgnoringSource(lhs, rhs) &&
+
+ // compare LayerSettings.PixelSource without buffer
+ lhs.source.solidColor == rhs.source.solidColor &&
+
+ // compare LayerSettings.PixelSource.Buffer without buffer & fence
+ equalIgnoringBuffer(lhs.source.buffer, rhs.source.buffer);
+}
+
+bool layerSettingsAreEqual(const LayerFE::LayerSettings& lhs, const LayerFE::LayerSettings& rhs) {
+ return lhs.bufferId == rhs.bufferId && lhs.frameNumber == rhs.frameNumber &&
+ equalIgnoringBuffer(lhs, rhs);
+}
+
+} // namespace
+
+ClientCompositionRequestCache::ClientCompositionRequest::ClientCompositionRequest(
+ const renderengine::DisplaySettings& initDisplay,
+ const std::vector<LayerFE::LayerSettings>& initLayerSettings)
+ : display(initDisplay) {
+ layerSettings.reserve(initLayerSettings.size());
+ for (const LayerFE::LayerSettings& settings : initLayerSettings) {
+ layerSettings.push_back(getLayerSettingsSnapshot(settings));
+ }
+}
+
+bool ClientCompositionRequestCache::ClientCompositionRequest::equals(
+ const renderengine::DisplaySettings& newDisplay,
+ const std::vector<LayerFE::LayerSettings>& newLayerSettings) const {
+ return newDisplay == display &&
+ std::equal(layerSettings.begin(), layerSettings.end(), newLayerSettings.begin(),
+ newLayerSettings.end(), layerSettingsAreEqual);
+}
+
+bool ClientCompositionRequestCache::exists(
+ uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) const {
+ for (const auto& [cachedBufferId, cachedRequest] : mCache) {
+ if (cachedBufferId == bufferId) {
+ return cachedRequest.equals(display, layerSettings);
+ }
+ }
+ return false;
+}
+
+void ClientCompositionRequestCache::add(uint64_t bufferId,
+ const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) {
+ const ClientCompositionRequest request(display, layerSettings);
+ for (auto& [cachedBufferId, cachedRequest] : mCache) {
+ if (cachedBufferId == bufferId) {
+ cachedRequest = std::move(request);
+ return;
+ }
+ }
+
+ if (mCache.size() >= mMaxCacheSize) {
+ mCache.pop_front();
+ }
+
+ mCache.emplace_back(bufferId, std::move(request));
+}
+
+void ClientCompositionRequestCache::remove(uint64_t bufferId) {
+ for (auto it = mCache.begin(); it != mCache.end(); it++) {
+ if (it->first == bufferId) {
+ mCache.erase(it);
+ return;
+ }
+ }
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 20f765c4a8..13f5137064 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -137,6 +137,10 @@ void Display::createRenderSurface(const RenderSurfaceCreationArgs& args) {
compositionengine::impl::createRenderSurface(getCompositionEngine(), *this, args));
}
+void Display::createClientCompositionCache(uint32_t cacheSize) {
+ cacheClientCompositionRequests(cacheSize);
+}
+
std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
const std::shared_ptr<compositionengine::Layer>& layer,
const sp<compositionengine::LayerFE>& layerFE) const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 650b5c1d29..df33cf0df1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -231,6 +231,14 @@ void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>
dirtyEntireOutput();
}
+void Output::cacheClientCompositionRequests(uint32_t cacheSize) {
+ if (cacheSize == 0) {
+ mClientCompositionRequestCache.reset();
+ } else {
+ mClientCompositionRequestCache = std::make_unique<ClientCompositionRequestCache>(cacheSize);
+ }
+};
+
void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
mRenderSurface = std::move(surface);
}
@@ -806,6 +814,7 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion
ALOGV(__FUNCTION__);
const auto& outputState = getState();
+ OutputCompositionState& outputCompositionState = editState();
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
outputState.usesClientComposition};
base::unique_fd readyFence;
@@ -839,7 +848,7 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion
clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
// Generate the client composition requests for the layers on this output.
- std::vector<renderengine::LayerSettings> clientCompositionLayers =
+ std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
clientCompositionDisplay.clearRegion,
clientCompositionDisplay.outputDataspace);
@@ -871,6 +880,19 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion
return std::nullopt;
}
+ // Check if the client composition requests were rendered into the provided graphic buffer. If
+ // so, we can reuse the buffer and avoid client composition.
+ if (mClientCompositionRequestCache) {
+ if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay,
+ clientCompositionLayers)) {
+ outputCompositionState.reusedClientComposition = true;
+ setExpensiveRenderingExpected(false);
+ return readyFence;
+ }
+ mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay,
+ clientCompositionLayers);
+ }
+
// We boost GPU frequency here because there will be color spaces conversion
// or complex GPU shaders and it's expensive. We boost the GPU frequency so that
// GPU composition can finish in time. We must reset GPU frequency afterwards,
@@ -882,10 +904,25 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion
setExpensiveRenderingExpected(true);
}
+ std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
+ clientCompositionLayerPointers.reserve(clientCompositionLayers.size());
+ std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
+ std::back_inserter(clientCompositionLayerPointers),
+ [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* {
+ return &settings;
+ });
+
const nsecs_t renderEngineStart = systemTime();
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- &readyFence);
+ status_t status =
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true,
+ std::move(fd), &readyFence);
+
+ if (status != NO_ERROR && mClientCompositionRequestCache) {
+ // If rendering was not successful, remove the request from the cache.
+ mClientCompositionRequestCache->remove(buf->getId());
+ }
+
auto& timeStats = getCompositionEngine().getTimeStats();
if (readyFence.get() < 0) {
timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
@@ -898,9 +935,9 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion
return readyFence;
}
-std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) {
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ std::vector<LayerFE::LayerSettings> clientCompositionLayers;
ALOGV("Rendering client layers");
const auto& outputState = getState();
@@ -944,15 +981,17 @@ std::vector<renderengine::LayerSettings> Output::generateClientCompositionReques
supportsProtectedContent,
clientComposition ? clearRegion : dummyRegion,
};
- if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+ if (std::optional<LayerFE::LayerSettings> result =
+ layerFE.prepareClientComposition(targetSettings)) {
if (!clientComposition) {
- auto& layerSettings = *result;
+ LayerFE::LayerSettings& layerSettings = *result;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
layerSettings.alpha = half(0.0);
layerSettings.disableBlending = true;
+ layerSettings.frameNumber = 0;
} else {
- std::optional<renderengine::LayerSettings> shadowLayer =
+ std::optional<LayerFE::LayerSettings> shadowLayer =
layerFE.prepareShadowClientComposition(*result, outputState.viewport,
outputDataspace);
if (shadowLayer) {
@@ -979,13 +1018,12 @@ std::vector<renderengine::LayerSettings> Output::generateClientCompositionReques
}
void Output::appendRegionFlashRequests(
- const Region& flashRegion,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ const Region& flashRegion, std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
if (flashRegion.isEmpty()) {
return;
}
- renderengine::LayerSettings layerSettings;
+ LayerFE::LayerSettings layerSettings;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
layerSettings.alpha = half(1.0);
@@ -1065,6 +1103,7 @@ void Output::chooseCompositionStrategy() {
auto& outputState = editState();
outputState.usesClientComposition = true;
outputState.usesDeviceComposition = false;
+ outputState.reusedClientComposition = false;
}
bool Output::getSkipColorTransform() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 0fcc308ca0..84d79f7924 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -27,6 +27,7 @@ void OutputCompositionState::dump(std::string& out) const {
dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
+ dumpVal(out, "reusedClientComposition", reusedClientComposition);
dumpVal(out, "layerStack", layerStackId);
dumpVal(out, "layerStackInternal", layerStackInternal);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6761b866c4..b559e425ca 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -47,12 +47,14 @@ using testing::_;
using testing::ByMove;
using testing::ByRef;
using testing::DoAll;
+using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::Eq;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
using testing::Mock;
+using testing::Pointee;
using testing::Property;
using testing::Ref;
using testing::Return;
@@ -62,6 +64,7 @@ using testing::StrictMock;
constexpr auto TR_IDENT = 0u;
constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
+constexpr auto MAX_CLIENT_COMPOSITION_CACHE_SIZE = 3;
const mat4 kIdentity;
const mat4 kNonIdentityHalf = mat4() * 0.5;
@@ -2765,9 +2768,9 @@ struct OutputComposeSurfacesTest : public testing::Test {
// mock implementations.
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<renderengine::LayerSettings>(bool, Region&, ui::Dataspace));
+ std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
- void(const Region&, std::vector<renderengine::LayerSettings>&));
+ void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
};
@@ -2775,6 +2778,7 @@ struct OutputComposeSurfacesTest : public testing::Test {
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ mOutput.cacheClientCompositionRequests(MAX_CLIENT_COMPOSITION_CACHE_SIZE);
mOutput.mState.frame = kDefaultOutputFrame;
mOutput.mState.viewport = kDefaultOutputViewport;
@@ -2787,6 +2791,7 @@ struct OutputComposeSurfacesTest : public testing::Test {
mOutput.mState.needsFiltering = false;
mOutput.mState.usesClientComposition = true;
mOutput.mState.usesDeviceComposition = false;
+ mOutput.mState.reusedClientComposition = false;
EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -2863,7 +2868,7 @@ TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFails) {
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -2877,7 +2882,7 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) {
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -2889,8 +2894,8 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) {
}
TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) {
- renderengine::LayerSettings r1;
- renderengine::LayerSettings r2;
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
@@ -2899,26 +2904,143 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) {
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{r1}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(
Invoke([&](const Region&,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
clientCompositionLayers.emplace_back(r2);
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAreArray({r1, r2}), _, true, _, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
.WillRepeatedly(Return(NO_ERROR));
verify().execute().expectAFenceWasReturned();
}
+TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithoutCache) {
+ mOutput.cacheClientCompositionRequests(0);
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .Times(2)
+ .WillOnce(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) {
+ mOutput.cacheClientCompositionRequests(3);
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ // We do not expect another call to draw layers.
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_TRUE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) {
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ sp<GraphicBuffer> otherOutputBuffer = new GraphicBuffer();
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
+ .WillOnce(Return(mOutputBuffer))
+ .WillOnce(Return(otherOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillRepeatedly(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) {
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+ LayerFE::LayerSettings r3;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+ r3.geometry.boundaries = FloatRect{5, 6, 7, 9};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3048,7 +3170,7 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, _))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3166,7 +3288,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas
mOutput.mState.dataspace = kExpensiveOutputDataspace;
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kExpensiveOutputDataspace))
- .WillOnce(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
// For this test, we also check the call order of key functions.
InSequence seq;
@@ -3184,7 +3306,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas
struct GenerateClientCompositionRequestsTest : public testing::Test {
struct OutputPartialMock : public OutputPartialMockBase {
// compositionengine::Output overrides
- std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion,
ui::Dataspace dataspace) override {
return impl::Output::generateClientCompositionRequests(supportsProtectedContent,
@@ -3206,7 +3328,7 @@ struct GenerateClientCompositionRequestsTest : public testing::Test {
StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
impl::OutputLayerCompositionState mOutputLayerState;
- renderengine::LayerSettings mRELayerSettings;
+ LayerFE::LayerSettings mLayerSettings;
};
GenerateClientCompositionRequestsTest() {
@@ -3237,11 +3359,11 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers
mLayers[i].mOutputLayerState.clearClientTarget = false;
mLayers[i].mOutputLayerState.visibleRegion = Region(kDisplayFrame);
mLayers[i].mLayerFEState.isOpaque = true;
- mLayers[i].mRELayerSettings.geometry.boundaries =
+ mLayers[i].mLayerSettings.geometry.boundaries =
FloatRect{static_cast<float>(i + 1), 0.f, 0.f, 0.f};
- mLayers[i].mRELayerSettings.source.solidColor = {1.0f, 1.0f, 1.0f};
- mLayers[i].mRELayerSettings.alpha = 1.0f;
- mLayers[i].mRELayerSettings.disableBlending = false;
+ mLayers[i].mLayerSettings.source.solidColor = {1.0f, 1.0f, 1.0f};
+ mLayers[i].mLayerSettings.alpha = 1.0f;
+ mLayers[i].mLayerSettings.disableBlending = false;
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(i))
.WillRepeatedly(Return(&mLayers[i].mOutputLayer));
@@ -3292,30 +3414,30 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, requiresVisibleRegionA
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositionRequests) {
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt));
EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mRELayerSettings));
+ .WillOnce(Return(mLayers[1].mLayerSettings));
EXPECT_CALL(mLayers[1].mLayerFE,
- prepareShadowClientComposition(mLayers[1].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
.WillOnce(Return(std::nullopt));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(3u, requests.size());
- EXPECT_EQ(mLayers[1].mRELayerSettings, requests[0]);
- EXPECT_EQ(mREShadowSettings, requests[1]);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[2]);
+ EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]);
+ EXPECT_EQ(mShadowSettings, requests[1]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
@@ -3340,7 +3462,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
mLayers[2].mLayerFEState.isOpaque = true;
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3348,7 +3470,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3368,7 +3490,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
mLayers[2].mLayerFEState.isOpaque = false;
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3376,7 +3498,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3401,9 +3523,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu
mLayers[2].mLayerFEState.isOpaque = true;
EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mRELayerSettings));
+ .WillOnce(Return(mLayers[1].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3413,13 +3535,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu
ASSERT_EQ(2u, requests.size());
// The second layer is expected to be rendered as alpha=0 black with no blending
- EXPECT_EQ(mLayers[1].mRELayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
+ EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
EXPECT_FALSE(requests[0].source.buffer.buffer);
EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
EXPECT_EQ(half{0.f}, requests[0].alpha);
EXPECT_EQ(true, requests[0].disableBlending);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[1]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3689,12 +3811,12 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq
leftLayer.mOutputLayerState.clearClientTarget = false;
leftLayer.mOutputLayerState.visibleRegion = Region(Rect(0, 0, 1000, 1000));
leftLayer.mLayerFEState.isOpaque = true;
- leftLayer.mRELayerSettings.source.solidColor = {1.f, 0.f, 0.f};
+ leftLayer.mLayerSettings.source.solidColor = {1.f, 0.f, 0.f};
rightLayer.mOutputLayerState.clearClientTarget = false;
rightLayer.mOutputLayerState.visibleRegion = Region(Rect(1000, 0, 2000, 1000));
rightLayer.mLayerFEState.isOpaque = true;
- rightLayer.mRELayerSettings.source.solidColor = {0.f, 1.f, 0.f};
+ rightLayer.mLayerSettings.source.solidColor = {0.f, 1.f, 0.f};
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
@@ -3716,9 +3838,9 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq
EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings))))
- .WillOnce(Return(leftLayer.mRELayerSettings));
+ .WillOnce(Return(leftLayer.mLayerSettings));
EXPECT_CALL(leftLayer.mLayerFE,
- prepareShadowClientComposition(leftLayer.mRELayerSettings, kPortraitViewport,
+ prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport,
kOutputDataspace))
.WillOnce(Return(std::nullopt));
@@ -3734,9 +3856,9 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq
EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings))))
- .WillOnce(Return(rightLayer.mRELayerSettings));
+ .WillOnce(Return(rightLayer.mLayerSettings));
EXPECT_CALL(rightLayer.mLayerFE,
- prepareShadowClientComposition(rightLayer.mRELayerSettings, kPortraitViewport,
+ prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport,
kOutputDataspace))
.WillOnce(Return(std::nullopt));
@@ -3744,8 +3866,8 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq
auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
accumClearRegion, kOutputDataspace);
ASSERT_EQ(2u, requests.size());
- EXPECT_EQ(leftLayer.mRELayerSettings, requests[0]);
- EXPECT_EQ(rightLayer.mRELayerSettings, requests[1]);
+ EXPECT_EQ(leftLayer.mLayerSettings, requests[0]);
+ EXPECT_EQ(rightLayer.mLayerSettings, requests[1]);
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3755,8 +3877,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
mLayers[2].mOutputLayerState.visibleRegion = kPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
@@ -3764,18 +3886,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mREShadowSettings, requests[0]);
+ EXPECT_EQ(mShadowSettings, requests[0]);
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3786,8 +3908,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
const Region kPartialContentWithPartialShadowRegion =
Region(kContentWithShadow).subtract(Rect(40, 40, 50, 80));
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
@@ -3795,19 +3917,19 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
- EXPECT_EQ(mREShadowSettings, requests[0]);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[1]);
+ EXPECT_EQ(mShadowSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
}
} // namespace
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e2122d1d30..4ae6dadfe8 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -70,6 +70,12 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
args.nativeWindow.get()),
args.nativeWindow, args.displaySurface});
+ if (!mFlinger->mDisableClientCompositionCache &&
+ SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
+ mCompositionDisplay->createClientCompositionCache(
+ static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
+ }
+
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
std::move(args.hdrCapabilities),
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f4d4329f6d..11ae46dbcd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -551,7 +551,7 @@ const char* Layer::getDebugName() const {
// drawing...
// ---------------------------------------------------------------------------
-std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
if (!getCompositionLayer()) {
return {};
@@ -559,7 +559,8 @@ std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
FloatRect bounds = getBounds();
half alpha = getAlpha();
- renderengine::LayerSettings layerSettings;
+
+ compositionengine::LayerFE::LayerSettings layerSettings;
layerSettings.geometry.boundaries = bounds;
if (targetSettings.useIdentityTransform) {
layerSettings.geometry.positionTransform = mat4();
@@ -581,8 +582,8 @@ std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
return layerSettings;
}
-std::optional<renderengine::LayerSettings> Layer::prepareShadowClientComposition(
- const renderengine::LayerSettings& casterLayerSettings, const Rect& displayViewport,
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareShadowClientComposition(
+ const LayerFE::LayerSettings& casterLayerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) {
renderengine::ShadowSettings shadow = getShadowSettings(displayViewport);
if (shadow.length <= 0.f) {
@@ -593,7 +594,8 @@ std::optional<renderengine::LayerSettings> Layer::prepareShadowClientComposition
const bool casterIsOpaque = ((casterLayerSettings.source.buffer.buffer != nullptr) &&
casterLayerSettings.source.buffer.isOpaque);
- renderengine::LayerSettings shadowLayer = casterLayerSettings;
+ compositionengine::LayerFE::LayerSettings shadowLayer = casterLayerSettings;
+
shadowLayer.shadow = shadow;
shadowLayer.geometry.boundaries = mBounds; // ignore transparent region
@@ -604,13 +606,16 @@ std::optional<renderengine::LayerSettings> Layer::prepareShadowClientComposition
shadowLayer.shadow.spotColor *= casterAlpha;
shadowLayer.sourceDataspace = outputDataspace;
shadowLayer.source.buffer.buffer = nullptr;
+ shadowLayer.source.buffer.fence = nullptr;
+ shadowLayer.frameNumber = 0;
+ shadowLayer.bufferId = 0;
if (shadowLayer.shadow.ambientColor.a <= 0.f && shadowLayer.shadow.spotColor.a <= 0.f) {
return {};
}
float casterCornerRadius = shadowLayer.geometry.roundedCornersRadius;
- const FloatRect& cornerRadiusCropRect = casterLayerSettings.geometry.roundedCornersCrop;
+ const FloatRect& cornerRadiusCropRect = shadowLayer.geometry.roundedCornersCrop;
const FloatRect& casterRect = shadowLayer.geometry.boundaries;
// crop used to set the corner radius may be larger than the content rect. Adjust the corner
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ffe004f9e9..6acf5fb3b5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -527,10 +527,10 @@ public:
void latchCompositionState(compositionengine::LayerFECompositionState&,
compositionengine::LayerFE::StateSubset subset) const override;
void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- std::optional<renderengine::LayerSettings> prepareShadowClientComposition(
- const renderengine::LayerSettings& layerSettings, const Rect& displayViewport,
+ std::optional<LayerSettings> prepareShadowClientComposition(
+ const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1b1b58b1e7..a894005c1d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -353,6 +353,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
+ property_get("debug.sf.disable_client_composition_cache", value, "1");
+ mDisableClientCompositionCache = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -1893,13 +1896,19 @@ void SurfaceFlinger::handleMessageRefresh() {
mHadClientComposition =
std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
auto& displayDevice = tokenDisplayPair.second;
- return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+ return displayDevice->getCompositionDisplay()->getState().usesClientComposition &&
+ !displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
});
mHadDeviceComposition =
std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
auto& displayDevice = tokenDisplayPair.second;
return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
});
+ mReusedClientComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
+ });
mVSyncModulator->onRefreshed(mHadClientComposition);
@@ -2079,6 +2088,10 @@ void SurfaceFlinger::postComposition()
mTimeStats->incrementClientCompositionFrames();
}
+ if (mReusedClientComposition) {
+ mTimeStats->incrementClientCompositionReusedFrames();
+ }
+
mTimeStats->setPresentFenceGlobal(presentFenceTime);
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
@@ -5408,7 +5421,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
const auto& displayViewport = renderArea.getDisplayViewport();
renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompositionLayers;
// assume that bounds are never offset, and that they are the same as the
// buffer bounds.
@@ -5469,7 +5482,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
- renderengine::LayerSettings fillLayer;
+ compositionengine::LayerFE::LayerSettings fillLayer;
fillLayer.source.buffer.buffer = nullptr;
fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0);
@@ -5490,7 +5503,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
};
auto result = layer->prepareClientComposition(targetSettings);
if (result) {
- std::optional<renderengine::LayerSettings> shadowLayer =
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowLayer =
layer->prepareShadowClientComposition(*result, displayViewport,
clientCompositionDisplay.outputDataspace);
if (shadowLayer) {
@@ -5500,13 +5513,20 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
}
});
+ std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
+ clientCompositionLayers.reserve(clientCompositionLayers.size());
+ std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
+ std::back_inserter(clientCompositionLayerPointers),
+ [](compositionengine::LayerFE::LayerSettings& settings)
+ -> renderengine::LayerSettings* { return &settings; });
+
clientCompositionDisplay.clearRegion = clearRegion;
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
base::unique_fd drawFence;
getRenderEngine().useProtectedContext(false);
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
/*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
*outSyncFd = drawFence.release();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7f7d8da245..f8980a513f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -323,6 +323,10 @@ public:
// Inherit from ClientCache::ErasedRecipient
void bufferErased(const client_cache_t& clientCacheId) override;
+ // If set, disables reusing client composition buffers. This can be set by
+ // debug.sf.disable_client_composition_cache
+ bool mDisableClientCompositionCache = false;
+
private:
friend class BufferLayer;
friend class BufferQueueLayer;
@@ -987,6 +991,10 @@ private:
// Note that it is possible for a frame to be composed via both client and device
// composition, for example in the case of overlays.
bool mHadDeviceComposition = false;
+ // True if in the previous frame, the client composition was skipped by reusing the buffer
+ // used in a previous composition. This can happed if the client composition requests
+ // did not change.
+ bool mReusedClientComposition = false;
enum class BootStage {
BOOTLOADER,
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 44a59fd246..c793941d49 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -155,6 +155,15 @@ void TimeStats::incrementClientCompositionFrames() {
mTimeStats.clientCompositionFrames++;
}
+void TimeStats::incrementClientCompositionReusedFrames() {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.clientCompositionReusedFrames++;
+}
+
static int32_t msBetween(nsecs_t start, nsecs_t end) {
int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::nanoseconds(end - start))
@@ -666,6 +675,7 @@ void TimeStats::clearGlobalLocked() {
mTimeStats.totalFrames = 0;
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.clientCompositionReusedFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5cd421c939..4e3ea2088f 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -51,6 +51,7 @@ public:
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
+ virtual void incrementClientCompositionReusedFrames() = 0;
// Records the start and end times for a frame.
// The start time is the same as the beginning of a SurfaceFlinger
@@ -178,6 +179,7 @@ public:
void incrementTotalFrames() override;
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
+ void incrementClientCompositionReusedFrames() override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 7e43880cfd..0ba90e23c9 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -102,6 +102,7 @@ std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> m
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
+ StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStats) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index bd97ecc57f..702c50e58e 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -59,6 +59,7 @@ public:
int32_t totalFrames = 0;
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
+ int32_t clientCompositionReusedFrames = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
Histogram frameDuration;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 8a762d4030..98cc023953 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -328,8 +328,9 @@ struct BaseDisplayVariant {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -377,8 +378,9 @@ struct BaseDisplayVariant {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -627,7 +629,7 @@ struct BaseLayerProperties {
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -643,16 +645,16 @@ struct BaseLayerProperties {
"verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
- EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
- EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
- EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
- EXPECT_EQ(false, layer.source.buffer.isOpaque);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
+ EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
+ EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
+ EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
+ EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
+ EXPECT_EQ(false, layer->source.buffer.isOpaque);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -676,7 +678,7 @@ struct BaseLayerProperties {
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -692,14 +694,14 @@ struct BaseLayerProperties {
"setupREColorCompositionCallExpectations verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2]),
- layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -752,7 +754,7 @@ struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties>
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -768,12 +770,12 @@ struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties>
"verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(1.0f, layer.alpha);
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(1.0f, layer->alpha);
return NO_ERROR;
});
}
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index c667080b41..7a834a20ac 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -42,6 +42,7 @@ namespace {
using testing::_;
using testing::Contains;
+using testing::HasSubstr;
using testing::InSequence;
using testing::SizeIs;
using testing::UnorderedElementsAre;
@@ -296,6 +297,21 @@ TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
}
+TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -640,6 +656,16 @@ TEST_F(TimeStatsTest, canClearTimeStats) {
EXPECT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, canClearClientCompositionSkippedFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+}
+
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 9ada5ef4aa..d1df08c40a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -35,6 +35,7 @@ public:
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));