Skip to content

Commit 8bdb01e

Browse files
cairno-googleAndroid (Google) Code Review
authored andcommitted
Merge "Crop shadows by parent layer crop" into main
2 parents ea6f56d + f0102c9 commit 8bdb01e

File tree

8 files changed

+131
-54
lines changed

8 files changed

+131
-54
lines changed

libs/renderengine/include/renderengine/LayerSettings.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ struct Geometry {
9393

9494
// Rectangle within which corners will be rounded.
9595
FloatRect roundedCornersCrop = FloatRect();
96+
97+
// Crop geometry in local space, used for cropping outset rendering, e.g. shadows.
98+
vec2 otherRoundedCornersRadius = vec2(0.0f, 0.0f);
99+
FloatRect otherCrop = FloatRect();
96100
};
97101

98102
// Descriptor of the source pixels for this layer.
@@ -228,6 +232,12 @@ static inline void PrintTo(const Geometry& settings, ::std::ostream* os) {
228232
*os << "\n .roundedCornersRadiusY = " << settings.roundedCornersRadius.y;
229233
*os << "\n .roundedCornersCrop = ";
230234
PrintTo(settings.roundedCornersCrop, os);
235+
236+
*os << "\n .otherRoundedCornersRadiusX = " << settings.otherRoundedCornersRadius.x;
237+
*os << "\n .otherRoundedCornersRadiusY = " << settings.otherRoundedCornersRadius.y;
238+
*os << "\n .otherCrop = ";
239+
PrintTo(settings.otherCrop, os);
240+
231241
*os << "\n}";
232242
}
233243

libs/renderengine/skia/SkiaRenderEngine.cpp

Lines changed: 71 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ void SkiaRenderEngine::drawLayersInternal(
887887
const auto [bounds, roundRectClip] =
888888
getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
889889
layer.geometry.roundedCornersRadius);
890+
890891
if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
891892
std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
892893

@@ -963,66 +964,82 @@ void SkiaRenderEngine::drawLayersInternal(
963964
}
964965
}
965966

