diff options
31 files changed, 361 insertions, 25 deletions
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index c169b763d4..c70bc3e5c1 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -45,6 +45,7 @@ message SurfaceChange { OpaqueFlagChange opaque_flag = 13; SecureFlagChange secure_flag = 14; DeferredTransactionChange deferred_transaction = 15; + CornerRadiusChange corner_radius = 16; } } @@ -62,6 +63,10 @@ message AlphaChange { 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 66025468ea..384f21ff17 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -385,6 +385,9 @@ status_t Replayer::doSurfaceTransaction( 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 @@ void Replayer::setCrop(SurfaceComposerClient::Transaction& t, 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 68390d33ae..120dd9babd 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -92,6 +92,8 @@ class Replayer { 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 9f30060467..407eecb6fb 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -82,6 +82,7 @@ status_t layer_state_t::write(Parcel& output) const 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 @@ status_t layer_state_t::read(const Parcel& input) } 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 @@ void layer_state_t::merge(const layer_state_t& other) { 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 41e5abbd0e..9dfccc799e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -475,6 +475,18 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_ 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 cdb230995b..3cfee9e8b7 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -82,6 +82,7 @@ struct layer_state_t { eColorTransformChanged = 0x10000000, eListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, + eCornerRadiusChanged = 0x80000000, }; layer_state_t() @@ -97,6 +98,7 @@ struct layer_state_t { mask(0), reserved(0), crop_legacy(Rect::INVALID_RECT), + cornerRadius(0.0f), frameNumber_legacy(0), overrideScalingMode(-1), transform(0), @@ -135,6 +137,7 @@ struct layer_state_t { 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 cf55b6b33d..7d0551289e 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -265,6 +265,7 @@ public: 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 6a40c6c680..f5387f28ea 100644 --- a/libs/renderengine/Mesh.cpp +++ b/libs/renderengine/Mesh.cpp @@ -33,13 +33,15 @@ Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t te 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 @@ float* Mesh::getTexCoords() { 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 b10b52bad8..7adda83926 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.cpp +++ b/libs/renderengine/gl/GLES20RenderEngine.cpp @@ -626,16 +626,18 @@ void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect s } 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 @@ void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) 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 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { 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 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { 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 77dba626a0..a9f8cad4cf 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.h +++ b/libs/renderengine/gl/GLES20RenderEngine.h @@ -83,13 +83,14 @@ protected: 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 7d2ea90d82..fe9d909923 100644 --- a/libs/renderengine/gl/Program.cpp +++ b/libs/renderengine/gl/Program.cpp @@ -36,6 +36,7 @@ Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const c glAttachShader(programId, fragmentId); glBindAttribLocation(programId, position, "position"); glBindAttribLocation(programId, texCoords, "texCoords"); + glBindAttribLocation(programId, cropCoords, "cropCoords"); glLinkProgram(programId); GLint status; @@ -66,6 +67,8 @@ Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const c 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 @@ void Program::setUniforms(const Description& desc) { 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 99bf0f071b..bc9cf08b8b 100644 --- a/libs/renderengine/gl/Program.h +++ b/libs/renderengine/gl/Program.h @@ -36,7 +36,16 @@ namespace gl { 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 @@ private: /* 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 464fc151a8..d0916adaf0 100644 --- a/libs/renderengine/gl/ProgramCache.cpp +++ b/libs/renderengine/gl/ProgramCache.cpp @@ -79,7 +79,8 @@ Formatter& dedent(Formatter& f) { 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 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) { .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 @@ String8 ProgramCache::generateVertexShader(const Key& needs) { 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 @@ String8 ProgramCache::generateVertexShader(const Key& needs) { if (needs.isTexturing()) { vs << "outTexCoords = (texture * texCoords).st;"; } + if (needs.hasRoundedCorners()) { + vs << "outCropCoords = cropCoords.st;"; + } vs << dedent << "}"; return vs.getString(); } @@ -541,6 +552,27 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { << "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 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } } + 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 d60fee6345..653aaf0f6c 100644 --- a/libs/renderengine/gl/ProgramCache.h +++ b/libs/renderengine/gl/ProgramCache.h @@ -78,31 +78,36 @@ public: 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 @@ public: 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 fe9022db03..7618424e85 100644 --- a/libs/renderengine/include/renderengine/Mesh.h +++ b/libs/renderengine/include/renderengine/Mesh.h @@ -62,14 +62,22 @@ public: 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 @@ private: 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 22891c42c4..bb7f4dfb71 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -114,10 +114,20 @@ public: 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 eadd656749..bd2055f4e5 100644 --- a/libs/renderengine/include/renderengine/private/Description.h +++ b/libs/renderengine/include/renderengine/private/Description.h @@ -50,6 +50,12 @@ struct Description { // 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 b862278e35..fd40f6cfa3 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -641,15 +641,21 @@ void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityT 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 9c34308cab..f27f6aa87e 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -45,9 +45,18 @@ void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */, 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 81456dfea9..4080f12449 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,6 +101,7 @@ Layer::Layer(const LayerCreationArgs& args) 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 @@ Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const { 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 @@ bool Layer::setColor(const half3& color) { 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 @@ half4 Layer::getColor() const { 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 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) 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 a4f9c9345b..687fc0a712 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -125,6 +125,17 @@ public: 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 @@ public: SortedVector<wp<Layer>> zOrderRelatives; half4 color; + float cornerRadius; bool inputInfoChanged; InputWindowInfo inputInfo; @@ -255,6 +267,13 @@ public: 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 @@ public: 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 @@ protected: // 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 3e5920f852..5b3c47713e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1687,6 +1687,10 @@ void SurfaceFlinger::calculateWorkingSet() { 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 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa // 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 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) { 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 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState 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 55cfa4bf7d..7bfe0338f7 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -109,6 +109,7 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, 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 @@ void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId 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 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, 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 394b99b415..563a44c088 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -144,6 +144,7 @@ private: 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 1d7fb6791f..d020a394ce 100644 --- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -121,6 +121,7 @@ LayerProtoParser::Layer LayerProtoParser::generateLayer(const LayerProto& layerP 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 @@ std::string LayerProtoParser::Layer::to_string() const { 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 6b3b49763d..a794ca57a3 100644 --- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -114,6 +114,7 @@ public: 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 c141ee3cab..b10043877c 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -87,6 +87,8 @@ message LayerProto { // 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 740d2fa302..e506757867 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -44,6 +44,7 @@ constexpr uint32_t SIZE_UPDATE = 134; 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 @@ public: 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 @@ public: 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 @@ void SurfaceInterceptorTest::alphaUpdate(Transaction& t) { 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 @@ void SurfaceInterceptorTest::runAllUpdates() { 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 @@ bool SurfaceInterceptorTest::alphaUpdateFound(const SurfaceChange& change, bool 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 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, 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 @@ TEST_F(SurfaceInterceptorTest, InterceptCropUpdateWorks) { 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 7e95d99512..e414991620 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -1225,6 +1225,28 @@ TEST_P(LayerTypeTransactionTest, SetAlphaClamped) { } } +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 cfaf495767..5a6aa9279a 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -580,7 +580,8 @@ struct BaseLayerProperties { 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 @@ struct BaseLayerProperties { 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 @@ struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> 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 90c3c20b68..a416808297 100644 --- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h +++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h @@ -56,10 +56,11 @@ public: 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()); |