diff options
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>&)); |