Use renderengine::drawLayers api everywhere.
There's some dead code left after this change, which I'll circle around
to removing in the future.
Bug: 118461793
Bug: 123496360
Change-Id: Ic631b0c452f67b353adaa63896e8cd080e391647
Test: librenderengine_test
Test: SurfaceFlinger_test
Test: libsurfaceflinger_unittest
Test: notch hide
Test: screen rotations
Test: photos
Test: adb screencap
Test: adb screenrecord
Test: simulate virtual displays (incl. secure overlays)
Test: go/wm-smoke with gpu composition forced
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index c5a9942..c137394 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -449,6 +449,7 @@
}
base::unique_fd GLESRenderEngine::flush() {
+ ATRACE_CALL();
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
return base::unique_fd();
}
@@ -479,6 +480,7 @@
}
bool GLESRenderEngine::finish() {
+ ATRACE_CALL();
if (!GLExtensions::getInstance().hasFenceSync()) {
ALOGW("no synchronization support");
return false;
@@ -594,6 +596,7 @@
}
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 +611,15 @@
}
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 +665,7 @@
}
// 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 +713,7 @@
}
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 +781,7 @@
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 +798,13 @@
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 +813,7 @@
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 +833,11 @@
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 +847,19 @@
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 +867,11 @@
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 +930,7 @@
}
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 e094860..34187f1 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,6 +71,8 @@
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 @@
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 4a519bb..0e3b405 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 @@
}
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 587cb31..77e648e 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 @@
}
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 56ac714..aa45ed8 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -126,6 +126,9 @@
// 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 20dd996..bc1a4da 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -108,6 +108,8 @@
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 b4c7c96..4b86cfe 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -52,6 +52,7 @@
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 bef25a8..0ee6153 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -194,7 +194,7 @@
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
@@ -685,14 +685,13 @@
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) {
@@ -855,8 +854,8 @@
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 4eafeac..9662fcd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -55,8 +55,6 @@
: Layer(args), mTextureName(args.flinger->getNewTexture()) {
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,13 +125,11 @@
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
@@ -151,30 +147,27 @@
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;
+ return false;
}
-
- // 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());
-
- 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();
@@ -211,17 +204,31 @@
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();
- engine.setupLayerTexturing(mTexture);
+ 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;
} 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 {
@@ -604,67 +611,6 @@
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 e3b7f2f..3fe8ed0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -28,6 +28,7 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <renderengine/Image.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <ui/FrameStats.h>
@@ -78,10 +79,6 @@
// 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,
@@ -169,13 +166,19 @@
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};
@@ -183,9 +186,6 @@
// 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;
};
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6826050..7ed8184 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -272,6 +272,7 @@
// 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::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 @@
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 ea46245..e2ef399 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -150,10 +150,16 @@
// 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 @@
// 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 42021d1..edfeb0b 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);
+ mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
getBE().compositionInfo.mBuffer = mActiveBuffer;
getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
@@ -317,6 +317,10 @@
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 d7c3f6a..20992a4 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,6 +62,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/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2132f59..ab9b850 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -449,46 +449,7 @@
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,
@@ -611,12 +572,18 @@
}
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 3f891d3..138bb4c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -95,6 +95,9 @@
// -----------------------------------------------------------------------
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 f27f6aa..34082c3 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -38,28 +38,14 @@
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 d1b1697..f43fc3c 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -29,8 +29,6 @@
~ColorLayer() override;
virtual const char* getTypeId() const { return "ColorLayer"; }
- virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform);
bool isVisible() const override;
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
@@ -40,6 +38,9 @@
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);
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 69b5728..6be4ad8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -89,10 +89,9 @@
// 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 dd01b05..ddeb730 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -75,16 +75,13 @@
// 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 180c40b..4be0706 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -57,7 +57,7 @@
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;
// Testing
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 0489310..2f0fceb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -53,9 +53,8 @@
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 @@
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 445f0bb..e767ad3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -53,7 +53,7 @@
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));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 2269e57..e9ff330 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -39,9 +39,8 @@
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 7fb67bd..c4d563f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -164,13 +164,10 @@
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 d546fc8..3f841d2 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -156,7 +156,7 @@
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 @@
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 @@
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 @@
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 @@
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 fe12825..0df1dab 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -212,52 +212,32 @@
}
/* ------------------------------------------------------------------------
- * 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);
+ Region result = mOutput.getDirtyRegion(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);
-
- 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 13cc663..c56d92a 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();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
@@ -387,7 +387,7 @@
.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 @@
.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 @@
.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 @@
.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 @@
}
/* ------------------------------------------------------------------------
- * 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 ca49f6c..9530398 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,7 +26,10 @@
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 413844b..409cf22 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -29,8 +29,6 @@
~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 @@
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 f181220..1884cfe 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 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 @@
// 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 d30961a..b9dc8d5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -413,11 +413,9 @@
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*/) {}
@@ -466,13 +464,15 @@
// If a buffer was replaced this frame, release the former buffer
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
@@ -803,7 +803,13 @@
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};
@@ -857,7 +863,6 @@
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 acf0013..706e59a 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>
@@ -1837,16 +1837,13 @@
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));
}
}
@@ -2365,7 +2362,7 @@
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;
@@ -2416,7 +2413,7 @@
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);
@@ -3286,13 +3283,15 @@
}
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();
@@ -3307,13 +3306,14 @@
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 "
@@ -3322,24 +3322,30 @@
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 =
@@ -3350,44 +3356,7 @@
// 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;
}
}
@@ -3396,11 +3365,11 @@
*/
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()) {
@@ -3416,22 +3385,28 @@
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:
@@ -3443,14 +3418,23 @@
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;
}
@@ -5585,35 +5569,109 @@
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);
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
- // make sure to clear all GL error flags
- engine.checkErrors();
+ // 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];
- // set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
- engine.disableTexturing();
+ 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,
@@ -5637,28 +5695,7 @@
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 4d84144..6d57677 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -597,7 +597,8 @@
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);
@@ -732,8 +733,11 @@
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 e972785..1c4a661 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -45,8 +45,10 @@
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;
@@ -158,7 +160,6 @@
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;
@@ -270,11 +271,10 @@
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);
@@ -286,36 +286,18 @@
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) {
@@ -339,31 +321,23 @@
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>
@@ -374,8 +348,6 @@
template <typename Case>
static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
Case::Layer::setupREScreenshotCompositionCallExpectations(test);
-
- EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
}
};
@@ -387,16 +359,11 @@
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));
}
};
@@ -503,7 +470,6 @@
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) {
@@ -586,33 +552,35 @@
}
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) {
@@ -627,20 +595,28 @@
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) {
@@ -680,10 +656,7 @@
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> {
@@ -692,24 +665,25 @@
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) {
@@ -813,7 +787,6 @@
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- LayerProperties::setupREColorCompositionCommonCallExpectations(test);
LayerProperties::setupREColorCompositionCallExpectations(test);
}