Rounded corners
Test: visual
Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test
Fixes: 111514493
Change-Id: Ie8f400bbcea3e9653295ea7b75c7eef568fd76c4
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index c169b76..c70bc3e 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -45,6 +45,7 @@
OpaqueFlagChange opaque_flag = 13;
SecureFlagChange secure_flag = 14;
DeferredTransactionChange deferred_transaction = 15;
+ CornerRadiusChange corner_radius = 16;
}
}
@@ -62,6 +63,10 @@
required float alpha = 1;
}
+message CornerRadiusChange {
+ required float corner_radius = 1;
+}
+
message LayerChange {
required uint32 layer = 1;
}
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 6602546..384f21f 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -385,6 +385,9 @@
case SurfaceChange::SurfaceChangeCase::kCrop:
setCrop(transaction, change.id(), change.crop());
break;
+ case SurfaceChange::SurfaceChangeCase::kCornerRadius:
+ setCornerRadius(transaction, change.id(), change.corner_radius());
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
setMatrix(transaction, change.id(), change.matrix());
break;
@@ -489,6 +492,13 @@
t.setCrop_legacy(mLayers[id], r);
}
+void Replayer::setCornerRadius(SurfaceComposerClient::Transaction& t,
+ layer_id id, const CornerRadiusChange& cc) {
+ ALOGV("Layer %d: Setting Corner Radius -- cornerRadius=%d", id, cc.corner_radius());
+
+ t.setCornerRadius(mLayers[id], cc.corner_radius());
+}
+
void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc) {
ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 68390d3..120dd9b 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -92,6 +92,8 @@
layer_id id, const LayerChange& lc);
void setCrop(SurfaceComposerClient::Transaction& t,
layer_id id, const CropChange& cc);
+ void setCornerRadius(SurfaceComposerClient::Transaction& t,
+ layer_id id, const CornerRadiusChange& cc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9f30060..407eecb 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -82,6 +82,7 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
+ output.writeFloat(cornerRadius);
if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
for (const auto& [listener, callbackIds] : listenerCallbacks) {
@@ -149,6 +150,7 @@
}
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+ cornerRadius = input.readFloat();
int32_t listenersSize = input.readInt32();
for (int32_t i = 0; i < listenersSize; i++) {
@@ -270,6 +272,10 @@
what |= eCropChanged_legacy;
crop_legacy = other.crop_legacy;
}
+ if (other.what & eCornerRadiusChanged) {
+ what |= eCornerRadiusChanged;
+ cornerRadius = other.cornerRadius;
+ }
if (other.what & eDeferTransaction_legacy) {
what |= eDeferTransaction_legacy;
barrierHandle_legacy = other.barrierHandle_legacy;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 41e5abb..9dfccc7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -475,6 +475,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCornerRadius(
+ const sp<SurfaceControl>& sc, float cornerRadius) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eCornerRadiusChanged;
+ s->cornerRadius = cornerRadius;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
const sp<IBinder>& handle,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index cdb2309..3cfee9e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -82,6 +82,7 @@
eColorTransformChanged = 0x10000000,
eListenerCallbacksChanged = 0x20000000,
eInputInfoChanged = 0x40000000,
+ eCornerRadiusChanged = 0x80000000,
};
layer_state_t()
@@ -97,6 +98,7 @@
mask(0),
reserved(0),
crop_legacy(Rect::INVALID_RECT),
+ cornerRadius(0.0f),
frameNumber_legacy(0),
overrideScalingMode(-1),
transform(0),
@@ -135,6 +137,7 @@
uint8_t reserved;
matrix22_t matrix;
Rect crop_legacy;
+ float cornerRadius;
sp<IBinder> barrierHandle_legacy;
sp<IBinder> reparentHandle;
uint64_t frameNumber_legacy;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index cf55b6b..7d05512 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -265,6 +265,7 @@
Transaction& setMatrix(const sp<SurfaceControl>& sc,
float dsdx, float dtdx, float dtdy, float dsdy);
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
diff --git a/libs/renderengine/Mesh.cpp b/libs/renderengine/Mesh.cpp
index 6a40c6c..f5387f2 100644
--- a/libs/renderengine/Mesh.cpp
+++ b/libs/renderengine/Mesh.cpp
@@ -33,13 +33,15 @@
return;
}
- size_t stride = vertexSize + texCoordSize;
+ const size_t CROP_COORD_SIZE = 2;
+ size_t stride = vertexSize + texCoordSize + CROP_COORD_SIZE;
size_t remainder = (stride * vertexCount) / vertexCount;
// Since all of the input parameters are unsigned, if stride is less than
// either vertexSize or texCoordSize, it must have overflowed. remainder
// will be equal to stride as long as stride * vertexCount doesn't overflow.
if ((stride < vertexSize) || (remainder != stride)) {
- ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
+ ALOGE("Overflow in Mesh(..., %zu, %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize,
+ CROP_COORD_SIZE);
mVertices.resize(1);
mVertices[0] = 0.0f;
mVertexCount = 0;
@@ -71,6 +73,13 @@
return mVertices.data() + mVertexSize;
}
+float const* Mesh::getCropCoords() const {
+ return mVertices.data() + mVertexSize + mTexCoordsSize;
+}
+float* Mesh::getCropCoords() {
+ return mVertices.data() + mVertexSize + mTexCoordsSize;
+}
+
size_t Mesh::getVertexCount() const {
return mVertexCount;
}
diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
index b10b52b..7adda83 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -626,16 +626,18 @@
}
void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
- bool disableTexture, const half4& color) {
+ bool disableTexture, const half4& color,
+ float cornerRadius) {
mState.isPremultipliedAlpha = premultipliedAlpha;
mState.isOpaque = opaque;
mState.color = color;
+ mState.cornerRadius = cornerRadius;
if (disableTexture) {
mState.textureEnabled = false;
}
- if (color.a < 1.0f || !opaque) {
+ if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) {
glEnable(GL_BLEND);
glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
@@ -703,6 +705,10 @@
glDisable(GL_BLEND);
}
+void GLES20RenderEngine::setupCornerRadiusCropSize(float width, float height) {
+ mState.cropSize = half2(width, height);
+}
+
void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
ATRACE_CALL();
if (mesh.getTexCoordsSize()) {
@@ -714,6 +720,12 @@
glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
mesh.getByteStride(), mesh.getPositions());
+ if (mState.cornerRadius > 0.0f) {
+ glEnableVertexAttribArray(Program::cropCoords);
+ glVertexAttribPointer(Program::cropCoords, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+ mesh.getByteStride(), mesh.getCropCoords());
+ }
+
// By default, DISPLAY_P3 is the only supported wide color output. However,
// when HDR content is present, hardware composer may be able to handle
// BT2020 data space, in that case, the output data space is set to be
@@ -831,6 +843,10 @@
if (mesh.getTexCoordsSize()) {
glDisableVertexAttribArray(Program::texCoords);
}
+
+ if (mState.cornerRadius > 0.0f) {
+ glDisableVertexAttribArray(Program::cropCoords);
+ }
}
size_t GLES20RenderEngine::getMaxTextureSize() const {
diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
index 77dba62..a9f8cad 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -83,13 +83,14 @@
void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
ui::Transform::orientation_flags rotation) override;
void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color) override;
+ const half4& color, float cornerRadius) override;
void setupLayerTexturing(const Texture& texture) override;
void setupLayerBlackedOut() override;
void setupFillWithColor(float r, float g, float b, float a) override;
void setColorTransform(const mat4& colorTransform) override;
void disableTexturing() override;
void disableBlending() override;
+ void setupCornerRadiusCropSize(float width, float height) override;
// HDR and color management related functions and state
void setSourceY410BT2020(bool enable) override;
diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
index 7d2ea90..fe9d909 100644
--- a/libs/renderengine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -36,6 +36,7 @@
glAttachShader(programId, fragmentId);
glBindAttribLocation(programId, position, "position");
glBindAttribLocation(programId, texCoords, "texCoords");
+ glBindAttribLocation(programId, cropCoords, "cropCoords");
glLinkProgram(programId);
GLint status;
@@ -66,6 +67,8 @@
mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
+ mCornerRadiusLoc = glGetUniformLocation(programId, "cornerRadius");
+ mCropCenterLoc = glGetUniformLocation(programId, "cropCenter");
// set-up the default values for our uniforms
glUseProgram(programId);
@@ -135,6 +138,12 @@
if (mDisplayMaxLuminanceLoc >= 0) {
glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance);
}
+ if (mCornerRadiusLoc >= 0) {
+ glUniform1f(mCornerRadiusLoc, desc.cornerRadius);
+ }
+ if (mCropCenterLoc >= 0) {
+ glUniform2f(mCropCenterLoc, desc.cropSize.x / 2.0f, desc.cropSize.y / 2.0f);
+ }
// these uniforms are always present
glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray());
}
diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h
index 99bf0f0..bc9cf08 100644
--- a/libs/renderengine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -36,7 +36,16 @@
class Program {
public:
// known locations for position and texture coordinates
- enum { position = 0, texCoords = 1 };
+ enum {
+ /* position of each vertex for vertex shader */
+ position = 0,
+
+ /* UV coordinates for texture mapping */
+ texCoords = 1,
+
+ /* Crop coordinates, in pixels */
+ cropCoords = 2
+ };
Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
~Program() = default;
@@ -85,6 +94,12 @@
/* location of transform matrix */
GLint mInputTransformMatrixLoc;
GLint mOutputTransformMatrixLoc;
+
+ /* location of corner radius uniform */
+ GLint mCornerRadiusLoc;
+
+ /* location of surface crop origin uniform, for rounded corner clipping */
+ GLint mCropCenterLoc;
};
} // namespace gl
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 464fc15..d0916ad 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -79,7 +79,8 @@
void ProgramCache::primeCache(bool useColorManagement) {
uint32_t shaderCount = 0;
- uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
+ uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK
+ | Key::ROUNDED_CORNERS_MASK;
// Prime the cache for all combinations of the above masks,
// leaving off the experimental color matrix mask options.
@@ -136,12 +137,15 @@
.set(Key::OPACITY_MASK,
description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
.set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
- description.hasInputTransformMatrix() ? Key::INPUT_TRANSFORM_MATRIX_ON
- : Key::INPUT_TRANSFORM_MATRIX_OFF)
+ description.hasInputTransformMatrix()
+ ? Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
.set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
description.hasOutputTransformMatrix() || description.hasColorMatrix()
? Key::OUTPUT_TRANSFORM_MATRIX_ON
- : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
+ : Key::OUTPUT_TRANSFORM_MATRIX_OFF)
+ .set(Key::ROUNDED_CORNERS_MASK,
+ description.cornerRadius > 0
+ ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF);
needs.set(Key::Y410_BT2020_MASK,
description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
@@ -513,6 +517,10 @@
vs << "attribute vec4 texCoords;"
<< "varying vec2 outTexCoords;";
}
+ if (needs.hasRoundedCorners()) {
+ vs << "attribute lowp vec4 cropCoords;";
+ vs << "varying lowp vec2 outCropCoords;";
+ }
vs << "attribute vec4 position;"
<< "uniform mat4 projection;"
<< "uniform mat4 texture;"
@@ -520,6 +528,9 @@
if (needs.isTexturing()) {
vs << "outTexCoords = (texture * texCoords).st;";
}
+ if (needs.hasRoundedCorners()) {
+ vs << "outCropCoords = cropCoords.st;";
+ }
vs << dedent << "}";
return vs.getString();
}
@@ -541,6 +552,27 @@
<< "varying vec2 outTexCoords;";
}
+ if (needs.hasRoundedCorners()) {
+ // Rounded corners implementation using a signed distance function.
+ fs << R"__SHADER__(
+ uniform float cornerRadius;
+ uniform vec2 cropCenter;
+ varying vec2 outCropCoords;
+
+ /**
+ * This function takes the current crop coordinates and calculates an alpha value based
+ * on the corner radius and distance from the crop center.
+ */
+ float applyCornerRadius(vec2 cropCoords)
+ {
+ vec2 position = cropCoords - cropCenter;
+ vec2 dist = abs(position) + vec2(cornerRadius) - cropCenter;
+ float plane = length(max(dist, vec2(0.0)));
+ return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0);
+ }
+ )__SHADER__";
+ }
+
if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
fs << "uniform vec4 color;";
}
@@ -639,6 +671,14 @@
}
}
+ if (needs.hasRoundedCorners()) {
+ if (needs.isPremultiplied()) {
+ fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));";
+ } else {
+ fs << "gl_FragColor.a *= applyCornerRadius(outCropCoords);";
+ }
+ }
+
fs << dedent << "}";
return fs.getString();
}
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index d60fee6..653aaf0 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -78,31 +78,36 @@
TEXTURE_EXT = 1 << TEXTURE_SHIFT,
TEXTURE_2D = 2 << TEXTURE_SHIFT,
- INPUT_TRANSFORM_MATRIX_SHIFT = 5,
+ ROUNDED_CORNERS_SHIFT = 5,
+ ROUNDED_CORNERS_MASK = 1 << ROUNDED_CORNERS_SHIFT,
+ ROUNDED_CORNERS_OFF = 0 << ROUNDED_CORNERS_SHIFT,
+ ROUNDED_CORNERS_ON = 1 << ROUNDED_CORNERS_SHIFT,
+
+ INPUT_TRANSFORM_MATRIX_SHIFT = 6,
INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
- OUTPUT_TRANSFORM_MATRIX_SHIFT = 6,
+ OUTPUT_TRANSFORM_MATRIX_SHIFT = 7,
OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
- INPUT_TF_SHIFT = 7,
+ INPUT_TF_SHIFT = 8,
INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
- OUTPUT_TF_SHIFT = 9,
+ OUTPUT_TF_SHIFT = 10,
OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
- Y410_BT2020_SHIFT = 11,
+ Y410_BT2020_SHIFT = 12,
Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
@@ -121,6 +126,9 @@
inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
+ inline bool hasRoundedCorners() const {
+ return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON;
+ }
inline bool hasInputTransformMatrix() const {
return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
}
diff --git a/libs/renderengine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h
index fe9022d..7618424 100644
--- a/libs/renderengine/include/renderengine/Mesh.h
+++ b/libs/renderengine/include/renderengine/Mesh.h
@@ -62,14 +62,22 @@
return VertexArray<TYPE>(getTexCoords(), mStride);
}
+ template <typename TYPE>
+ VertexArray<TYPE> getCropCoordArray() {
+ return VertexArray<TYPE>(getCropCoords(), mStride);
+ }
+
Primitive getPrimitive() const;
// returns a pointer to the vertices positions
float const* getPositions() const;
- // returns a pointer to the vertices texture coordinates
+ // returns a pointer to the vertices texture coordinates
float const* getTexCoords() const;
+ // returns a pointer to the vertices crop coordinates
+ float const* getCropCoords() const;
+
// number of vertices in this mesh
size_t getVertexCount() const;
@@ -92,6 +100,7 @@
float* getPositions();
float* getTexCoords();
+ float* getCropCoords();
std::vector<float> mVertices;
size_t mVertexCount;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 22891c4..bb7f4df 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -114,10 +114,20 @@
virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
ui::Transform::orientation_flags rotation) = 0;
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color) = 0;
+ const half4& color, float cornerRadius) = 0;
virtual void setupLayerTexturing(const Texture& texture) = 0;
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
+ // Sets up the crop size for corner radius clipping.
+ //
+ // Having corner radius will force GPU composition on the layer and its children, drawing it
+ // with a special shader. The shader will receive the radius and the crop rectangle as input,
+ // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
+ // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
+ // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
+ // in local layer coordinate space, so we have to take the layer transform into account when
+ // walking up the tree.
+ virtual void setupCornerRadiusCropSize(float width, float height) = 0;
// Set a color transform matrix that is applied in linear space right before OETF.
virtual void setColorTransform(const mat4& /* colorTransform */) = 0;
diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
index eadd656..bd2055f 100644
--- a/libs/renderengine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -50,6 +50,12 @@
// whether this layer is marked as opaque
bool isOpaque = true;
+ // corner radius of the layer
+ float cornerRadius = 0;
+
+ // Size of the rounded rectangle we are cropping to
+ half2 cropSize;
+
// Texture this layer uses
Texture texture;
bool textureEnabled = false;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b862278..fd40f6c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -641,15 +641,21 @@
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());
+ getColor(), roundedCornerState.radius);
engine.setSourceDataSpace(mCurrentDataSpace);
if (isHdrY410()) {
engine.setSourceY410BT2020(true);
}
+ engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
+
engine.drawMesh(getBE().mMesh);
engine.disableBlending();
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 9c34308..f27f6aa 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -45,9 +45,18 @@
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);
+ true /* disableTexture */, color, roundedCornerState.radius);
+
engine.setSourceDataSpace(mCurrentDataSpace);
+ engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
engine.drawMesh(mesh);
engine.disableBlending();
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 81456df..4080f12 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -101,6 +101,7 @@
mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion.clear();
+ mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
@@ -400,6 +401,23 @@
return activeCrop;
}
+void Layer::setupRoundedCornersCropCoordinates(Rect win,
+ const FloatRect& roundedCornersCrop) const {
+ // Translate win by the rounded corners rect coordinates, to have all values in
+ // layer coordinate space.
+ win.left -= roundedCornersCrop.left;
+ win.right -= roundedCornersCrop.left;
+ win.top -= roundedCornersCrop.top;
+ win.bottom -= roundedCornersCrop.top;
+
+ renderengine::Mesh::VertexArray<vec2> cropCoords(getBE().mMesh.getCropCoordArray<vec2>());
+ cropCoords[0] = vec2(win.left, win.top);
+ cropCoords[1] = vec2(win.left, win.top + win.getHeight());
+ cropCoords[2] = vec2(win.right, win.top + win.getHeight());
+ cropCoords[3] = vec2(win.right, win.top);
+ cropCoords[3] = vec2(win.right, win.top);
+}
+
FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
// the content crop is the area of the content that gets scaled to the
// layer's size. This is in buffer space.
@@ -1220,6 +1238,17 @@
return true;
}
+bool Layer::setCornerRadius(float cornerRadius) {
+ if (mCurrentState.cornerRadius == cornerRadius)
+ return false;
+
+ mCurrentState.sequence++;
+ mCurrentState.cornerRadius = cornerRadius;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
bool allowNonRectPreservingTransforms) {
ui::Transform t;
@@ -1918,6 +1947,26 @@
return half4(color.r, color.g, color.b, getAlpha());
}
+Layer::RoundedCornerState Layer::getRoundedCornerState() const {
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ RoundedCornerState parentState = p->getRoundedCornerState();
+ if (parentState.radius > 0) {
+ ui::Transform t = getActiveTransform(getDrawingState());
+ t = t.inverse();
+ parentState.cropRect = t.transform(parentState.cropRect);
+ // The rounded corners shader only accepts 1 corner radius for performance reasons,
+ // but a transform matrix can define horizontal and vertical scales.
+ // Let's take the average between both of them and pass into the shader, practically we
+ // never do this type of transformation on windows anyway.
+ parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+ return parentState;
+ }
+ }
+ const float radius = getDrawingState().cornerRadius;
+ return radius > 0 ? RoundedCornerState(computeBounds(), radius) : RoundedCornerState();
+}
+
void Layer::commitChildList() {
for (size_t i = 0; i < mCurrentChildren.size(); i++) {
const auto& child = mCurrentChildren[i];
@@ -1978,6 +2027,7 @@
size->set_h(state.active_legacy.h);
LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
+ layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_is_opaque(isOpaque(state));
layerInfo->set_invalidate(contentDirty);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a4f9c93..687fc0a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -125,6 +125,17 @@
inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
};
+ struct RoundedCornerState {
+ RoundedCornerState() = default;
+ RoundedCornerState(FloatRect cropRect, float radius)
+ : cropRect(cropRect), radius(radius) {}
+
+ // Rounded rectangle in local layer coordinate space.
+ FloatRect cropRect = FloatRect();
+ // Radius of the rounded rectangle.
+ float radius = 0.0f;
+ };
+
struct State {
Geometry active_legacy;
Geometry requested_legacy;
@@ -167,6 +178,7 @@
SortedVector<wp<Layer>> zOrderRelatives;
half4 color;
+ float cornerRadius;
bool inputInfoChanged;
InputWindowInfo inputInfo;
@@ -255,6 +267,13 @@
virtual bool setAlpha(float alpha);
virtual bool setColor(const half3& color);
+
+ // Set rounded corner radius for this layer and its children.
+ //
+ // We only support 1 radius per layer in the hierarchy, where parent layers have precedence.
+ // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
+ // from which we inferred the rounded corner radius.
+ virtual bool setCornerRadius(float cornerRadius);
virtual bool setTransparentRegionHint(const Region& transparent);
virtual bool setFlags(uint8_t flags, uint8_t mask);
virtual bool setLayerStack(uint32_t layerStack);
@@ -573,6 +592,13 @@
half getAlpha() const;
half4 getColor() const;
+ // Returns how rounded corners should be drawn for this layer.
+ // This will traverse the hierarchy until it reaches its root, finding topmost rounded
+ // corner definition and converting it into current layer's coordinates.
+ // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
+ // ignored.
+ RoundedCornerState getRoundedCornerState() const;
+
void traverseInReverseZOrder(LayerVector::StateSet stateSet,
const LayerVector::Visitor& visitor);
void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
@@ -645,11 +671,15 @@
// IGraphicBufferProducer client, as that should not affect child clipping.
// Returns in screen space.
Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
+ /**
+ * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
+ * crop coordinates, transforming them into layer space.
+ */
+ void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
// drawing
void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
float alpha) const;
-
void setParent(const sp<Layer>& layer);
LayerVector makeTraversalList(LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3e5920f..5b3c477 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1687,6 +1687,10 @@
layer->forceClientComposition(*displayId);
}
+ if (layer->getRoundedCornerState().radius > 0.0f) {
+ layer->forceClientComposition(*displayId);
+ }
+
if (layer->getForceClientComposition(*displayId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
layer->setCompositionType(*displayId, HWC2::Composition::Client);
@@ -2876,6 +2880,7 @@
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
if (layer->getAlpha() == 1.0f && !translucent &&
+ layer->getRoundedCornerState().radius == 0.0f &&
((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
@@ -3166,7 +3171,7 @@
const Layer::State& state(layer->getDrawingState());
if (layer->getClearClientTarget(*displayId) && !firstLayer &&
layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
- hasClientComposition) {
+ layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
layer->clearWithOpenGL(renderArea);
@@ -3586,6 +3591,10 @@
if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eCornerRadiusChanged) {
+ if (layer->setCornerRadius(s.cornerRadius))
+ flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eLayerStackChanged) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
// We only allow setting layer stacks for top level layers,
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 55cfa4b..7bfe033 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -109,6 +109,7 @@
layer->mCurrentState.activeTransparentRegion_legacy);
addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
+ addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
layer->mCurrentState.barrierLayer_legacy.promote(),
@@ -289,6 +290,14 @@
setProtoRectLocked(protoRect, rect);
}
+void SurfaceInterceptor::addCornerRadiusLocked(Transaction* transaction, int32_t layerId,
+ float cornerRadius)
+{
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ CornerRadiusChange* cornerRadiusChange(change->mutable_corner_radius());
+ cornerRadiusChange->set_corner_radius(cornerRadius);
+}
+
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -350,6 +359,9 @@
if (state.what & layer_state_t::eCropChanged_legacy) {
addCropLocked(transaction, layerId, state.crop_legacy);
}
+ if (state.what & layer_state_t::eCornerRadiusChanged) {
+ addCornerRadiusLocked(transaction, layerId, state.cornerRadius);
+ }
if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
if (state.barrierHandle_legacy != nullptr) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 394b99b..563a44c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -144,6 +144,7 @@
void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags);
void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
+ void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 1d7fb67..d020a39 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -121,6 +121,7 @@
layer.appId = layerProto.app_id();
layer.hwcCompositionType = layerProto.hwc_composition_type();
layer.isProtected = layerProto.is_protected();
+ layer.cornerRadius = layerProto.corner_radius();
return layer;
}
@@ -294,6 +295,7 @@
size.y);
StringAppendF(&result, "crop=%s, ", crop.to_string().c_str());
+ StringAppendF(&result, "cornerRadius=%f, ", cornerRadius);
StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 6b3b497..a794ca5 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -114,6 +114,7 @@
int32_t appId;
int32_t hwcCompositionType;
bool isProtected;
+ float cornerRadius;
std::string to_string() const;
};
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index c141ee3..b100438 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -87,6 +87,8 @@
// If active_buffer is not null, record its transform.
optional TransformProto buffer_transform = 39;
optional int32 effective_scaling_mode = 40;
+ // Layer's corner radius.
+ optional float corner_radius = 41;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 740d2fa..e506757 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -44,6 +44,7 @@
constexpr uint32_t STACK_UPDATE = 1;
constexpr uint64_t DEFERRED_UPDATE = 0;
constexpr float ALPHA_UPDATE = 0.29f;
+constexpr float CORNER_RADIUS_UPDATE = 0.2f;
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
@@ -167,6 +168,7 @@
bool alphaUpdateFound(const SurfaceChange& change, bool foundAlpha);
bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
+ bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -198,6 +200,7 @@
void alphaUpdate(Transaction&);
void layerUpdate(Transaction&);
void cropUpdate(Transaction&);
+ void cornerRadiusUpdate(Transaction&);
void matrixUpdate(Transaction&);
void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
@@ -313,6 +316,10 @@
t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE);
}
+void SurfaceInterceptorTest::cornerRadiusUpdate(Transaction& t) {
+ t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
+}
+
void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
@@ -369,6 +376,7 @@
runInTransaction(&SurfaceInterceptorTest::positionUpdate);
runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
+ runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -430,6 +438,17 @@
return foundAlpha;
}
+bool SurfaceInterceptorTest::cornerRadiusUpdateFound(const SurfaceChange &change,
+ bool foundCornerRadius) {
+ bool hasCornerRadius(change.corner_radius().corner_radius() == CORNER_RADIUS_UPDATE);
+ if (hasCornerRadius && !foundCornerRadius) {
+ foundCornerRadius = true;
+ } else if (hasCornerRadius && foundCornerRadius) {
+ [] () { FAIL(); }();
+ }
+ return foundCornerRadius;
+}
+
bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
@@ -572,6 +591,9 @@
case SurfaceChange::SurfaceChangeCase::kCrop:
foundUpdate = cropUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kCornerRadius:
+ foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -730,6 +752,11 @@
captureTest(&SurfaceInterceptorTest::cropUpdate, SurfaceChange::SurfaceChangeCase::kCrop);
}
+TEST_F(SurfaceInterceptorTest, InterceptCornerRadiusUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::cornerRadiusUpdate,
+ SurfaceChange::SurfaceChangeCase::kCornerRadius);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 7e95d99..e414991 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1225,6 +1225,28 @@
}
}
+TEST_P(LayerTypeTransactionTest, SetCornerRadius) {
+ sp<SurfaceControl> layer;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 16.0f;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
+
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .apply();
+ {
+ auto shot = screenshot();
+ // Transparent corners
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(0, size - testArea, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, 0, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, size - testArea, testArea, testArea),
+ Color::BLACK);
+ }
+}
+
TEST_F(LayerTransactionTest, SetColorBasic) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index cfaf495..5a6aa92 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -580,7 +580,8 @@
EXPECT_CALL(*test->mRenderEngine,
setupLayerBlending(true, false, false,
half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
- LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
+ 0.0f))
.Times(1);
EXPECT_CALL(*test->mRenderEngine, createImage())
@@ -626,7 +627,8 @@
EXPECT_CALL(*test->mRenderEngine,
setupLayerBlending(true, false, true,
half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
- LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
+ 0.0f))
.Times(1);
EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
@@ -690,7 +692,7 @@
EXPECT_CALL(*test->mRenderEngine,
setupLayerBlending(true, false, false,
half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
- Base::COLOR[3])))
+ Base::COLOR[3]), 0.0f))
.Times(1);
EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 90c3c20..a416808 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -56,10 +56,11 @@
MOCK_CONST_METHOD0(checkErrors, void());
MOCK_METHOD4(setViewportAndProjection,
void(size_t, size_t, Rect, ui::Transform::orientation_flags));
- MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
+ MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float));
MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
MOCK_METHOD0(setupLayerBlackedOut, void());
MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
+ MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float));
MOCK_METHOD1(setColorTransform, void(const mat4&));
MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
MOCK_METHOD0(disableTexturing, void());