From 46080ef7141f53ca6bb24f4edaf0b674069c5bd4 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 26 Oct 2018 18:43:14 -0700 Subject: [RenderEngine] Move RenderEngine to libs/renderengine To do side-by-side comparison between readback buffer from hardware composer and client target of RenderEngine, we need RenderEngine to be accessible in VTS, which means RenderEngine should be part of VNDK. This patch moves RenderEngine out of SurfaceFlinger to libs/renderengine. BUG: 112585051 Test: build, flash, boot and do some display validation Change-Id: Ib6b302eaad04c7cc6c5bae39b1d25b38be188d01 --- libs/renderengine/Mesh.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 libs/renderengine/Mesh.cpp (limited to 'libs/renderengine/Mesh.cpp') diff --git a/libs/renderengine/Mesh.cpp b/libs/renderengine/Mesh.cpp new file mode 100644 index 0000000000..6a40c6c680 --- /dev/null +++ b/libs/renderengine/Mesh.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace android { +namespace renderengine { + +Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) + : mVertexCount(vertexCount), + mVertexSize(vertexSize), + mTexCoordsSize(texCoordSize), + mPrimitive(primitive) { + if (vertexCount == 0) { + mVertices.resize(1); + mVertices[0] = 0.0f; + mStride = 0; + return; + } + + size_t stride = vertexSize + texCoordSize; + 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); + mVertices.resize(1); + mVertices[0] = 0.0f; + mVertexCount = 0; + mVertexSize = 0; + mTexCoordsSize = 0; + mStride = 0; + return; + } + + mVertices.resize(stride * vertexCount); + mStride = stride; +} + +Mesh::Primitive Mesh::getPrimitive() const { + return mPrimitive; +} + +float const* Mesh::getPositions() const { + return mVertices.data(); +} +float* Mesh::getPositions() { + return mVertices.data(); +} + +float const* Mesh::getTexCoords() const { + return mVertices.data() + mVertexSize; +} +float* Mesh::getTexCoords() { + return mVertices.data() + mVertexSize; +} + +size_t Mesh::getVertexCount() const { + return mVertexCount; +} + +size_t Mesh::getVertexSize() const { + return mVertexSize; +} + +size_t Mesh::getTexCoordsSize() const { + return mTexCoordsSize; +} + +size_t Mesh::getByteStride() const { + return mStride * sizeof(float); +} + +size_t Mesh::getStride() const { + return mStride; +} + +} // namespace renderengine +} // namespace android -- cgit v1.2.3-59-g8ed1b From 1b6531ccf5dab13a6817c7519693df220d0944a1 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 5 Jul 2018 17:18:21 -0700 Subject: Rounded corners Test: visual Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Fixes: 111514493 Change-Id: Ie8f400bbcea3e9653295ea7b75c7eef568fd76c4 --- cmds/surfacereplayer/proto/src/trace.proto | 5 +++ cmds/surfacereplayer/replayer/Replayer.cpp | 10 +++++ cmds/surfacereplayer/replayer/Replayer.h | 2 + libs/gui/LayerState.cpp | 6 +++ libs/gui/SurfaceComposerClient.cpp | 12 ++++++ libs/gui/include/gui/LayerState.h | 3 ++ libs/gui/include/gui/SurfaceComposerClient.h | 1 + libs/renderengine/Mesh.cpp | 13 +++++- libs/renderengine/gl/GLES20RenderEngine.cpp | 20 ++++++++- libs/renderengine/gl/GLES20RenderEngine.h | 3 +- libs/renderengine/gl/Program.cpp | 9 ++++ libs/renderengine/gl/Program.h | 17 +++++++- libs/renderengine/gl/ProgramCache.cpp | 48 +++++++++++++++++++-- libs/renderengine/gl/ProgramCache.h | 18 +++++--- libs/renderengine/include/renderengine/Mesh.h | 11 ++++- .../include/renderengine/RenderEngine.h | 12 +++++- .../include/renderengine/private/Description.h | 6 +++ services/surfaceflinger/BufferLayer.cpp | 8 +++- services/surfaceflinger/ColorLayer.cpp | 11 ++++- services/surfaceflinger/Layer.cpp | 50 ++++++++++++++++++++++ services/surfaceflinger/Layer.h | 32 +++++++++++++- services/surfaceflinger/SurfaceFlinger.cpp | 11 ++++- services/surfaceflinger/SurfaceInterceptor.cpp | 12 ++++++ services/surfaceflinger/SurfaceInterceptor.h | 1 + .../surfaceflinger/layerproto/LayerProtoParser.cpp | 2 + .../include/layerproto/LayerProtoParser.h | 1 + services/surfaceflinger/layerproto/layers.proto | 2 + .../tests/SurfaceInterceptor_test.cpp | 27 ++++++++++++ services/surfaceflinger/tests/Transaction_test.cpp | 22 ++++++++++ .../tests/unittests/CompositionTest.cpp | 8 ++-- .../unittests/mock/RenderEngine/MockRenderEngine.h | 3 +- 31 files changed, 361 insertions(+), 25 deletions(-) (limited to 'libs/renderengine/Mesh.cpp') 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(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& 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& sc, const sp& 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 barrierHandle_legacy; sp 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& sc, float dsdx, float dtdx, float dtdy, float dsdy); Transaction& setCrop_legacy(const sp& sc, const Rect& crop); + Transaction& setCornerRadius(const sp& sc, float cornerRadius); Transaction& setLayerStack(const sp& 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(getTexCoords(), mStride); } + template + VertexArray getCropCoordArray() { + return VertexArray(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 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& 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 cropCoords(getBE().mMesh.getCropCoordArray()); + 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& 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> 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& 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); 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& 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& 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& 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 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& 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 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 bufferLayer; sp 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 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()); -- cgit v1.2.3-59-g8ed1b