diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/renderengine/gl/GLESRenderEngine.cpp | 14 | ||||
| -rw-r--r-- | libs/renderengine/include/renderengine/LayerSettings.h | 5 | ||||
| -rw-r--r-- | libs/renderengine/skia/Cache.cpp | 21 | ||||
| -rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.cpp | 24 | ||||
| -rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.h | 3 | ||||
| -rw-r--r-- | libs/renderengine/tests/RenderEngineTest.cpp | 60 |
6 files changed, 89 insertions, 38 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 22dd86698b..6dc01b916e 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -921,7 +921,8 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners // and the middle part without rounded corners. - const int32_t radius = ceil(layer.geometry.roundedCornersRadius); + const int32_t radius = ceil( + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0); const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); setScissor(topRect); drawMesh(mesh); @@ -1266,23 +1267,24 @@ void GLESRenderEngine::drawLayersInternal( const half3 solidColor = layer.source.solidColor; const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + const float radius = + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / + 2.0f; // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer.geometry.roundedCornersRadius); + setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius); if (layer.disableBlending) { glDisable(GL_BLEND); } setSourceDataSpace(layer.sourceDataspace); if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, - layer.shadow); + handleShadow(layer.geometry.boundaries, radius, layer.shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + else if (radius > 0.0 && color.a >= 1.0f && isOpaque) { handleRoundedCorners(display, layer, mesh); } else { drawMesh(mesh); diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 154e5269f0..b3a617c04b 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -87,7 +87,7 @@ struct Geometry { // 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. - float roundedCornersRadius = 0.0; + vec2 roundedCornersRadius = vec2(0.0f, 0.0f); // Rectangle within which corners will be rounded. FloatRect roundedCornersCrop = FloatRect(); @@ -258,7 +258,8 @@ static inline void PrintTo(const Geometry& settings, ::std::ostream* os) { PrintTo(settings.boundaries, os); *os << "\n .positionTransform = "; PrintMatrix(settings.positionTransform, os); - *os << "\n .roundedCornersRadius = " << settings.roundedCornersRadius; + *os << "\n .roundedCornersRadiusX = " << settings.roundedCornersRadius.x; + *os << "\n .roundedCornersRadiusY = " << settings.roundedCornersRadius.y; *os << "\n .roundedCornersCrop = "; PrintTo(settings.roundedCornersCrop, os); *os << "\n}"; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index f3064f3c69..c39f0a97fd 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -66,7 +66,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = rect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, // drawShadow ignores alpha .shadow = @@ -87,7 +87,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = smallerRect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, .source = PixelSource{ @@ -148,7 +148,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting // In reduced shader mode, all non-zero round rect radii get the same code path. for (float roundedCornersRadius : {0.0f, 50.0f}) { // roundedCornersCrop is always set, but the radius triggers the behavior - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; for (bool isOpaque : {true, false}) { layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.2f), half(1.0f)}) { @@ -181,7 +181,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; auto layers = std::vector<LayerSettings>{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); @@ -238,7 +238,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti .geometry = Geometry{ .boundaries = rect, - .roundedCornersRadius = 27, // larger than the 20 above. + .roundedCornersRadius = {27.f, 27.f}, .roundedCornersCrop = FloatRect(0, 0, displayRect.width(), displayRect.height()), }, @@ -275,9 +275,9 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti // larger than the layer bounds. .positionTransform = kFlip, .boundaries = rect, - .roundedCornersRadius = 94.2551, - .roundedCornersCrop = FloatRect( - -93.75, 0, displayRect.width() + 93.75, displayRect.height()), + .roundedCornersRadius = {94.2551f, 94.2551f}, + .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75, + displayRect.height()), }, .source = PixelSource{.buffer = Buffer{ @@ -307,10 +307,11 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett // the boundaries have to be smaller than the rounded crop so that // clipRRect is used instead of drawRRect .boundaries = small, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, .roundedCornersCrop = rect, }, - .source = PixelSource{ + .source = + PixelSource{ .solidColor = half3(0.f, 0.f, 0.f), }, .sourceDataspace = kDestDataSpace, diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 97271cb32d..0caa9f2fbd 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1276,7 +1276,7 @@ inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) { * produce the insected roundRect. If false, the returned state of the radii param is undefined. */ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, - const SkRect& insetCrop, float cornerRadius, + const SkRect& insetCrop, const vec2& cornerRadius, SkVector radii[4]) { const bool leftEqual = bounds.fLeft == crop.fLeft; const bool topEqual = bounds.fTop == crop.fTop; @@ -1288,8 +1288,8 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, // In particular the round rect implementation will scale the value of all corner radii // if the sum of the radius along any edge is greater than the length of that edge. // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap - const bool requiredWidth = bounds.width() > (cornerRadius * 2); - const bool requiredHeight = bounds.height() > (cornerRadius * 2); + const bool requiredWidth = bounds.width() > (cornerRadius.x * 2); + const bool requiredHeight = bounds.height() > (cornerRadius.y * 2); if (!requiredWidth || !requiredHeight) { return false; } @@ -1298,7 +1298,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, // contained within the cropped shape and does not need rounded. // compute the UpperLeft corner radius if (leftEqual && topEqual) { - radii[0].set(cornerRadius, cornerRadius); + radii[0].set(cornerRadius.x, cornerRadius.y); } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) || (topEqual && bounds.fLeft >= insetCrop.fLeft)) { radii[0].set(0, 0); @@ -1307,7 +1307,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the UpperRight corner radius if (rightEqual && topEqual) { - radii[1].set(cornerRadius, cornerRadius); + radii[1].set(cornerRadius.x, cornerRadius.y); } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) || (topEqual && bounds.fRight <= insetCrop.fRight)) { radii[1].set(0, 0); @@ -1316,7 +1316,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the BottomRight corner radius if (rightEqual && bottomEqual) { - radii[2].set(cornerRadius, cornerRadius); + radii[2].set(cornerRadius.x, cornerRadius.y); } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) || (bottomEqual && bounds.fRight <= insetCrop.fRight)) { radii[2].set(0, 0); @@ -1325,7 +1325,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the BottomLeft corner radius if (leftEqual && bottomEqual) { - radii[3].set(cornerRadius, cornerRadius); + radii[3].set(cornerRadius.x, cornerRadius.y); } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) || (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) { radii[3].set(0, 0); @@ -1338,22 +1338,22 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect, const FloatRect& cropRect, - const float cornerRadius) { + const vec2& cornerRadius) { const SkRect bounds = getSkRect(boundsRect); const SkRect crop = getSkRect(cropRect); SkRRect clip; - if (cornerRadius > 0) { + if (cornerRadius.x > 0 && cornerRadius.y > 0) { // it the crop and the bounds are equivalent or there is no crop then we don't need a clip if (bounds == crop || crop.isEmpty()) { - return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip}; + return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip}; } // This makes an effort to speed up common, simple bounds + clip combinations by // converting them to a single RRect draw. It is possible there are other cases // that can be converted. if (crop.contains(bounds)) { - const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius); + const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y); if (insetCrop.contains(bounds)) { return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required } @@ -1367,7 +1367,7 @@ inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const Fl } // we didn't hit any of our fast paths so set the clip to the cropRect - clip.setRectXY(crop, cornerRadius, cornerRadius); + clip.setRectXY(crop, cornerRadius.x, cornerRadius.y); } // if we hit this point then we either don't have rounded corners or we are going to rely diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 5ef9944b14..68c336327b 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -90,7 +90,8 @@ private: inline SkRect getSkRect(const FloatRect& layer); inline SkRect getSkRect(const Rect& layer); inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds, - const FloatRect& crop, float cornerRadius); + const FloatRect& crop, + const vec2& cornerRadius); inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7c70a748b5..8889f76ccf 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -444,7 +444,9 @@ public: const ubyte4& backgroundColor) { const Rect casterRect(castingLayer.geometry.boundaries); Region casterRegion = Region(casterRect); - const float casterCornerRadius = castingLayer.geometry.roundedCornersRadius; + const float casterCornerRadius = (castingLayer.geometry.roundedCornersRadius.x + + castingLayer.geometry.roundedCornersRadius.y) / + 2.0; if (casterCornerRadius > 0.0f) { // ignore the corners if a corner radius is set Rect cornerRect(casterCornerRadius, casterCornerRadius); @@ -1129,7 +1131,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layer.geometry.boundaries = fullscreenRect().toFloatRect(); - layer.geometry.roundedCornersRadius = 5.0f; + layer.geometry.roundedCornersRadius = {5.0f, 5.0f}; layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; @@ -2131,7 +2133,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); - castingLayer.geometry.roundedCornersRadius = 3.0f; + castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f}; castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = @@ -2219,7 +2221,8 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2231,7 +2234,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings greenLayer; greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; greenLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - greenLayer.geometry.roundedCornersRadius = 5.0f; + greenLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; // Bottom right corner is not going to be rounded. greenLayer.geometry.roundedCornersCrop = Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT, @@ -2268,7 +2271,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2313,7 +2316,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32); - redLayer.geometry.roundedCornersRadius = 64; + redLayer.geometry.roundedCornersRadius = {64.0f, 64.0f}; redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2334,6 +2337,49 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255); } +TEST_P(RenderEngineTest, testRoundedCornersXY) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + initializeRenderEngine(); + + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + + std::vector<renderengine::LayerSettings> layers; + + renderengine::LayerSettings redLayer; + redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; + redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); + redLayer.geometry.roundedCornersRadius = {5.0f, 20.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); + // Red background. + redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); + redLayer.alpha = 1.0f; + + layers.push_back(redLayer); + + invokeDraw(settings, layers); + + // Due to roundedCornersRadius, the corners are untouched. + expectBufferColor(Point(0, 0), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0); + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + + // Y-axis draws a larger radius, check that its untouched as well + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 5), 0, 0, 0, 0); + expectBufferColor(Point(0, 5), 0, 0, 0, 0); + + // middle should be red + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255); +} + TEST_P(RenderEngineTest, testClear) { initializeRenderEngine(); |