diff options
35 files changed, 589 insertions, 599 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index c5a994278b..3d6ac8f198 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -449,6 +449,7 @@ bool GLESRenderEngine::isCurrent() const { } base::unique_fd GLESRenderEngine::flush() { + ATRACE_CALL(); if (!GLExtensions::getInstance().hasNativeFenceSync()) { return base::unique_fd(); } @@ -479,6 +480,7 @@ base::unique_fd GLESRenderEngine::flush() { } bool GLESRenderEngine::finish() { + ATRACE_CALL(); if (!GLExtensions::getInstance().hasFenceSync()) { ALOGW("no synchronization support"); return false; @@ -544,6 +546,8 @@ bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) { } void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) { + ATRACE_CALL(); + glDisable(GL_BLEND); glClearColor(red, green, blue, alpha); glClear(GL_COLOR_BUFFER_BIT); } @@ -594,6 +598,7 @@ void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) { } void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) { + ATRACE_CALL(); const GLImage& glImage = static_cast<const GLImage&>(image); const GLenum target = GL_TEXTURE_EXTERNAL_OES; @@ -608,8 +613,15 @@ void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& i } status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, + sp<Fence> bufferFence, bool readCache) { + return bindExternalTextureBuffer(texName, buffer, bufferFence, readCache, + /*persistCache=*/false); +} + +status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> bufferFence, bool readCache, bool persistCache) { + ATRACE_CALL(); if (readCache) { auto cachedImage = mImageCache.find(buffer->getId()); @@ -655,7 +667,7 @@ status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<Graphi } // We don't always want to persist to the cache, e.g. on older devices we - // might bind for synchronization purpoeses, but that might leak if we never + // might bind for synchronization purposes, but that might leak if we never // call drawLayers again, so it's just better to recreate the image again // if needed when we draw. if (persistCache) { @@ -703,6 +715,7 @@ FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& } status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { + ATRACE_CALL(); GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer); EGLImageKHR eglImage = glFramebuffer->getEGLImage(); uint32_t textureName = glFramebuffer->getTextureName(); @@ -770,6 +783,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers, ANativeWindowBuffer* const buffer, base::unique_fd* drawFence) { + ATRACE_CALL(); if (layers.empty()) { ALOGV("Drawing empty layer stack"); return NO_ERROR; @@ -786,6 +800,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, evictImages(layers); + // clear the entire buffer, sometimes when we reuse buffers we'd persist + // ghost images otherwise. + // we also require a full transparent framebuffer for overlays. This is + // probably not quite efficient on all GPUs, since we could filter out + // opaque layers. + clearWithColor(0.0, 0.0, 0.0, 0.0); + setViewportAndProjection(display.physicalDisplay, display.clip); setOutputDataSpace(display.outputDataspace); @@ -794,6 +815,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform; mState.projectionMatrix = projectionMatrix; if (!display.clearRegion.isEmpty()) { + glDisable(GL_BLEND); fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0); } @@ -813,9 +835,11 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, bool usePremultipliedAlpha = true; bool disableTexture = true; + bool isOpaque = false; if (layer.source.buffer.buffer != nullptr) { disableTexture = false; + isOpaque = layer.source.buffer.isOpaque; sp<GraphicBuffer> gBuf = layer.source.buffer.buffer; @@ -825,17 +849,19 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); - texture.setMatrix(layer.source.buffer.textureTransform.asArray()); + mat4 texMatrix = layer.source.buffer.textureTransform; + + texture.setMatrix(texMatrix.asArray()); texture.setFiltering(layer.source.buffer.useTextureFiltering); texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); setSourceY410BT2020(layer.source.buffer.isY410BT2020); renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); - texCoords[0] = vec2(0.0, 1.0); - texCoords[1] = vec2(0.0, 0.0); - texCoords[2] = vec2(1.0, 0.0); - texCoords[3] = vec2(1.0, 1.0); + texCoords[0] = vec2(0.0, 0.0); + texCoords[1] = vec2(0.0, 1.0); + texCoords[2] = vec2(1.0, 1.0); + texCoords[3] = vec2(1.0, 0.0); setupLayerTexturing(texture); } @@ -843,8 +869,11 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, 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, layer.source.buffer.isOpaque, disableTexture, - color, layer.geometry.roundedCornersRadius); + setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, + layer.geometry.roundedCornersRadius); + if (layer.disableBlending) { + glDisable(GL_BLEND); + } setSourceDataSpace(layer.sourceDataspace); drawMesh(mesh); @@ -903,6 +932,7 @@ void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sou } void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { + ATRACE_CALL(); mVpWidth = viewport.getWidth(); mVpHeight = viewport.getHeight(); diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index e094860f6e..34187f15ab 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -71,6 +71,8 @@ public: void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; void bindExternalTextureImage(uint32_t texName, const Image& image) override; + status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence, + bool readCache); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; void checkErrors() const override; @@ -184,6 +186,9 @@ private: const bool mUseColorManagement = false; // Cache of GL images that we'll store per GraphicBuffer ID + // TODO: Layer should call back on destruction instead to clean this up, + // as it has better system utilization at the potential expense of a + // more complicated interface. std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache; class FlushTracer { diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp index 4a519bb422..0e3b40568c 100644 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ b/libs/renderengine/gl/GLFramebuffer.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include "GLFramebuffer.h" #include <GLES/gl.h> @@ -21,6 +23,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <nativebase/nativebase.h> +#include <utils/Trace.h> #include "GLESRenderEngine.h" namespace android { @@ -40,6 +43,7 @@ GLFramebuffer::~GLFramebuffer() { } bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) { + ATRACE_CALL(); if (mEGLImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mEGLDisplay, mEGLImage); mEGLImage = EGL_NO_IMAGE_KHR; diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp index 587cb313c2..77e648e70f 100644 --- a/libs/renderengine/gl/GLImage.cpp +++ b/libs/renderengine/gl/GLImage.cpp @@ -14,11 +14,14 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include "GLImage.h" #include <vector> #include <log/log.h> +#include <utils/Trace.h> #include "GLESRenderEngine.h" #include "GLExtensions.h" @@ -50,6 +53,7 @@ GLImage::~GLImage() { } bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) { + ATRACE_CALL(); if (mEGLImage != EGL_NO_IMAGE_KHR) { if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) { ALOGE("failed to destroy image: %#x", eglGetError()); diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 56ac71416a..aa45ed8353 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -126,6 +126,9 @@ struct LayerSettings { // Additional layer-specific color transform to be applied before the global // transform. mat4 colorTransform = mat4(); + + // True if blending will be forced to be disabled. + bool disableBlending = false; }; } // namespace renderengine diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 20dd996ec2..bc1a4da962 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -108,6 +108,8 @@ public: virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0; + virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, + sp<Fence> fence, bool cleanCache) = 0; // When binding a native buffer, it must be done before setViewportAndProjection // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation. virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index b4c7c962f9..4b86cfeb68 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -52,6 +52,7 @@ public: MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); + MOCK_METHOD4(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>, bool)); MOCK_CONST_METHOD0(checkErrors, void()); MOCK_METHOD4(setViewportAndProjection, void(size_t, size_t, Rect, ui::Transform::orientation_flags)); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index bef25a83c7..f82beeb4c5 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -178,6 +178,9 @@ struct RenderEngineTest : public ::testing::Test { template <typename SourceVariant> void fillBufferWithRoundedCorners(); + template <typename SourceVariant> + void overlayCorners(); + void fillRedBufferTextureTransform(); void fillBufferTextureTransform(); @@ -194,7 +197,7 @@ struct RenderEngineTest : public ::testing::Test { void clearLeftRegion(); - void fillBufferThenClearRegion(); + void clearRegion(); // Dumb hack to get aroud the fact that tear-down for renderengine isn't // well defined right now, so we can't create multiple instances @@ -543,6 +546,44 @@ void RenderEngineTest::fillBufferWithRoundedCorners() { 255); } +template <typename SourceVariant> +void RenderEngineTest::overlayCorners() { + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + + std::vector<renderengine::LayerSettings> layersFirst; + + renderengine::LayerSettings layerOne; + layerOne.geometry.boundaries = + FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0); + SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this); + layerOne.alpha = 0.2; + + 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; + renderengine::LayerSettings layerTwo; + layerTwo.geometry.boundaries = + FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0, + DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); + SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this); + layerTwo.alpha = 1.0f; + + layersSecond.push_back(layerTwo); + invokeDraw(settings, layersSecond, mBuffer); + + expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0); + expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1, + DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + 0, 255, 0, 255); +} + void RenderEngineTest::fillRedBufferTextureTransform() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); @@ -685,14 +726,13 @@ void RenderEngineTest::clearLeftRegion() { invokeDraw(settings, layers, mBuffer); } -void RenderEngineTest::fillBufferThenClearRegion() { - fillGreenBuffer<ColorSourceVariant>(); +void RenderEngineTest::clearRegion() { // Reuse mBuffer clearLeftRegion(); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - 0, 255, 0, 255); + 0, 0, 0, 0); } TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) { @@ -747,6 +787,10 @@ TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) { fillBufferWithRoundedCorners<ColorSourceVariant>(); } +TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) { + overlayCorners<ColorSourceVariant>(); +} + TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) { fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>(); } @@ -795,6 +839,10 @@ TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>(); } +TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) { + overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>(); +} + TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) { fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>(); } @@ -843,6 +891,10 @@ TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) { fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>(); } +TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) { + overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>(); +} + TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) { fillBufferTextureTransform(); } @@ -855,8 +907,8 @@ TEST_F(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) { fillBufferWithoutPremultiplyAlpha(); } -TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) { - fillBufferThenClearRegion(); +TEST_F(RenderEngineTest, drawLayers_clearRegion) { + clearRegion(); } } // namespace android diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 65308a619d..f986329245 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -57,8 +57,6 @@ BufferLayer::BufferLayer(const LayerCreationArgs& args) compositionengine::LayerCreationArgs{this})} { ALOGV("Creating Layer %s", args.name.string()); - mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName); - mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; @@ -129,13 +127,11 @@ static constexpr mat4 inverseOrientation(uint32_t transform) { return inverse(tr); } -/* - * onDraw will draw the current layer onto the presentable buffer - */ -void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform) { +bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer) { ATRACE_CALL(); - + Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer); if (CC_UNLIKELY(mActiveBuffer == 0)) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with @@ -153,30 +149,27 @@ void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip, finished = true; return; } - under.orSelf(renderArea.getTransform().transform(layer->visibleRegion)); + under.orSelf(layer->visibleRegion); }); // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); if (!holes.isEmpty()) { - clearWithOpenGL(renderArea, 0, 0, 0, 1); + clearRegion.orSelf(holes); } - return; - } - - // Bind the current buffer to the GL texture, and wait for it to be - // ready for us to draw into. - status_t err = bindTextureImage(); - if (err != NO_ERROR) { - ALOGW("onDraw: bindTextureImage failed (err=%d)", err); - // Go ahead and draw the buffer anyway; no matter what we do the screen - // is probably going to have something visibly wrong. + return false; } - bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure()); - - auto& engine(mFlinger->getRenderEngine()); - + const State& s(getDrawingState()); if (!blackOutLayer) { + layer.source.buffer.buffer = mActiveBuffer; + layer.source.buffer.isOpaque = isOpaque(s); + layer.source.buffer.fence = mActiveBufferFence; + layer.source.buffer.cacheHint = useCachedBufferForClientComposition() + ? renderengine::Buffer::CachingHint::USE_CACHE + : renderengine::Buffer::CachingHint::NO_CACHE; + layer.source.buffer.textureName = mTextureName; + layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); + layer.source.buffer.isY410BT2020 = isHdrY410(); // TODO: we could be more subtle with isFixedSize() const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize(); @@ -213,17 +206,31 @@ void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip, memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); } - // Set things up for texturing. - mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); - mTexture.setFiltering(useFiltering); - mTexture.setMatrix(textureMatrix); + const Rect win{computeBounds()}; + const float bufferWidth = getBufferSize(s).getWidth(); + const float bufferHeight = getBufferSize(s).getHeight(); + + const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; + const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; + const float translateY = float(win.top) / bufferHeight; + const float translateX = float(win.left) / bufferWidth; - engine.setupLayerTexturing(mTexture); + // Flip y-coordinates because GLConsumer expects OpenGL convention. + mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * + mat4::translate(vec4(-.5, -.5, 0, 1)) * + mat4::translate(vec4(translateX, translateY, 0, 1)) * + mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); + + layer.source.buffer.useTextureFiltering = useFiltering; + layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr; } else { - engine.setupLayerBlackedOut(); + // If layer is blacked out, force alpha to 1 so that we draw a black color + // layer. + layer.source.buffer.buffer = nullptr; + layer.alpha = 1.0; } - drawWithOpenGL(renderArea, useIdentityTransform); - engine.disableTexturing(); + + return true; } bool BufferLayer::isHdrY410() const { @@ -606,67 +613,6 @@ bool BufferLayer::needsFiltering() const { sourceCrop.getWidth() != displayFrame.getWidth(); } -void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const { - ATRACE_CALL(); - const State& s(getDrawingState()); - - computeGeometry(renderArea, getBE().mMesh, useIdentityTransform); - - /* - * NOTE: the way we compute the texture coordinates here produces - * different results than when we take the HWC path -- in the later case - * the "source crop" is rounded to texel boundaries. - * This can produce significantly different results when the texture - * is scaled by a large amount. - * - * The GL code below is more logical (imho), and the difference with - * HWC is due to a limitation of the HWC API to integers -- a question - * is suspend is whether we should ignore this problem or revert to - * GL composition when a buffer scaling is applied (maybe with some - * minimal value)? Or, we could make GL behave like HWC -- but this feel - * like more of a hack. - */ - const Rect bounds{computeBounds()}; // Rounds from FloatRect - - Rect win = bounds; - const int bufferWidth = getBufferSize(s).getWidth(); - const int bufferHeight = getBufferSize(s).getHeight(); - - const float left = float(win.left) / float(bufferWidth); - const float top = float(win.top) / float(bufferHeight); - const float right = float(win.right) / float(bufferWidth); - const float bottom = float(win.bottom) / float(bufferHeight); - - // TODO: we probably want to generate the texture coords with the mesh - // here we assume that we only have 4 vertices - renderengine::Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>()); - // flip texcoords vertically because BufferLayerConsumer expects them to be in GL convention - texCoords[0] = vec2(left, 1.0f - top); - texCoords[1] = vec2(left, 1.0f - bottom); - texCoords[2] = vec2(right, 1.0f - bottom); - texCoords[3] = vec2(right, 1.0f - top); - - const auto roundedCornerState = getRoundedCornerState(); - const auto cropRect = roundedCornerState.cropRect; - setupRoundedCornersCropCoordinates(win, cropRect); - - auto& engine(mFlinger->getRenderEngine()); - engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */, - getColor(), roundedCornerState.radius); - engine.setSourceDataSpace(mCurrentDataSpace); - - if (isHdrY410()) { - engine.setSourceY410BT2020(true); - } - - engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight()); - - engine.drawMesh(getBE().mMesh); - engine.disableBlending(); - - engine.setSourceY410BT2020(false); -} - uint64_t BufferLayer::getHeadFrameNumber() const { if (hasFrameUpdate()) { return getFrameNumber(); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 8158d6c522..d0c1b134e9 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -22,6 +22,7 @@ #include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> +#include <renderengine/Image.h> #include <renderengine/Mesh.h> #include <renderengine/Texture.h> #include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE @@ -77,10 +78,6 @@ public: // isFixedSize - true if content has a fixed size bool isFixedSize() const override; - // onDraw - draws the surface. - void onDraw(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform) override; - bool isHdrY410() const override; void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport, @@ -168,13 +165,19 @@ protected: bool mRefreshPending{false}; + // Returns true if, when drawing the active buffer during gpu compositon, we + // should use a cached buffer or not. + virtual bool useCachedBufferForClientComposition() const = 0; + + // prepareClientLayer - constructs a RenderEngine layer for GPU composition. + bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer); + private: // Returns true if this layer requires filtering bool needsFiltering() const; - // drawing - void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const; - uint64_t getHeadFrameNumber() const; uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; @@ -182,9 +185,6 @@ private: // main thread. bool mBufferLatched{false}; // TODO: Use mActiveBuffer? - // The texture used to draw the layer in GLES composition mode - mutable renderengine::Texture mTexture; - Rect getBufferSize(const State& s) const override; std::shared_ptr<compositionengine::Layer> mCompositionLayer; diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6826050d86..7ed818454c 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -272,6 +272,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, // Update the BufferLayerConsumer state. mCurrentTexture = slot; mCurrentTextureBuffer = nextTextureBuffer; + mCurrentTextureBufferStaleForGpu = false; mCurrentTextureImageFreed = nullptr; mCurrentCrop = item.mCrop; mCurrentTransform = item.mTransform; @@ -294,48 +295,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, status_t BufferLayerConsumer::bindTextureImageLocked() { ATRACE_CALL(); - mRE.checkErrors(); - - // It is possible for the current slot's buffer to be freed before a new one - // is bound. In that scenario we still want to bind the image. - if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) { - BLC_LOGE("bindTextureImage: no currently-bound texture"); - mRE.bindExternalTextureImage(mTexName, *mRE.createImage()); - return NO_INIT; - } - - renderengine::Image* imageToRender; - - // mCurrentTextureImageFreed is non-null iff mCurrentTexture == - // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check. - if (mCurrentTextureImageFreed) { - imageToRender = mCurrentTextureImageFreed.get(); - } else if (mImages[mCurrentTexture]) { - imageToRender = mImages[mCurrentTexture].get(); - } else { - std::unique_ptr<renderengine::Image> image = mRE.createImage(); - bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(), - mCurrentTextureBuffer->getUsage() & - GRALLOC_USAGE_PROTECTED); - if (!success) { - BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 - " fmt=%d", - mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(), - mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(), - mCurrentTextureBuffer->getPixelFormat()); - BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture); - mRE.bindExternalTextureImage(mTexName, *image); - return UNKNOWN_ERROR; - } - imageToRender = image.get(); - // Cache the image here so that we can reuse it. - mImages[mCurrentTexture] = std::move(image); - } - - mRE.bindExternalTextureImage(mTexName, *imageToRender); - - // Wait for the new buffer to be ready. - return doFenceWaitLocked(); + return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false); } status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) { @@ -433,16 +393,29 @@ int BufferLayerConsumer::getCurrentApi() const { return mCurrentApi; } -sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const { +sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const { Mutex::Autolock lock(mMutex); if (outSlot != nullptr) { *outSlot = mCurrentTexture; } + if (outFence != nullptr) { + *outFence = mCurrentFence; + } + return mCurrentTextureBuffer; } +bool BufferLayerConsumer::getAndSetCurrentBufferCacheHint() { + Mutex::Autolock lock(mMutex); + bool useCache = mCurrentTextureBufferStaleForGpu; + // Set the staleness bit here, as this function is only called during a + // client composition path. + mCurrentTextureBufferStaleForGpu = true; + return useCache; +} + Rect BufferLayerConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index ea46245ea4..e2ef399599 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -150,10 +150,16 @@ public: // for use with bilinear filtering. void setFilteringEnabled(bool enabled); + // Sets mCurrentTextureBufferStaleForGpu to true to indicate that the + // buffer is now "stale" for GPU composition, and returns the old staleness + // bit as a caching hint. + bool getAndSetCurrentBufferCacheHint(); + // getCurrentBuffer returns the buffer associated with the current image. // When outSlot is not nullptr, the current buffer slot index is also - // returned. - sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const; + // returned. Simiarly, when outFence is not nullptr, the current output + // fence is returned. + sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; @@ -255,6 +261,10 @@ private: // must track it separately in order to support the getCurrentBuffer method. sp<GraphicBuffer> mCurrentTextureBuffer; + // True if the buffer was used for the previous client composition frame, + // and false otherwise. + bool mCurrentTextureBufferStaleForGpu; + // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. Rect mCurrentCrop; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 42021d118f..edfeb0bcfd 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -306,7 +306,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t status_t BufferQueueLayer::updateActiveBuffer() { // update the active buffer - mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot); + mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence); getBE().compositionInfo.mBuffer = mActiveBuffer; getBE().compositionInfo.mBufferSlot = mActiveBufferSlot; @@ -317,6 +317,10 @@ status_t BufferQueueLayer::updateActiveBuffer() { return NO_ERROR; } +bool BufferQueueLayer::useCachedBufferForClientComposition() const { + return mConsumer->getAndSetCurrentBufferCacheHint(); +} + status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mConsumer->getFrameNumber(); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index d7c3f6ab78..20992a4a0f 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -62,6 +62,9 @@ public: public: bool fenceHasSignaled() const override; +protected: + bool useCachedBufferForClientComposition() const override; + private: nsecs_t getDesiredPresentTime() override; std::shared_ptr<FenceTime> getCurrentFenceTime() const override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 044662c98d..2005d20d17 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -450,46 +450,7 @@ status_t BufferStateLayer::bindTextureImage() { const State& s(getDrawingState()); auto& engine(mFlinger->getRenderEngine()); - engine.checkErrors(); - - // TODO(marissaw): once buffers are cached, don't create a new image everytime - mTextureImage = engine.createImage(); - - bool created = - mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(), - s.buffer->getUsage() & GRALLOC_USAGE_PROTECTED); - if (!created) { - ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", - s.buffer->getWidth(), s.buffer->getHeight(), s.buffer->getStride(), - s.buffer->getUsage(), s.buffer->getPixelFormat()); - engine.bindExternalTextureImage(mTextureName, *engine.createImage()); - return NO_INIT; - } - - engine.bindExternalTextureImage(mTextureName, *mTextureImage); - - // Wait for the new buffer to be ready. - if (s.acquireFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync()) { - base::unique_fd fenceFd(s.acquireFence->dup()); - if (fenceFd == -1) { - ALOGE("error dup'ing fence fd: %d", errno); - return -errno; - } - if (!engine.waitFence(std::move(fenceFd))) { - ALOGE("failed to wait on fence fd"); - return UNKNOWN_ERROR; - } - } else { - status_t err = s.acquireFence->waitForever("BufferStateLayer::bindTextureImage"); - if (err != NO_ERROR) { - ALOGE("error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; + return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false); } status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, @@ -612,12 +573,18 @@ status_t BufferStateLayer::updateActiveBuffer() { } mActiveBuffer = s.buffer; + mActiveBufferFence = s.acquireFence; getBE().compositionInfo.mBuffer = mActiveBuffer; getBE().compositionInfo.mBufferSlot = 0; return NO_ERROR; } +bool BufferStateLayer::useCachedBufferForClientComposition() const { + // TODO: Store a proper staleness bit to support EGLImage caching. + return false; +} + status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) { // TODO(marissaw): support frame history events mCurrentFrameNumber = mFrameNumber; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 3f891d3fd6..138bb4c9ac 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -95,6 +95,9 @@ public: // ----------------------------------------------------------------------- bool fenceHasSignaled() const override; +protected: + bool useCachedBufferForClientComposition() const override; + private: nsecs_t getDesiredPresentTime() override; std::shared_ptr<FenceTime> getCurrentFenceTime() const override; diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index b4e9d17d59..d82ff0eab3 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -44,28 +44,14 @@ ColorLayer::ColorLayer(const LayerCreationArgs& args) ColorLayer::~ColorLayer() = default; -void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */, - bool useIdentityTransform) { - half4 color = getColor(); - if (color.a > 0) { - renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2); - computeGeometry(renderArea, mesh, useIdentityTransform); - auto& engine(mFlinger->getRenderEngine()); - - Rect win{computeBounds()}; - - const auto roundedCornerState = getRoundedCornerState(); - const auto cropRect = roundedCornerState.cropRect; - setupRoundedCornersCropCoordinates(win, cropRect); - - engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */, - true /* disableTexture */, color, roundedCornerState.radius); - - engine.setSourceDataSpace(mCurrentDataSpace); - engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight()); - engine.drawMesh(mesh); - engine.disableBlending(); - } +bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer) { + Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer); + half4 color(getColor()); + half3 solidColor(color.r, color.g, color.b); + layer.source.solidColor = solidColor; + return true; } bool ColorLayer::isVisible() const { diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h index 3b98e8c1ed..ed4c2d8208 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/ColorLayer.h @@ -31,8 +31,6 @@ public: std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override; virtual const char* getTypeId() const { return "ColorLayer"; } - virtual void onDraw(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform); bool isVisible() const override; bool setColor(const half3& color) override; @@ -44,6 +42,9 @@ public: protected: FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; } + virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer); private: std::shared_ptr<compositionengine::Layer> mCompositionLayer; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index a7ab472d68..84b2423def 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -97,10 +97,9 @@ public: // TODO(lpique): Make this protected once it is only internally called. virtual OutputCompositionState& editState() = 0; - // Gets the physical space dirty region. If repaintEverything is true, this - // will be the full display bounds. Internally the dirty region is stored in - // logical (aka layer stack) space. - virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0; + // Gets the dirty region in layer stack space. + // If repaintEverything is true, this will be the full display bounds. + virtual Region getDirtyRegion(bool repaintEverything) const = 0; // Tests whether a given layerStackId belongs in this output. // A layer belongs to the output if its layerStackId matches the of the output layerStackId, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index dd01b05c04..ddeb7304a8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -75,16 +75,13 @@ public: // Allocates a buffer as scratch space for GPU composition virtual sp<GraphicBuffer> dequeueBuffer() = 0; - // Queues the drawn buffer for consumption by HWC - virtual void queueBuffer() = 0; + // Queues the drawn buffer for consumption by HWC. readyFence is the fence + // which will fire when the buffer is ready for consumption. + virtual void queueBuffer(base::unique_fd&& readyFence) = 0; // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Marks the current buffer has finished, so that it can be presented and - // swapped out - virtual void finishBuffer() = 0; - // Called to set the viewport and projection state for rendering into this // surface virtual void setViewportAndProjection() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index d876c03558..3fd057c79f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -61,7 +61,7 @@ public: const OutputCompositionState& getState() const override; OutputCompositionState& editState() override; - Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override; + Region getDirtyRegion(bool repaintEverything) const override; bool belongsInOutput(uint32_t, bool) const override; compositionengine::OutputLayer* getOutputLayerForLayer( diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0489310e04..2f0fceb387 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -53,9 +53,8 @@ public: status_t beginFrame(bool mustRecompose) override; status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override; sp<GraphicBuffer> dequeueBuffer() override; - void queueBuffer() override; + void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; - void finishBuffer() override; void setViewportAndProjection() override; void flip() override; @@ -77,9 +76,6 @@ private: const sp<ANativeWindow> mNativeWindow; // Current buffer being rendered into sp<GraphicBuffer> mGraphicBuffer; - // File descriptor indicating that mGraphicBuffer is ready for display, i.e. - // that drawing to the buffer is now complete. - base::unique_fd mBufferReady; const sp<DisplaySurface> mDisplaySurface; ui::Size mSize; std::uint32_t mPageFlipCount{0}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index e79a44c282..2972ad7346 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -56,7 +56,7 @@ public: MOCK_CONST_METHOD0(getState, const OutputCompositionState&()); MOCK_METHOD0(editState, OutputCompositionState&()); - MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool)); + MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool)); MOCK_CONST_METHOD1(getOutputLayerForLayer, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index 2269e579c1..e9ff330482 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -39,9 +39,8 @@ public: MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData)); MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>()); - MOCK_METHOD0(queueBuffer, void()); + MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(finishBuffer, void()); MOCK_METHOD0(setViewportAndProjection, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6d5147db33..f6c1a33d18 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -170,13 +170,10 @@ OutputCompositionState& Output::editState() { return mState; } -Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const { - Region dirty; - if (repaintEverything) { - dirty.set(mState.bounds); - } else { - dirty = mState.transform.transform(mState.dirtyRegion); - dirty.andSelf(mState.bounds); +Region Output::getDirtyRegion(bool repaintEverything) const { + Region dirty(mState.viewport); + if (!repaintEverything) { + dirty.andSelf(mState.dirtyRegion); } return dirty; } diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index d546fc81ac..3f841d241b 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -156,7 +156,7 @@ sp<GraphicBuffer> RenderSurface::dequeueBuffer() { return mGraphicBuffer; } -void RenderSurface::queueBuffer() { +void RenderSurface::queueBuffer(base::unique_fd&& readyFence) { auto& hwc = mCompositionEngine.getHwComposer(); const auto id = mDisplay.getId(); @@ -178,9 +178,9 @@ void RenderSurface::queueBuffer() { if (mGraphicBuffer == nullptr) { ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str()); } else { - status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), - dup(mBufferReady)); + status_t result = + mNativeWindow->queueBuffer(mNativeWindow.get(), + mGraphicBuffer->getNativeBuffer(), dup(readyFence)); if (result != NO_ERROR) { ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(), result); @@ -190,12 +190,10 @@ void RenderSurface::queueBuffer() { LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result); } else { mNativeWindow->cancelBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), - dup(mBufferReady)); + mGraphicBuffer->getNativeBuffer(), dup(readyFence)); } } - mBufferReady.reset(); mGraphicBuffer = nullptr; } } @@ -217,14 +215,6 @@ void RenderSurface::setViewportAndProjection() { ui::Transform::ROT_0); } -void RenderSurface::finishBuffer() { - auto& renderEngine = mCompositionEngine.getRenderEngine(); - mBufferReady = renderEngine.flush(); - if (mBufferReady.get() < 0) { - renderEngine.finish(); - } -} - void RenderSurface::flip() { mPageFlipCount++; } @@ -263,9 +253,5 @@ sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() { return mGraphicBuffer; } -base::unique_fd& RenderSurface::mutableBufferReadyForTest() { - return mBufferReady; -} - } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index cc1211bf1a..314d98baa0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -215,52 +215,32 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { } /* ------------------------------------------------------------------------ - * Output::getPhysicalSpaceDirtyRegion() + * Output::getDirtyRegion() */ -TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) { - const Rect displaySize{100, 200}; - mOutput.editState().bounds = displaySize; +TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) { + const Rect viewport{100, 200}; + mOutput.editState().viewport = viewport; mOutput.editState().dirtyRegion.set(50, 300); { - Region result = mOutput.getPhysicalSpaceDirtyRegion(true); - - EXPECT_THAT(result, RegionEq(Region(displaySize))); - } - - // For repaint everything == true, the returned value does not depend on the display - // rotation. - mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0); - - { - Region result = mOutput.getPhysicalSpaceDirtyRegion(true); + Region result = mOutput.getDirtyRegion(true); - EXPECT_THAT(result, RegionEq(Region(displaySize))); + EXPECT_THAT(result, RegionEq(Region(viewport))); } } -TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) { - const Rect displaySize{100, 200}; - mOutput.editState().bounds = displaySize; +TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { + const Rect viewport{100, 200}; + mOutput.editState().viewport = viewport; mOutput.editState().dirtyRegion.set(50, 300); { - Region result = mOutput.getPhysicalSpaceDirtyRegion(false); + Region result = mOutput.getDirtyRegion(false); // The dirtyRegion should be clipped to the display bounds. EXPECT_THAT(result, RegionEq(Region(Rect(50, 200)))); } - - mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(), - displaySize.getHeight()); - - { - Region result = mOutput.getPhysicalSpaceDirtyRegion(false); - - // The dirtyRegion should be rotated and clipped to the display bounds. - EXPECT_THAT(result, RegionEq(Region(Rect(100, 50)))); - } } /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 13cc663c45..c56d92a067 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -373,7 +373,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { .WillOnce(Return(false)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); - mSurface.queueBuffer(); + mSurface.queueBuffer(base::unique_fd()); EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); } @@ -387,7 +387,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); - mSurface.queueBuffer(); + mSurface.queueBuffer(base::unique_fd()); EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } @@ -402,7 +402,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); - mSurface.queueBuffer(); + mSurface.queueBuffer(base::unique_fd()); EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } @@ -419,7 +419,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); - mSurface.queueBuffer(); + mSurface.queueBuffer(base::unique_fd()); EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } @@ -436,7 +436,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirt .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); - mSurface.queueBuffer(); + mSurface.queueBuffer(base::unique_fd()); EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } @@ -452,29 +452,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { } /* ------------------------------------------------------------------------ - * RenderSurface::finishBuffer() - */ - -TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) { - int fd = dup(1); - - EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd)))); - - mSurface.finishBuffer(); - - EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release()); -} - -TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) { - EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2)))); - EXPECT_CALL(mRenderEngine, finish()).Times(1); - - mSurface.finishBuffer(); - - EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release()); -} - -/* ------------------------------------------------------------------------ * RenderSurface::setViewportAndProjection() */ diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index ca49f6c7af..9530398a81 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -26,7 +26,10 @@ ContainerLayer::ContainerLayer(const LayerCreationArgs& args) : Layer(args) {} ContainerLayer::~ContainerLayer() = default; -void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {} +bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, + renderengine::LayerSettings&) { + return false; +} bool ContainerLayer::isVisible() const { return !isHiddenByPolicy(); diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h index 413844b6f5..409cf225f2 100644 --- a/services/surfaceflinger/ContainerLayer.h +++ b/services/surfaceflinger/ContainerLayer.h @@ -29,8 +29,6 @@ public: ~ContainerLayer() override; const char* getTypeId() const override { return "ContainerLayer"; } - void onDraw(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform) override; bool isVisible() const override; void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport, @@ -39,6 +37,11 @@ public: bool isCreatedFromMainThread() const override { return true; } bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; } + +protected: + bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer); }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2de169dcb1..185393e4ab 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -639,7 +639,7 @@ void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) { * Here we cancel out the orientation component of the WM transform. * The scaling and translate components are already included in our bounds * computation so it's enough to just omit it in the composition. - * See comment in onDraw with ref to b/36727915 for why. + * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why. */ transform = ui::Transform(invTransform) * tr * bufferOrientation; } @@ -707,12 +707,51 @@ void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) { // drawing... // --------------------------------------------------------------------------- -void Layer::draw(const RenderArea& renderArea, const Region& clip) { - onDraw(renderArea, clip, false); +bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, + Region& clearRegion, renderengine::LayerSettings& layer) { + return prepareClientLayer(renderArea, clip, false, clearRegion, layer); } -void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) { - onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform); +bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform, + Region& clearRegion, renderengine::LayerSettings& layer) { + return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform, + clearRegion, layer); +} + +bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/, + bool useIdentityTransform, Region& /*clearRegion*/, + renderengine::LayerSettings& layer) { + FloatRect bounds = computeBounds(); + half alpha = getAlpha(); + layer.geometry.boundaries = bounds; + if (useIdentityTransform) { + layer.geometry.positionTransform = mat4(); + } else { + const ui::Transform transform = getTransform(); + mat4 m; + m[0][0] = transform[0][0]; + m[0][1] = transform[0][1]; + m[0][3] = transform[0][2]; + m[1][0] = transform[1][0]; + m[1][1] = transform[1][1]; + m[1][3] = transform[1][2]; + m[3][0] = transform[2][0]; + m[3][1] = transform[2][1]; + m[3][3] = transform[2][2]; + layer.geometry.positionTransform = m; + } + + if (hasColorTransform()) { + layer.colorTransform = getColorTransform(); + } + + const auto roundedCornerState = getRoundedCornerState(); + layer.geometry.roundedCornersRadius = roundedCornerState.radius; + layer.geometry.roundedCornersCrop = roundedCornerState.cropRect; + + layer.alpha = alpha; + layer.sourceDataspace = mCurrentDataSpace; + return true; } void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue, diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f099df613b..4cead875d5 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -421,11 +421,9 @@ public: virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; } protected: - /* - * onDraw - draws the surface. - */ - virtual void onDraw(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform) = 0; + virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform, Region& clearRegion, + renderengine::LayerSettings& layer) = 0; public: virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {} @@ -475,11 +473,14 @@ public: virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { } /* - * draw - performs some global clipping optimizations - * and calls onDraw(). + * prepareClientLayer - populates a renderengine::LayerSettings to passed to + * RenderEngine::drawLayers. Returns true if the layer can be used, and + * false otherwise. */ - void draw(const RenderArea& renderArea, const Region& clip); - void draw(const RenderArea& renderArea, bool useIdentityTransform); + bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion, + renderengine::LayerSettings& layer); + bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform, + Region& clearRegion, renderengine::LayerSettings& layer); /* * doTransaction - process the transaction. This is a good place to figure @@ -810,7 +811,13 @@ protected: FenceTimeline mReleaseTimeline; // main thread + // Active buffer fields sp<GraphicBuffer> mActiveBuffer; + sp<Fence> mActiveBufferFence; + // False if the buffer and its contents have been previously used for GPU + // composition, true otherwise. + bool mIsActiveBufferUpdatedForGpu = true; + ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN; Rect mCurrentCrop; uint32_t mCurrentTransform{0}; @@ -866,7 +873,6 @@ private: const LayerVector::Visitor& visitor); LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet, const std::vector<Layer*>& layersInTree); - /** * Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds. * The cropped bounds must be transformed back from parent layer space to child layer space by diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d54a1d56c8..123b4e4808 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -// #define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <sys/types.h> @@ -1853,16 +1853,13 @@ void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice, if (displayState.isEnabled) { // transform the dirty region into this screen's coordinate space - const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything); + const Region dirtyRegion = display->getDirtyRegion(repaintEverything); if (!dirtyRegion.isEmpty()) { + base::unique_fd readyFence; // redraw the whole screen - doComposeSurfaces(displayDevice); + doComposeSurfaces(displayDevice, dirtyRegion, &readyFence); - // and draw the dirty region - auto& engine(getRenderEngine()); - engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1); - - display->getRenderSurface()->queueBuffer(); + display->getRenderSurface()->queueBuffer(std::move(readyFence)); } } @@ -2399,7 +2396,7 @@ void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) { auto display = displayDevice->getCompositionDisplay(); const auto& displayState = display->getState(); - bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty(); + bool dirty = !display->getDirtyRegion(false).isEmpty(); bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0; bool wasEmpty = !displayState.lastCompositionHadVisibleLayers; @@ -2450,7 +2447,7 @@ void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool if (displayState.isEnabled) { // transform the dirty region into this screen's coordinate space - const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything); + const Region dirtyRegion = display->getDirtyRegion(repaintEverything); // repaint the framebuffer (if needed) doDisplayComposition(displayDevice, dirtyRegion); @@ -3335,13 +3332,15 @@ void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice } ALOGV("doDisplayComposition"); - if (!doComposeSurfaces(displayDevice)) return; + base::unique_fd readyFence; + if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return; // swap buffers (presentation) - display->getRenderSurface()->queueBuffer(); + display->getRenderSurface()->queueBuffer(std::move(readyFence)); } -bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { +bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, + const Region& debugRegion, base::unique_fd* readyFence) { ALOGV("doComposeSurfaces"); auto display = displayDevice->getCompositionDisplay(); @@ -3356,13 +3355,14 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { mat4 colorMatrix; bool applyColorMatrix = false; - // Framebuffer will live in this scope for GPU composition. - std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo; + renderengine::DisplaySettings clientCompositionDisplay; + std::vector<renderengine::LayerSettings> clientCompositionLayers; + sp<GraphicBuffer> buf; if (hasClientComposition) { ALOGV("hasClientComposition"); - sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer(); + buf = display->getRenderSurface()->dequeueBuffer(); if (buf == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " @@ -3371,24 +3371,30 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { return false; } - // Bind the framebuffer in this scope. - fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(), - buf->getNativeBuffer()); + clientCompositionDisplay.physicalDisplay = displayState.scissor; + clientCompositionDisplay.clip = displayState.scissor; + const ui::Transform& displayTransform = displayState.transform; + mat4 m; + m[0][0] = displayTransform[0][0]; + m[0][1] = displayTransform[0][1]; + m[0][3] = displayTransform[0][2]; + m[1][0] = displayTransform[1][0]; + m[1][1] = displayTransform[1][1]; + m[1][3] = displayTransform[1][2]; + m[3][0] = displayTransform[2][0]; + m[3][1] = displayTransform[2][1]; + m[3][3] = displayTransform[2][2]; - if (fbo->getStatus() != NO_ERROR) { - ALOGW("Binding buffer for display [%s] failed with status: %d", - displayDevice->getDisplayName().c_str(), fbo->getStatus()); - return false; - } + clientCompositionDisplay.globalTransform = m; const auto* profile = display->getDisplayColorProfile(); Dataspace outputDataspace = Dataspace::UNKNOWN; if (profile->hasWideColorGamut()) { outputDataspace = displayState.dataspace; } - getRenderEngine().setOutputDataSpace(outputDataspace); - getRenderEngine().setDisplayMaxLuminance( - profile->getHdrCapabilities().getDesiredMaxLuminance()); + clientCompositionDisplay.outputDataspace = outputDataspace; + clientCompositionDisplay.maxLuminance = + profile->getHdrCapabilities().getDesiredMaxLuminance(); const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId); const bool skipClientColorTransform = @@ -3399,44 +3405,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { // Compute the global color transform matrix. applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform; if (applyColorMatrix) { - colorMatrix = mDrawingState.colorMatrix; - } - - display->getRenderSurface()->setViewportAndProjection(); - - // Never touch the framebuffer if we don't have any framebuffer layers - if (hasDeviceComposition) { - // when using overlays, we assume a fully transparent framebuffer - // NOTE: we could reduce how much we need to clear, for instance - // remove where there are opaque FB layers. however, on some - // GPUs doing a "clean slate" clear might be more efficient. - // We'll revisit later if needed. - getRenderEngine().clearWithColor(0, 0, 0, 0); - } else { - // we start with the whole screen area and remove the scissor part - // we're left with the letterbox region - // (common case is that letterbox ends-up being empty) - const Region letterbox = bounds.subtract(displayState.scissor); - - // compute the area to clear - const Region region = displayState.undefinedRegion.merge(letterbox); - - // screen is already cleared here - if (!region.isEmpty()) { - // can happen with SurfaceView - drawWormhole(region); - } - } - - const Rect& bounds = displayState.bounds; - const Rect& scissor = displayState.scissor; - if (scissor != bounds) { - // scissor doesn't match the screen's dimensions, so we - // need to clear everything outside of it and enable - // the GL scissor so we don't draw anything where we shouldn't - - // enable scissor for this frame - getRenderEngine().setScissor(scissor); + clientCompositionDisplay.colorTransform = colorMatrix; } } @@ -3445,10 +3414,11 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { */ ALOGV("Rendering client layers"); - const ui::Transform& displayTransform = displayState.transform; bool firstLayer = true; + Region clearRegion = Region::INVALID_REGION; for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region clip(bounds.intersect(displayTransform.transform(layer->visibleRegion))); + const Region viewportRegion(displayState.viewport); + const Region clip(viewportRegion.intersect(layer->visibleRegion)); ALOGV("Layer: %s", layer->getName().string()); ALOGV(" Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str()); if (!clip.isEmpty()) { @@ -3464,22 +3434,28 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared - layer->clearWithOpenGL(renderArea); + renderengine::LayerSettings layerSettings; + Region dummyRegion; + bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion, + layerSettings); + + if (prepared) { + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); + layerSettings.alpha = half(0.0); + layerSettings.disableBlending = true; + clientCompositionLayers.push_back(layerSettings); + } } break; } case HWC2::Composition::Client: { - if (layer->hasColorTransform()) { - mat4 tmpMatrix; - if (applyColorMatrix) { - tmpMatrix = mDrawingState.colorMatrix; - } - tmpMatrix *= layer->getColorTransform(); - getRenderEngine().setColorTransform(tmpMatrix); - } else { - getRenderEngine().setColorTransform(colorMatrix); + renderengine::LayerSettings layerSettings; + bool prepared = + layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings); + if (prepared) { + clientCompositionLayers.push_back(layerSettings); } - layer->draw(renderArea, clip); break; } default: @@ -3491,14 +3467,23 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) { firstLayer = false; } - // Perform some cleanup steps if we used client composition. if (hasClientComposition) { - getRenderEngine().setColorTransform(mat4()); - getRenderEngine().disableScissor(); - display->getRenderSurface()->finishBuffer(); - // Clear out error flags here so that we don't wait until next - // composition to log. - getRenderEngine().checkErrors(); + clientCompositionDisplay.clearRegion = clearRegion; + if (!debugRegion.isEmpty()) { + Region::const_iterator it = debugRegion.begin(); + Region::const_iterator end = debugRegion.end(); + while (it != end) { + const Rect& rect = *it++; + renderengine::LayerSettings layerSettings; + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(1.0, 0.0, 1.0); + layerSettings.geometry.boundaries = rect.toFloatRect(); + layerSettings.alpha = half(1.0); + clientCompositionLayers.push_back(layerSettings); + } + } + getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, + buf->getNativeBuffer(), readyFence); } return true; } @@ -5612,35 +5597,109 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - bool useIdentityTransform) { + ANativeWindowBuffer* buffer, bool useIdentityTransform, + int* outSyncFd) { ATRACE_CALL(); - auto& engine(getRenderEngine()); - const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); const auto sourceCrop = renderArea.getSourceCrop(); const auto rotation = renderArea.getRotationFlags(); - engine.setOutputDataSpace(renderArea.getReqDataSpace()); - engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance); - - // make sure to clear all GL error flags - engine.checkErrors(); - - // set-up our viewport - engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation); - engine.disableTexturing(); + renderengine::DisplaySettings clientCompositionDisplay; + std::vector<renderengine::LayerSettings> clientCompositionLayers; + + // assume that bounds are never offset, and that they are the same as the + // buffer bounds. + clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight); + ui::Transform transform = renderArea.getTransform(); + mat4 m; + m[0][0] = transform[0][0]; + m[0][1] = transform[0][1]; + m[0][3] = transform[0][2]; + m[1][0] = transform[1][0]; + m[1][1] = transform[1][1]; + m[1][3] = transform[1][2]; + m[3][0] = transform[2][0]; + m[3][1] = transform[2][1]; + m[3][3] = transform[2][2]; + + clientCompositionDisplay.globalTransform = m; + mat4 rotMatrix; + // Displacement for repositioning the clipping rectangle after rotating it + // with the rotation hint. + int displacementX = 0; + int displacementY = 0; + float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; + switch (rotation) { + case ui::Transform::ROT_90: + rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); + displacementX = reqWidth; + break; + case ui::Transform::ROT_180: + rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); + displacementX = reqWidth; + displacementY = reqHeight; + break; + case ui::Transform::ROT_270: + rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); + displacementY = reqHeight; + break; + default: + break; + } + // We need to transform the clipping window into the right spot. + // First, rotate the clipping rectangle by the rotation hint to get the + // right orientation + const vec4 clipTL = vec4(sourceCrop.left, sourceCrop.top, 0, 1); + const vec4 clipBR = vec4(sourceCrop.right, sourceCrop.bottom, 0, 1); + const vec4 rotClipTL = rotMatrix * clipTL; + const vec4 rotClipBR = rotMatrix * clipBR; + const int newClipLeft = std::min(rotClipTL[0], rotClipBR[0]); + const int newClipTop = std::min(rotClipTL[1], rotClipBR[1]); + const int newClipRight = std::max(rotClipTL[0], rotClipBR[0]); + const int newClipBottom = std::max(rotClipTL[1], rotClipBR[1]); + + // Now reposition the clipping rectangle with the displacement vector + // computed above. + const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1)); + + clientCompositionDisplay.clip = + Rect(newClipLeft + displacementX, newClipTop + displacementY, + newClipRight + displacementX, newClipBottom + displacementY); + + // We need to perform the same transformation in layer space, so propagate + // it to the global transform. + mat4 clipTransform = displacementMat * rotMatrix; + clientCompositionDisplay.globalTransform *= clipTransform; + clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); + clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill()); - // redraw the screen entirely... - engine.clearWithColor(0, 0, 0, alpha); + renderengine::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); + fillLayer.alpha = half(alpha); + clientCompositionLayers.push_back(fillLayer); + + Region clearRegion = Region::INVALID_REGION; traverseLayers([&](Layer* layer) { - engine.setColorTransform(layer->getColorTransform()); - layer->draw(renderArea, useIdentityTransform); - engine.setColorTransform(mat4()); + renderengine::LayerSettings layerSettings; + bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion, + layerSettings); + if (prepared) { + clientCompositionLayers.push_back(layerSettings); + } }); + + clientCompositionDisplay.clearRegion = clearRegion; + base::unique_fd drawFence; + getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer, + &drawFence); + + *outSyncFd = drawFence.release(); } status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, @@ -5664,28 +5723,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, ALOGW("FB is protected: PERMISSION_DENIED"); return PERMISSION_DENIED; } - auto& engine(getRenderEngine()); - - // this binds the given EGLImage as a framebuffer for the - // duration of this scope. - renderengine::BindNativeBufferAsFramebuffer bufferBond(engine, buffer); - if (bufferBond.getStatus() != NO_ERROR) { - ALOGE("got ANWB binding error while taking screenshot"); - return INVALID_OPERATION; - } - - // this will in fact render into our dequeued buffer - // via an FBO, which means we didn't have to create - // an EGLSurface and therefore we're not - // dependent on the context's EGLConfig. - renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform); - - base::unique_fd syncFd = engine.flush(); - if (syncFd < 0) { - engine.finish(); - } - *outSyncFd = syncFd.release(); - + renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a127550c93..6dc1a6ca7b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -597,7 +597,8 @@ private: void startBootAnim(); void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - bool useIdentityTransform); + ANativeWindowBuffer* buffer, bool useIdentityTransform, + int* outSyncFd); status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat, bool useIdentityTransform); @@ -736,8 +737,11 @@ private: void logLayerStats(); void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion); - // This fails if using GL and the surface has been destroyed. - bool doComposeSurfaces(const sp<DisplayDevice>& display); + // This fails if using GL and the surface has been destroyed. readyFence + // will be populated if using GL and native fence sync is supported, to + // signal when drawing has completed. + bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm, + base::unique_fd* readyFence); void postFramebuffer(const sp<DisplayDevice>& display); void postFrame(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index e092aed471..ee79c18cf4 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -45,8 +45,10 @@ namespace { using testing::_; using testing::AtLeast; +using testing::Between; using testing::ByMove; using testing::DoAll; +using testing::Field; using testing::Invoke; using testing::IsNull; using testing::Mock; @@ -159,7 +161,6 @@ public: renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::DispSync* mPrimaryDispSync = new mock::DispSync(); - renderengine::mock::Image* mReImage = new renderengine::mock::Image(); renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer(); sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE; @@ -279,11 +280,10 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1); EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); - EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return()); - EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true)); - + // TODO: remove once we verify that we can just grab the fence from the + // FramebufferSurface. EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(0); + return base::unique_fd(); })); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); @@ -295,36 +295,18 @@ struct BaseDisplayVariant { template <typename Case> static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { - // Called once with a non-null value to set a framebuffer, and then - // again with nullptr to clear it. - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false)) - .WillOnce(Return(true)); - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false)) - .WillOnce(Return(true)); - - EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return()); - EXPECT_CALL(*test->mRenderEngine, createFramebuffer()) - .WillOnce(Return( - ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer)))); - EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1); - EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1); - EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1); - EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd()))); - EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true)); - - EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1); - EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE)) - .Times(1); - // This expectation retires on saturation as setViewportAndProjection is - // called an extra time for the code path this setup is for. - // TODO: Investigate this extra call - EXPECT_CALL(*test->mRenderEngine, - setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, - Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - ui::Transform::ROT_0)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1); + EXPECT_CALL(*test->mRenderEngine, drawLayers) + .WillRepeatedly( + [](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& /*layerSettings*/, + ANativeWindowBuffer*, base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + return NO_ERROR; + }); } static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) { @@ -348,31 +330,23 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence()) .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence)); - EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1); - EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE)) - .Times(1); - EXPECT_CALL(*test->mRenderEngine, setColorTransform(_)).Times(2); - // These expectations retire on saturation as the code path these - // expectations are for appears to make an extra call to them. - // TODO: Investigate this extra call - EXPECT_CALL(*test->mRenderEngine, - setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, - Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - ui::Transform::ROT_0)) - .Times(1); - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false)) - .WillOnce(Return(true)); - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false)) - .WillOnce(Return(true)); - EXPECT_CALL(*test->mRenderEngine, createFramebuffer()) - .WillOnce(Return( - ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer)))); - EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1); - EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1); EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0)); EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _)) .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1), Return(0))); + EXPECT_CALL(*test->mRenderEngine, drawLayers) + .WillRepeatedly( + [](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& /*layerSettings*/, + ANativeWindowBuffer*, base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); + return NO_ERROR; + }); } template <typename Case> @@ -383,8 +357,6 @@ struct BaseDisplayVariant { template <typename Case> static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) { Case::Layer::setupREScreenshotCompositionCallExpectations(test); - - EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true)); } }; @@ -396,16 +368,11 @@ struct InsecureDisplaySetupVariant : public BaseDisplayVariant<InsecureDisplaySe template <typename Case> static void setupRELayerCompositionCallExpectations(CompositionTest* test) { Case::Layer::setupInsecureRECompositionCallExpectations(test); - - // TODO: Investigate this extra call - EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1); } template <typename Case> static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) { Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test); - - EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true)); } }; @@ -516,7 +483,6 @@ struct BaseLayerProperties { bool ignoredRecomputeVisibleRegions; layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE); Mock::VerifyAndClear(test->mRenderEngine); - Mock::VerifyAndClear(test->mReImage); } static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { @@ -598,33 +564,35 @@ struct BaseLayerProperties { } static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { - EXPECT_CALL(*test->mRenderEngine, - setupLayerBlending(true, false, false, - half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], - LayerProperties::COLOR[2], LayerProperties::COLOR[3]), - 0.0f)) - .Times(1); - - EXPECT_CALL(*test->mRenderEngine, createImage()) - .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage)))); - EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1); - EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1); - EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1); - EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1); - EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1); - EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1); - // This call retires on saturation as the code that renders a texture disables the state, - // along with a top-level disable to ensure it is disabled for non-buffer layers. - EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation(); + EXPECT_CALL(*test->mRenderEngine, drawLayers) + .WillOnce([](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layerSettings, + ANativeWindowBuffer*, base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + // screen capture adds an additional color layer as an alpha + // prefill, so gtet the back layer. + renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); + EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); + EXPECT_EQ(renderengine::Buffer::CachingHint::NO_CACHE, + layer.source.buffer.cacheHint); + 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; + }); } static void setupREBufferCompositionCallExpectations(CompositionTest* test) { LayerProperties::setupREBufferCompositionCommonCallExpectations(test); - - // TODO - Investigate and eliminate these differences between display - // composition and screenshot composition. - EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1); } static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) { @@ -639,20 +607,28 @@ struct BaseLayerProperties { LayerProperties::setupREBufferCompositionCommonCallExpectations(test); } - static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) { - EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1); - } - static void setupREColorCompositionCallExpectations(CompositionTest* test) { - EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1); - EXPECT_CALL(*test->mRenderEngine, - setupLayerBlending(true, false, true, - half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], - LayerProperties::COLOR[2], LayerProperties::COLOR[3]), - 0.0f)) - .Times(1); - EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1); - EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1); + EXPECT_CALL(*test->mRenderEngine, drawLayers) + .WillOnce([](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layerSettings, + ANativeWindowBuffer*, base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + // screen capture adds an additional color layer as an alpha + // prefill, so get the back layer. + 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); + return NO_ERROR; + }); } static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) { @@ -692,10 +668,7 @@ struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerPropert EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1); } - static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { - EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1); - EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1); - } + static void setupREBufferCompositionCommonCallExpectations(CompositionTest* /*test*/) {} }; struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> { @@ -704,25 +677,25 @@ struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure; static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) { - EXPECT_CALL(*test->mRenderEngine, createImage()) - .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage)))); - EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1); - EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1); - - EXPECT_CALL(*test->mRenderEngine, - setupLayerBlending(true, false, false, - half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2], - Base::COLOR[3]), - 0.0f)) - .Times(1); - EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1); - EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1); - EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1); - EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1); - // This call retires on saturation as the code that renders a texture disables the state, - // along with a top-level disable to ensure it is disabled for non-buffer layers. - EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation(); + EXPECT_CALL(*test->mRenderEngine, drawLayers) + .WillOnce([](const renderengine::DisplaySettings& displaySettings, + const std::vector<renderengine::LayerSettings>& layerSettings, + ANativeWindowBuffer*, base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + // screen capture adds an additional color layer as an alpha + // prefill, so get the back layer. + 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; + }); } static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) { @@ -826,7 +799,6 @@ struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> { } static void setupRECompositionCallExpectations(CompositionTest* test) { - LayerProperties::setupREColorCompositionCommonCallExpectations(test); LayerProperties::setupREColorCompositionCallExpectations(test); } |