966-
if (layer.shadow.length > 0) {
967-
// This would require a new parameter/flag to SkShadowUtils::DrawShadow
968-
LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
969-
970-
SkRRect shadowBounds, shadowClip;
971-
if (layer.geometry.boundaries == layer.shadow.boundaries) {
972-
shadowBounds = bounds;
973-
shadowClip = roundRectClip;
974-
} else {
975-
std::tie(shadowBounds, shadowClip) =
976-
getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
977-
layer.geometry.roundedCornersRadius);
967+
{
968+
SkRRect otherCrop;
969+
otherCrop.setRectXY(getSkRect(layer.geometry.otherCrop),
970+
layer.geometry.otherRoundedCornersRadius.x,
971+
layer.geometry.otherRoundedCornersRadius.y);
972+
// Outset rendering needs to be clipped by parent.
973+
SkAutoCanvasRestore acr(canvas, true);
974+
if (!otherCrop.isEmpty()) {
975+
canvas->clipRRect(otherCrop, true);
978976
}
979977

980-
// Technically, if bounds is a rect and roundRectClip is not empty,
981-
// it means that the bounds and roundedCornersCrop were different
982-
// enough that we should intersect them to find the proper shadow.
983-
// In practice, this often happens when the two rectangles appear to
984-
// not match due to rounding errors. Draw the rounded version, which
985-
// looks more like the intent.
986-
const auto& rrect =
987-
shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
988-
drawShadow(canvas, rrect, layer.shadow);
989-
}
978+
if (layer.shadow.length > 0) {
979+
// This would require a new parameter/flag to SkShadowUtils::DrawShadow
980+
LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
981+
982+
SkRRect shadowBounds, shadowClip;
983+
if (layer.geometry.boundaries == layer.shadow.boundaries) {
984+
shadowBounds = bounds;
985+
shadowClip = roundRectClip;
986+
} else {
987+
std::tie(shadowBounds, shadowClip) =
988+
getBoundsAndClip(layer.shadow.boundaries,
989+
layer.geometry.roundedCornersCrop,
990+
layer.geometry.roundedCornersRadius);
991+
}
990992

991-
// TODO(b/367464660): Move this code above and
992-
// update elevation shadow rendering to use these bounds since they should be
993-
// identical.
994-
SkRRect originalBounds, originalClip;
995-
std::tie(originalBounds, originalClip) =
996-
getBoundsAndClip(layer.geometry.originalBounds, layer.geometry.roundedCornersCrop,
997-
layer.geometry.roundedCornersRadius);
998-
const SkRRect& preferredOriginalBounds =
999-
originalBounds.isRect() && !originalClip.isEmpty() ? originalClip : originalBounds;
993+
// Technically, if bounds is a rect and roundRectClip is not empty,
994+
// it means that the bounds and roundedCornersCrop were different
995+
// enough that we should intersect them to find the proper shadow.
996+
// In practice, this often happens when the two rectangles appear to
997+
// not match due to rounding errors. Draw the rounded version, which
998+
// looks more like the intent.
999+
const auto& rrect =
1000+
shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
1001+
drawShadow(canvas, rrect, layer.shadow);
1002+
}
10001003

1001-
// Similar to shadows, do the rendering before the clip is applied because even when the
1002-
// layer is occluded it should have an outline.
1003-
if (layer.borderSettings.strokeWidth > 0) {
1004-
SkRRect outlineRect = preferredOriginalBounds;
1005-
outlineRect.outset(layer.borderSettings.strokeWidth, layer.borderSettings.strokeWidth);
1004+
// TODO(b/367464660): Move this code above and
1005+
// update elevation shadow rendering to use these bounds since they should be
1006+
// identical.
1007+
SkRRect originalBounds, originalClip;
1008+
std::tie(originalBounds, originalClip) =
1009+
getBoundsAndClip(layer.geometry.originalBounds,
1010+
layer.geometry.roundedCornersCrop,
1011+
layer.geometry.roundedCornersRadius);
1012+
const SkRRect& preferredOriginalBounds =
1013+
originalBounds.isRect() && !originalClip.isEmpty() ? originalClip
1014+
: originalBounds;
1015+
1016+
// Similar to shadows, do the rendering before the clip is applied because even when the
1017+
// layer is occluded it should have an outline.
1018+
if (layer.borderSettings.strokeWidth > 0) {
1019+
SkRRect outlineRect = preferredOriginalBounds;
1020+
outlineRect.outset(layer.borderSettings.strokeWidth,
1021+
layer.borderSettings.strokeWidth);
10061022

1007-
SkPaint paint;
1008-
paint.setAntiAlias(true);
1009-
paint.setColor(layer.borderSettings.color);
1010-
paint.setStyle(SkPaint::kFill_Style);
1011-
canvas->drawDRRect(outlineRect, preferredOriginalBounds, paint);
1012-
}
1023+
SkPaint paint;
1024+
paint.setAntiAlias(true);
1025+
paint.setColor(layer.borderSettings.color);
1026+
paint.setStyle(SkPaint::kFill_Style);
1027+
canvas->drawDRRect(outlineRect, preferredOriginalBounds, paint);
1028+
}
10131029

1014-
if (!layer.boxShadowSettings.boxShadows.empty()) {
1015-
for (const gui::BoxShadowSettings::BoxShadowParams& box :
1016-
layer.boxShadowSettings.boxShadows) {
1017-
SkRRect boxRect = preferredOriginalBounds;
1018-
boxRect.outset(box.spreadRadius, box.spreadRadius);
1019-
boxRect.offset(box.offsetX, box.offsetY);
1020-
float sigma = convertBlurUserRadiusToSigma(box.blurRadius);
1021-
SkPaint blur;
1022-
blur.setAntiAlias(true);
1023-
blur.setColor(box.color);
1024-
blur.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, false));
1025-
canvas->drawRRect(boxRect, blur);
1030+
if (!layer.boxShadowSettings.boxShadows.empty()) {
1031+
for (const gui::BoxShadowSettings::BoxShadowParams& box :
1032+
layer.boxShadowSettings.boxShadows) {
1033+
SkRRect boxRect = preferredOriginalBounds;
1034+
boxRect.outset(box.spreadRadius, box.spreadRadius);
1035+
boxRect.offset(box.offsetX, box.offsetY);
1036+
float sigma = convertBlurUserRadiusToSigma(box.blurRadius);
1037+
SkPaint blur;
1038+
blur.setAntiAlias(true);
1039+
blur.setColor(box.color);
1040+
blur.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, false));
1041+
canvas->drawRRect(boxRect, blur);
1042+
}
10261043
}
10271044
}
10281045

