Loading services/surfaceflinger/Layer.cpp +31 −10 Original line number Original line Diff line number Diff line Loading @@ -1915,27 +1915,48 @@ const std::vector<BlurRegion> Layer::getBlurRegions() const { } } Layer::RoundedCornerState Layer::getRoundedCornerState() const { Layer::RoundedCornerState Layer::getRoundedCornerState() const { const auto& p = mDrawingParent.promote(); // Get parent settings if (p != nullptr) { RoundedCornerState parentSettings; RoundedCornerState parentState = p->getRoundedCornerState(); const auto& parent = mDrawingParent.promote(); if (parentState.radius > 0) { if (parent != nullptr) { parentSettings = parent->getRoundedCornerState(); if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); t = t.inverse(); parentState.cropRect = t.transform(parentState.cropRect); parentSettings.cropRect = t.transform(parentSettings.cropRect); // The rounded corners shader only accepts 1 corner radius for performance reasons, // The rounded corners shader only accepts 1 corner radius for performance reasons, // but a transform matrix can define horizontal and vertical scales. // 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 // 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. // never do this type of transformation on windows anyway. auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); parentState.radius *= (scaleX + scaleY) / 2.0f; parentSettings.radius *= (scaleX + scaleY) / 2.0f; return parentState; } } } } // Get layer settings Rect layerCropRect = getCroppedBufferSize(getDrawingState()); const float radius = getDrawingState().cornerRadius; const float radius = getDrawingState().cornerRadius; return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); if (layerSettings.radius > 0 && parentSettings.radius > 0) { // If the parent and the layer have rounded corner settings, use the parent settings if the // parent crop is entirely inside the layer crop. // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. if (parentSettings.cropRect.left > layerCropRect.left && parentSettings.cropRect.top > layerCropRect.top && parentSettings.cropRect.right < layerCropRect.right && parentSettings.cropRect.bottom < layerCropRect.bottom) { return parentSettings; } else { return layerSettings; } } else if (layerSettings.radius > 0) { return layerSettings; } else if (parentSettings.radius > 0) { return parentSettings; } return {}; } } void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, Loading services/surfaceflinger/Layer.h +2 −4 Original line number Original line Diff line number Diff line Loading @@ -606,10 +606,8 @@ public: virtual bool getTransformToDisplayInverse() const { return false; } virtual bool getTransformToDisplayInverse() const { return false; } // Returns how rounded corners should be drawn for this layer. // Returns how rounded corners should be drawn for this layer. // This will traverse the hierarchy until it reaches its root, finding topmost rounded // A layer can override its parent's rounded corner settings if the parent's rounded // corner definition and converting it into current layer's coordinates. // corner crop does not intersect with its own rounded corner crop. // As of now, only 1 corner radius per display list is supported. Subsequent ones will be // ignored. virtual RoundedCornerState getRoundedCornerState() const; virtual RoundedCornerState getRoundedCornerState() const; bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } Loading services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +89 −0 Original line number Original line Diff line number Diff line Loading @@ -465,6 +465,95 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildBufferRotation } } } } TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) { sp<SurfaceControl> parent; sp<SurfaceControl> child; const uint32_t size = 64; const uint32_t parentSize = size * 3; const uint32_t testLength = 4; const float cornerRadius = 20.0f; ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); Transaction() .setCornerRadius(parent, cornerRadius) .setCornerRadius(child, cornerRadius) .reparent(child, parent) .setPosition(child, size, size) .apply(); { const uint32_t top = size - 1; const uint32_t left = size - 1; const uint32_t bottom = size * 2 - 1; const uint32_t right = size * 2 - 1; auto shot = getScreenCapture(); // Edges are transparent // TL shot->expectColor(Rect(left, top, testLength, testLength), Color::RED); // TR shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED); // BL shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), Color::RED); // BR shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED); // Solid center shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), Color::GREEN); } } // Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by // the child corner radius crop. TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) { sp<SurfaceControl> parent; sp<SurfaceControl> child; const uint32_t size = 64; const uint32_t parentSize = size * 3; const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1); const uint32_t testLength = 4; const float cornerRadius = 20.0f; ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); Transaction() .setCornerRadius(parent, cornerRadius) .setCrop(parent, parentCrop) .setCornerRadius(child, cornerRadius) .reparent(child, parent) .setPosition(child, size, size) .apply(); { const uint32_t top = size - 1; const uint32_t left = size - 1; const uint32_t bottom = size * 2 - 1; const uint32_t right = size * 2 - 1; auto shot = getScreenCapture(); // Edges are transparent // TL shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK); // TR shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK); // BL shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), Color::BLACK); // BR shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::BLACK); // Solid center shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), Color::GREEN); } } TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); Loading Loading
services/surfaceflinger/Layer.cpp +31 −10 Original line number Original line Diff line number Diff line Loading @@ -1915,27 +1915,48 @@ const std::vector<BlurRegion> Layer::getBlurRegions() const { } } Layer::RoundedCornerState Layer::getRoundedCornerState() const { Layer::RoundedCornerState Layer::getRoundedCornerState() const { const auto& p = mDrawingParent.promote(); // Get parent settings if (p != nullptr) { RoundedCornerState parentSettings; RoundedCornerState parentState = p->getRoundedCornerState(); const auto& parent = mDrawingParent.promote(); if (parentState.radius > 0) { if (parent != nullptr) { parentSettings = parent->getRoundedCornerState(); if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); t = t.inverse(); parentState.cropRect = t.transform(parentState.cropRect); parentSettings.cropRect = t.transform(parentSettings.cropRect); // The rounded corners shader only accepts 1 corner radius for performance reasons, // The rounded corners shader only accepts 1 corner radius for performance reasons, // but a transform matrix can define horizontal and vertical scales. // 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 // 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. // never do this type of transformation on windows anyway. auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); parentState.radius *= (scaleX + scaleY) / 2.0f; parentSettings.radius *= (scaleX + scaleY) / 2.0f; return parentState; } } } } // Get layer settings Rect layerCropRect = getCroppedBufferSize(getDrawingState()); const float radius = getDrawingState().cornerRadius; const float radius = getDrawingState().cornerRadius; return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); if (layerSettings.radius > 0 && parentSettings.radius > 0) { // If the parent and the layer have rounded corner settings, use the parent settings if the // parent crop is entirely inside the layer crop. // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. if (parentSettings.cropRect.left > layerCropRect.left && parentSettings.cropRect.top > layerCropRect.top && parentSettings.cropRect.right < layerCropRect.right && parentSettings.cropRect.bottom < layerCropRect.bottom) { return parentSettings; } else { return layerSettings; } } else if (layerSettings.radius > 0) { return layerSettings; } else if (parentSettings.radius > 0) { return parentSettings; } return {}; } } void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, Loading
services/surfaceflinger/Layer.h +2 −4 Original line number Original line Diff line number Diff line Loading @@ -606,10 +606,8 @@ public: virtual bool getTransformToDisplayInverse() const { return false; } virtual bool getTransformToDisplayInverse() const { return false; } // Returns how rounded corners should be drawn for this layer. // Returns how rounded corners should be drawn for this layer. // This will traverse the hierarchy until it reaches its root, finding topmost rounded // A layer can override its parent's rounded corner settings if the parent's rounded // corner definition and converting it into current layer's coordinates. // corner crop does not intersect with its own rounded corner crop. // As of now, only 1 corner radius per display list is supported. Subsequent ones will be // ignored. virtual RoundedCornerState getRoundedCornerState() const; virtual RoundedCornerState getRoundedCornerState() const; bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } Loading
services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +89 −0 Original line number Original line Diff line number Diff line Loading @@ -465,6 +465,95 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildBufferRotation } } } } TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) { sp<SurfaceControl> parent; sp<SurfaceControl> child; const uint32_t size = 64; const uint32_t parentSize = size * 3; const uint32_t testLength = 4; const float cornerRadius = 20.0f; ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); Transaction() .setCornerRadius(parent, cornerRadius) .setCornerRadius(child, cornerRadius) .reparent(child, parent) .setPosition(child, size, size) .apply(); { const uint32_t top = size - 1; const uint32_t left = size - 1; const uint32_t bottom = size * 2 - 1; const uint32_t right = size * 2 - 1; auto shot = getScreenCapture(); // Edges are transparent // TL shot->expectColor(Rect(left, top, testLength, testLength), Color::RED); // TR shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED); // BL shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), Color::RED); // BR shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED); // Solid center shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), Color::GREEN); } } // Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by // the child corner radius crop. TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) { sp<SurfaceControl> parent; sp<SurfaceControl> child; const uint32_t size = 64; const uint32_t parentSize = size * 3; const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1); const uint32_t testLength = 4; const float cornerRadius = 20.0f; ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize)); ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); Transaction() .setCornerRadius(parent, cornerRadius) .setCrop(parent, parentCrop) .setCornerRadius(child, cornerRadius) .reparent(child, parent) .setPosition(child, size, size) .apply(); { const uint32_t top = size - 1; const uint32_t left = size - 1; const uint32_t bottom = size * 2 - 1; const uint32_t right = size * 2 - 1; auto shot = getScreenCapture(); // Edges are transparent // TL shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK); // TR shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK); // BL shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength), Color::BLACK); // BR shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::BLACK); // Solid center shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2, parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2), Color::GREEN); } } TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceSupportsBlurs()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP(); Loading