Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46c1d036 authored by Cairn Overturf's avatar Cairn Overturf Committed by Android (Google) Code Review
Browse files

Merge "Fix shadows when device is rotated" into main

parents 33387f2e ee5b1fdb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -503,7 +503,7 @@ interface ISurfaceComposer {
     * lightRadius
     *      Radius of the light casting the shadow.
     */
    oneway void setGlobalShadowSettings(in Color ambientColor, in Color spotColor, float lightPosY, float lightPosZ, float lightRadius);
    void setGlobalShadowSettings(in Color ambientColor, in Color spotColor, float lightPosY, float lightPosZ, float lightRadius);

    /**
     * Gets whether a display supports DISPLAY_DECORATION layers.
+10 −3
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ static inline SkM44 getSkM44(const android::mat4& matrix) {
                 matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
}

[[maybe_unused]]
static inline SkPoint3 getSkPoint3(const android::vec3& vector) {
    return SkPoint3::Make(vector.x, vector.y, vector.z);
}
@@ -1370,10 +1371,16 @@ void SkiaRenderEngine::drawShadow(SkCanvas* canvas,
    const auto flags =
            settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;

    // DrawShadow expects the light pos in device space.
    // Shadow settings is in layer space (which is our current canvas transform).
    SkMatrix deviceFromLayer = canvas->getTotalMatrix();
    SkPoint lightPos = {settings.lightPos.x, settings.lightPos.y}; // lightPos is in layer space
    deviceFromLayer.mapPoints(&lightPos, 1);                       // lightPos is in device space

    SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
                              getSkPoint3(settings.lightPos), settings.lightRadius,
                              getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
                              flags);
                              SkPoint3{lightPos.fX, lightPos.fY, settings.lightPos.z},
                              settings.lightRadius, getSkColor(settings.ambientColor),
                              getSkColor(settings.spotColor), flags);
}

void SkiaRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
+13 −5
Original line number Diff line number Diff line
@@ -343,11 +343,19 @@ void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
        return;
    }

    // Shift the spot light x-position to the middle of the display and then
    // offset it by casting layer's screen pos.
    state.lightPos.x =
            (static_cast<float>(layerStackRect.width()) / 2.f) - mSnapshot->transformedBounds.left;
    state.lightPos.y -= mSnapshot->transformedBounds.top;
    // The light source should be at (screenWidth/2, globalShadowSettings.lightPos.y) in
    // screenspace.
    vec2 lightPosScreenSpace = {
            (static_cast<float>(layerStackRect.width()) / 2.f),
            state.lightPos.y,
    };

    // Skia expects light pos in layer space.
    vec2 lightPosLayerSpace = mSnapshot->geomInverseLayerTransform.transform(lightPosScreenSpace);

    state.lightPos.x = lightPosLayerSpace.x;
    state.lightPos.y = lightPosLayerSpace.y;

    caster.shadow = state;
}

+3 −0
Original line number Diff line number Diff line
@@ -8304,6 +8304,9 @@ status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, cons
    // these values are overridden when calculating the shadow settings for a layer.
    mCurrentState.globalShadowSettings.lightPos.x = 0.f;
    mCurrentState.globalShadowSettings.length = 0.f;

    setTransactionFlags(eTransactionNeeded);

    return NO_ERROR;
}

+76 −6
Original line number Diff line number Diff line
@@ -876,18 +876,24 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, CropElevationShadowByParent) {
    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::WHITE, parentSize, parentSize));
    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::BLUE, size, size));

    // TODO(b/377194534): This test fails on Tangor because global shadow
    // settings seem to not respect rotation.
    SurfaceComposerClient::getDefault()->setGlobalShadowSettings({1, 0, 0, 0.5f}, {0, 1, 0, 0.5f},
                                                                 0, 500.0f, 800.0f);
                                                                 0, 250.0f, 800.0f);

    // Global shadow settings are committed after snapshot updates so we have to perform a commit
    // before enabling layer shadows.
    Transaction().apply(true);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    ui::Size resolution = mRenderPathHarness.getRotatedResolution();
    int x = resolution.width / 2;
    int y = 500;

    Transaction()
            .setPosition(parent, x, y)
            .setCrop(parent, Rect(0, 0, parentSize / 2, parentSize))
            .reparent(child, parent)
            .setPosition(child, size, size)
            .setCrop(child, Rect(0, 0, size, size))
            .setPosition(child, size, size)
            .setCornerRadius(child, 20.0f)
@@ -896,7 +902,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, CropElevationShadowByParent) {

    auto shot = getScreenCapture();

    shot->expectBufferMatchesImageFromFile(Rect(0, 0, parentSize, parentSize),
    shot->expectBufferMatchesImageFromFile(Rect(x, y, x + parentSize, y + parentSize),
                                           "testdata/CropElevationShadowByParent.png");
}

@@ -1146,6 +1152,70 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
        shot->expectColor(crop, Color::RED);
    }
}

class RotatedVirtualDisplayTest
      : public LayerTypeTransactionHarness,
        public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath, ui::Rotation>> {
public:
    RotatedVirtualDisplayTest()
          : LayerTypeTransactionHarness(std::get<0>(GetParam())),
            mRenderPathHarness(this, std::get<1>(GetParam()), std::get<2>(GetParam())) {}

    std::unique_ptr<ScreenCapture> getScreenCapture() {
        return mRenderPathHarness.getScreenCapture();
    }

protected:
    LayerRenderPathTestHarness mRenderPathHarness;
};

INSTANTIATE_TEST_CASE_P(RotatedVirtualDisplayTests, RotatedVirtualDisplayTest,
                        ::testing::Combine(::testing::Values(static_cast<uint32_t>(
                                                   ISurfaceComposerClient::eFXSurfaceBufferState)),
                                           ::testing::Values(RenderPath::VIRTUAL_DISPLAY),
                                           ::testing::Values(ui::Rotation::Rotation0,
                                                             ui::Rotation::Rotation90,
                                                             ui::Rotation::Rotation180,
                                                             ui::Rotation::Rotation270)));

TEST_P(RotatedVirtualDisplayTest, ElevationShadowHasCorrectOrientation) {
    sp<SurfaceControl> parent;
    sp<SurfaceControl> child;
    const uint32_t size = 64;
    const uint32_t parentSize = size * 3;
    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::WHITE, parentSize, parentSize));
    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));

    SurfaceComposerClient::getDefault()->setGlobalShadowSettings({1, 0, 0, 1.0f}, {0, 1, 0, 1.0f},
                                                                 0, 500.0f, 800.0f);

    // Global shadow settings are committed after snapshot updates so we have to perform a commit
    // before enabling layer shadows.
    Transaction().apply(true);

    ui::Size resolution = mRenderPathHarness.getRotatedResolution();
    int x = resolution.width / 2;
    int y = 500;
    Transaction()
            .setPosition(parent, x, y)
            .setCrop(parent, Rect(0, 0, parentSize, parentSize))
            .reparent(child, parent)
            .setCrop(child, Rect(0, 0, size, size))
            .setPosition(child, size, size)
            .setCornerRadius(child, 20.0f)
            .setShadowRadius(child, 20.0f)
            .apply(true);

    auto shot = getScreenCapture();

    shot->expectBufferMatchesImageFromFile(mRenderPathHarness.rotateRect(
                                                   Rect(x, y, x + parentSize, y + parentSize)),
                                           "testdata/Shadow_" +
                                                   mRenderPathHarness.getRotationName() + ".png");
}

} // namespace android

// TODO(b/129481165): remove the #pragma below and fix conversion issues
Loading