services/surfaceflinger/FrontEnd/LayerSnapshot.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState {
7676
bool contentOpaque;
7777
bool layerOpaqueFlagSet;
7878
RoundedCornerState roundedCorner;
79+
// roundedCorner of the parent but in local space.
80+
RoundedCornerState parentRoundedCorner;
81+
// geomLayerCrop of the parent but in local space.
82+
FloatRect parentGeomLayerCrop;
83+
7984
FloatRect transformedBounds;
8085
Rect transformedBoundsWithoutTransparentRegion;
8186
bool premultipliedAlpha;

services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,8 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot,
10481048
} else {
10491049
snapshot.roundedCorner.radius = snapshot.roundedCorner.requestedRadius;
10501050
}
1051+
1052+
snapshot.parentRoundedCorner = parentRoundedCorner;
10511053
}
10521054

10531055
/**
@@ -1134,6 +1136,9 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot,
11341136
requested.getTransparentRegion());
11351137
snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
11361138
}
1139+
1140+
snapshot.parentGeomLayerCrop =
1141+
snapshot.localTransform.inverse().transform(parentSnapshot.geomLayerCrop);
11371142
}
11381143

11391144
void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const RequestedLayerState&,

services/surfaceflinger/LayerFE.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientC
124124
SFTRACE_CALL();
125125
compositionengine::LayerFE::LayerSettings layerSettings;
126126
layerSettings.geometry.originalBounds = mSnapshot->geomLayerBounds;
127+
128+
if (mSnapshot->parentRoundedCorner.hasRequestedRadius()) {
129+
layerSettings.geometry.otherRoundedCornersRadius = mSnapshot->parentRoundedCorner.radius;
130+
layerSettings.geometry.otherCrop = mSnapshot->parentRoundedCorner.cropRect;
131+
} else {
132+
layerSettings.geometry.otherCrop = mSnapshot->parentGeomLayerCrop;
133+
}
134+
127135
layerSettings.geometry.boundaries =
128136
reduce(mSnapshot->geomLayerBounds, mSnapshot->transparentRegionHint);
129137
layerSettings.geometry.positionTransform = mSnapshot->geomLayerTransform.asMatrix4();

services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,38 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBoxShadowSettings) {
868868
}
869869
}
870870

871+
TEST_P(LayerTypeAndRenderTypeTransactionTest, CropElevationShadowByParent) {
872+
sp<SurfaceControl> parent;
873+
sp<SurfaceControl> child;
874+
const uint32_t size = 64;
875+
const uint32_t parentSize = size * 3;
876+
ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
877+
ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::WHITE, parentSize, parentSize));
878+
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
879+
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
880+
881+
// TODO(b/377194534): This test fails on Tangor because global shadow
882+
// settings seem to not respect rotation.
883+
SurfaceComposerClient::getDefault()->setGlobalShadowSettings({1, 0, 0, 0.5f}, {0, 1, 0, 0.5f},
884+
0, 500.0f, 800.0f);
885+
886+
std::this_thread::sleep_for(std::chrono::seconds(1));
887+
888+
Transaction()
889+
.setCrop(parent, Rect(0, 0, parentSize / 2, parentSize))
890+
.reparent(child, parent)
891+
.setCrop(child, Rect(0, 0, size, size))
892+
.setPosition(child, size, size)
893+
.setCornerRadius(child, 20.0f)
894+
.setShadowRadius(child, 20.0f)
895+
.apply(true);
896+
897+
auto shot = getScreenCapture();
898+
899+
shot->expectBufferMatchesImageFromFile(Rect(0, 0, parentSize, parentSize),
900+
"testdata/CropElevationShadowByParent.png");
901+
}
902+
871903
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
872904
if (!deviceSupportsBlurs()) GTEST_SKIP();
873905
if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP();
2.91 KB
Loading
-354 Bytes
Loading

0 commit comments

Comments
 (0)