Revert "Use renderengine::drawLayers api everywhere."
This reverts commit 0f7148365cfa405e8ed802b33c0e2a7b790fcf42.
Reason for revert: b/123878751, preparing while i investigate
Bug: 123878751
Test: bug no longer repros
Change-Id: I6c77427f0c113f96b68aec479ccec52b0bbb2c6b
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index c137394..c5a9942 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -449,7 +449,6 @@
}
base::unique_fd GLESRenderEngine::flush() {
- ATRACE_CALL();
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
return base::unique_fd();
}
@@ -480,7 +479,6 @@
}
bool GLESRenderEngine::finish() {
- ATRACE_CALL();
if (!GLExtensions::getInstance().hasFenceSync()) {
ALOGW("no synchronization support");
return false;
@@ -596,7 +594,6 @@
}
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;
@@ -611,15 +608,8 @@
}
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());
@@ -665,7 +655,7 @@
}
// We don't always want to persist to the cache, e.g. on older devices we
- // might bind for synchronization purposes, but that might leak if we never
+ // might bind for synchronization purpoeses, 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) {
@@ -713,7 +703,6 @@
}
status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
- ATRACE_CALL();
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
EGLImageKHR eglImage = glFramebuffer->getEGLImage();
uint32_t textureName = glFramebuffer->getTextureName();
@@ -781,7 +770,6 @@
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;
@@ -798,13 +786,6 @@
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);
@@ -813,7 +794,6 @@
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);
}
@@ -833,11 +813,9 @@
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;
@@ -847,19 +825,17 @@
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.setMatrix(layer.source.buffer.textureTransform.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, 0.0);
- texCoords[1] = vec2(0.0, 1.0);
- texCoords[2] = vec2(1.0, 1.0);
- texCoords[3] = vec2(1.0, 0.0);
+ 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);
setupLayerTexturing(texture);
}
@@ -867,11 +843,8 @@
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) {
- glDisable(GL_BLEND);
- }
+ setupLayerBlending(usePremultipliedAlpha, layer.source.buffer.isOpaque, disableTexture,
+ color, layer.geometry.roundedCornersRadius);
setSourceDataSpace(layer.sourceDataspace);
drawMesh(mesh);
@@ -930,7 +903,6 @@
}
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 34187f1..e094860 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,8 +71,6 @@
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;
@@ -186,9 +184,6 @@
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 0e3b405..4a519bb 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
#include "GLFramebuffer.h"
#include <GLES/gl.h>
@@ -23,7 +21,6 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <nativebase/nativebase.h>
-#include <utils/Trace.h>
#include "GLESRenderEngine.h"
namespace android {
@@ -43,7 +40,6 @@
}
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 77e648e..587cb31 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -14,14 +14,11 @@
* 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"
@@ -53,7 +50,6 @@
}
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 aa45ed8..56ac714 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -126,9 +126,6 @@
// 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 bc1a4da..20dd996 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -108,8 +108,6 @@
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 4b86cfe..b4c7c96 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -52,7 +52,6 @@
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 0ee6153..bef25a8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -194,7 +194,7 @@
void clearLeftRegion();
- void clearRegion();
+ void fillBufferThenClearRegion();
// 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
@@ -685,13 +685,14 @@
invokeDraw(settings, layers, mBuffer);
}
-void RenderEngineTest::clearRegion() {
+void RenderEngineTest::fillBufferThenClearRegion() {
+ fillGreenBuffer<ColorSourceVariant>();
// 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, 0, 0, 0);
+ 0, 255, 0, 255);
}
TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
@@ -854,8 +855,8 @@
fillBufferWithoutPremultiplyAlpha();
}
-TEST_F(RenderEngineTest, drawLayers_clearRegion) {
- clearRegion();
+TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) {
+ fillBufferThenClearRegion();
}
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f986329..65308a6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -57,6 +57,8 @@
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;
@@ -127,11 +129,13 @@
return inverse(tr);
}
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer) {
+/*
+ * onDraw will draw the current layer onto the presentable buffer
+ */
+void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) {
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
@@ -149,27 +153,30 @@
finished = true;
return;
}
- under.orSelf(layer->visibleRegion);
+ under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
});
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
if (!holes.isEmpty()) {
- clearRegion.orSelf(holes);
+ clearWithOpenGL(renderArea, 0, 0, 0, 1);
}
- return false;
+ 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.
+ }
+
bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
- const State& s(getDrawingState());
+
+ auto& engine(mFlinger->getRenderEngine());
+
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();
@@ -206,31 +213,17 @@
memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
}
- const Rect win{computeBounds()};
- const float bufferWidth = getBufferSize(s).getWidth();
- const float bufferHeight = getBufferSize(s).getHeight();
+ // Set things up for texturing.
+ mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+ mTexture.setFiltering(useFiltering);
+ mTexture.setMatrix(textureMatrix);
- 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;
-
- // 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;
+ engine.setupLayerTexturing(mTexture);
} else {
- // 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;
+ engine.setupLayerBlackedOut();
}
-
- return true;
+ drawWithOpenGL(renderArea, useIdentityTransform);
+ engine.disableTexturing();
}
bool BufferLayer::isHdrY410() const {
@@ -613,6 +606,67 @@
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 d0c1b13..8158d6c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -22,7 +22,6 @@
#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
@@ -78,6 +77,10 @@
// 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,
@@ -165,19 +168,13 @@
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};
@@ -185,6 +182,9 @@
// 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 7ed8184..6826050 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -272,7 +272,6 @@
// Update the BufferLayerConsumer state.
mCurrentTexture = slot;
mCurrentTextureBuffer = nextTextureBuffer;
- mCurrentTextureBufferStaleForGpu = false;
mCurrentTextureImageFreed = nullptr;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
@@ -295,7 +294,48 @@
status_t BufferLayerConsumer::bindTextureImageLocked() {
ATRACE_CALL();
- return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
+ 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();
}
status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
@@ -393,29 +433,16 @@
return mCurrentApi;
}
-sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const {
+sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) 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 e2ef399..ea46245 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -150,16 +150,10 @@
// 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. Simiarly, when outFence is not nullptr, the current output
- // fence is returned.
- sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
+ // returned.
+ sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
// getCurrentCrop returns the cropping rectangle of the current buffer.
Rect getCurrentCrop() const;
@@ -261,10 +255,6 @@
// 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 edfeb0b..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -306,7 +306,7 @@
status_t BufferQueueLayer::updateActiveBuffer() {
// update the active buffer
- mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
+ mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
getBE().compositionInfo.mBuffer = mActiveBuffer;
getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
@@ -317,10 +317,6 @@
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 20992a4..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,9 +62,6 @@
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 2005d20..044662c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -450,7 +450,46 @@
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
- return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
+ 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;
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -573,18 +612,12 @@
}
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 138bb4c..3f891d3 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -95,9 +95,6 @@
// -----------------------------------------------------------------------
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 d82ff0e..b4e9d17 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -44,14 +44,28 @@
ColorLayer::~ColorLayer() = default;
-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;
+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::isVisible() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index ed4c2d8..3b98e8c 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -31,6 +31,8 @@
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;
@@ -42,9 +44,6 @@
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 84b2423..a7ab472 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -97,9 +97,10 @@
// TODO(lpique): Make this protected once it is only internally called.
virtual OutputCompositionState& editState() = 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;
+ // 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;
// 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 ddeb730..dd01b05 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -75,13 +75,16 @@
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer() = 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;
+ // Queues the drawn buffer for consumption by HWC
+ virtual void queueBuffer() = 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 3fd057c..d876c03 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -61,7 +61,7 @@
const OutputCompositionState& getState() const override;
OutputCompositionState& editState() override;
- Region getDirtyRegion(bool repaintEverything) const override;
+ Region getPhysicalSpaceDirtyRegion(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 2f0fceb..0489310 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -53,8 +53,9 @@
status_t beginFrame(bool mustRecompose) override;
status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
sp<GraphicBuffer> dequeueBuffer() override;
- void queueBuffer(base::unique_fd&& readyFence) override;
+ void queueBuffer() override;
void onPresentDisplayCompleted() override;
+ void finishBuffer() override;
void setViewportAndProjection() override;
void flip() override;
@@ -76,6 +77,9 @@
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 2972ad7..e79a44c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -56,7 +56,7 @@
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
+ MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, 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 e9ff330..2269e57 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -39,8 +39,9 @@
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
- MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
+ MOCK_METHOD0(queueBuffer, void());
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 f6c1a33..6d5147d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -170,10 +170,13 @@
return mState;
}
-Region Output::getDirtyRegion(bool repaintEverything) const {
- Region dirty(mState.viewport);
- if (!repaintEverything) {
- dirty.andSelf(mState.dirtyRegion);
+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);
}
return dirty;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3f841d2..d546fc8 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -156,7 +156,7 @@
return mGraphicBuffer;
}
-void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
+void RenderSurface::queueBuffer() {
auto& hwc = mCompositionEngine.getHwComposer();
const auto id = mDisplay.getId();
@@ -178,9 +178,9 @@
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(readyFence));
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
if (result != NO_ERROR) {
ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
result);
@@ -190,10 +190,12 @@
LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
} else {
mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(), dup(readyFence));
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
}
}
+ mBufferReady.reset();
mGraphicBuffer = nullptr;
}
}
@@ -215,6 +217,14 @@
ui::Transform::ROT_0);
}
+void RenderSurface::finishBuffer() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ mBufferReady = renderEngine.flush();
+ if (mBufferReady.get() < 0) {
+ renderEngine.finish();
+ }
+}
+
void RenderSurface::flip() {
mPageFlipCount++;
}
@@ -253,5 +263,9 @@
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 314d98b..cc1211b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -215,32 +215,52 @@
}
/* ------------------------------------------------------------------------
- * Output::getDirtyRegion()
+ * Output::getPhysicalSpaceDirtyRegion()
*/
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
- const Rect viewport{100, 200};
- mOutput.editState().viewport = viewport;
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
mOutput.editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getDirtyRegion(true);
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
- EXPECT_THAT(result, RegionEq(Region(viewport)));
+ 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);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
}
}
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
- const Rect viewport{100, 200};
- mOutput.editState().viewport = viewport;
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
mOutput.editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getDirtyRegion(false);
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(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 c56d92a..13cc663 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -373,7 +373,7 @@
.WillOnce(Return(false));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer();
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
@@ -387,7 +387,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer();
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -402,7 +402,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer();
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -419,7 +419,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer();
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -436,7 +436,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer();
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -452,6 +452,29 @@
}
/* ------------------------------------------------------------------------
+ * 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 9530398..ca49f6c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,10 +26,7 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
- renderengine::LayerSettings&) {
- return false;
-}
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {}
bool ContainerLayer::isVisible() const {
return !isHiddenByPolicy();
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 409cf22..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -29,6 +29,8 @@
~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,
@@ -37,11 +39,6 @@
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 185393e..2de169d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -639,7 +639,7 @@
* 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 BufferLayer::prepareClientLayer with ref to b/36727915 for why.
+ * See comment in onDraw with ref to b/36727915 for why.
*/
transform = ui::Transform(invTransform) * tr * bufferOrientation;
}
@@ -707,51 +707,12 @@
// drawing...
// ---------------------------------------------------------------------------
-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, const Region& clip) {
+ onDraw(renderArea, clip, false);
}
-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::draw(const RenderArea& renderArea, bool useIdentityTransform) {
+ onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
}
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 4cead87..f099df6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -421,9 +421,11 @@
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer) = 0;
+ /*
+ * onDraw - draws the surface.
+ */
+ virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) = 0;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
@@ -473,14 +475,11 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * prepareClientLayer - populates a renderengine::LayerSettings to passed to
- * RenderEngine::drawLayers. Returns true if the layer can be used, and
- * false otherwise.
+ * draw - performs some global clipping optimizations
+ * and calls onDraw().
*/
- 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);
+ void draw(const RenderArea& renderArea, const Region& clip);
+ void draw(const RenderArea& renderArea, bool useIdentityTransform);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -811,13 +810,7 @@
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};
@@ -873,6 +866,7 @@
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 cf2b80c..96496f0 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>
@@ -1873,13 +1873,16 @@
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
- base::unique_fd readyFence;
// redraw the whole screen
- doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+ doComposeSurfaces(displayDevice);
- display->getRenderSurface()->queueBuffer(std::move(readyFence));
+ // and draw the dirty region
+ auto& engine(getRenderEngine());
+ engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
+
+ display->getRenderSurface()->queueBuffer();
}
}
@@ -2414,7 +2417,7 @@
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
- bool dirty = !display->getDirtyRegion(false).isEmpty();
+ bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
@@ -2465,7 +2468,7 @@
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
doDisplayComposition(displayDevice, dirtyRegion);
@@ -3350,15 +3353,13 @@
}
ALOGV("doDisplayComposition");
- base::unique_fd readyFence;
- if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
- display->getRenderSurface()->queueBuffer(std::move(readyFence));
+ display->getRenderSurface()->queueBuffer();
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
- const Region& debugRegion, base::unique_fd* readyFence) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
ALOGV("doComposeSurfaces");
auto display = displayDevice->getCompositionDisplay();
@@ -3373,14 +3374,13 @@
mat4 colorMatrix;
bool applyColorMatrix = false;
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
- sp<GraphicBuffer> buf;
+ // Framebuffer will live in this scope for GPU composition.
+ std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
if (hasClientComposition) {
ALOGV("hasClientComposition");
- buf = display->getRenderSurface()->dequeueBuffer();
+ sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
@@ -3389,30 +3389,24 @@
return false;
}
- 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];
+ // Bind the framebuffer in this scope.
+ fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
+ buf->getNativeBuffer());
- clientCompositionDisplay.globalTransform = m;
+ if (fbo->getStatus() != NO_ERROR) {
+ ALOGW("Binding buffer for display [%s] failed with status: %d",
+ displayDevice->getDisplayName().c_str(), fbo->getStatus());
+ return false;
+ }
const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
if (profile->hasWideColorGamut()) {
outputDataspace = displayState.dataspace;
}
- clientCompositionDisplay.outputDataspace = outputDataspace;
- clientCompositionDisplay.maxLuminance =
- profile->getHdrCapabilities().getDesiredMaxLuminance();
+ getRenderEngine().setOutputDataSpace(outputDataspace);
+ getRenderEngine().setDisplayMaxLuminance(
+ profile->getHdrCapabilities().getDesiredMaxLuminance());
const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
const bool skipClientColorTransform =
@@ -3423,7 +3417,44 @@
// Compute the global color transform matrix.
applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
if (applyColorMatrix) {
- clientCompositionDisplay.colorTransform = colorMatrix;
+ 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);
}
}
@@ -3432,11 +3463,10 @@
*/
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 viewportRegion(displayState.viewport);
- const Region clip(viewportRegion.intersect(layer->visibleRegion));
+ const Region clip(bounds.intersect(displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
ALOGV(" Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
if (!clip.isEmpty()) {
@@ -3452,28 +3482,22 @@
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- 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);
- }
+ layer->clearWithOpenGL(renderArea);
}
break;
}
case HWC2::Composition::Client: {
- renderengine::LayerSettings layerSettings;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ if (layer->hasColorTransform()) {
+ mat4 tmpMatrix;
+ if (applyColorMatrix) {
+ tmpMatrix = mDrawingState.colorMatrix;
+ }
+ tmpMatrix *= layer->getColorTransform();
+ getRenderEngine().setColorTransform(tmpMatrix);
+ } else {
+ getRenderEngine().setColorTransform(colorMatrix);
}
+ layer->draw(renderArea, clip);
break;
}
default:
@@ -3485,23 +3509,14 @@
firstLayer = false;
}
+ // Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
- 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);
+ 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();
}
return true;
}
@@ -5631,109 +5646,35 @@
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
- int* outSyncFd) {
+ bool useIdentityTransform) {
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();
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ engine.setOutputDataSpace(renderArea.getReqDataSpace());
+ engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
- // 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];
+ // make sure to clear all GL error flags
+ engine.checkErrors();
- 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;
+ // set-up our viewport
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
+ engine.disableTexturing();
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) {
- renderengine::LayerSettings layerSettings;
- bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
- }
+ engine.setColorTransform(layer->getColorTransform());
+ layer->draw(renderArea, useIdentityTransform);
+ engine.setColorTransform(mat4());
});
-
- clientCompositionDisplay.clearRegion = clearRegion;
- base::unique_fd drawFence;
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
- &drawFence);
-
- *outSyncFd = drawFence.release();
}
status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
@@ -5757,7 +5698,28 @@
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
- renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd);
+ 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();
+
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9aaf6de..d108ad1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -600,8 +600,7 @@
void startBootAnim();
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
- int* outSyncFd);
+ bool useIdentityTransform);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
@@ -740,11 +739,8 @@
void logLayerStats();
void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
- // 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);
+ // This fails if using GL and the surface has been destroyed.
+ bool doComposeSurfaces(const sp<DisplayDevice>& display);
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 1c4a661..ab9aadc 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -45,10 +45,8 @@
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;
@@ -160,6 +158,7 @@
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;
@@ -271,10 +270,11 @@
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
- // TODO: remove once we verify that we can just grab the fence from the
- // FramebufferSurface.
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+
EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
- return base::unique_fd();
+ return base::unique_fd(0);
}));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
@@ -286,18 +286,36 @@
template <typename Case>
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
- 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;
- });
+ // 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);
}
static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
@@ -321,23 +339,31 @@
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>
@@ -348,6 +374,8 @@
template <typename Case>
static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
Case::Layer::setupREScreenshotCompositionCallExpectations(test);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
}
};
@@ -359,11 +387,16 @@
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));
}
};
@@ -470,6 +503,7 @@
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) {
@@ -552,35 +586,33 @@
}
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
- 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;
- });
+ 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();
}
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) {
@@ -595,28 +627,20 @@
LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
}
+ static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
- 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;
- });
+ 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);
}
static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
@@ -656,7 +680,10 @@
EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
}
- static void setupREBufferCompositionCommonCallExpectations(CompositionTest* /*test*/) {}
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ }
};
struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
@@ -665,25 +692,25 @@
static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
- 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;
- });
+ 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();
}
static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
@@ -787,6 +814,7 @@
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREColorCompositionCommonCallExpectations(test);
LayerProperties::setupREColorCompositionCallExpectations(test);
}