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

Commit 6f54ae54 authored by Leon Scroggins's avatar Leon Scroggins Committed by Android (Google) Code Review
Browse files

Merge "Pass display's colorTransform to RE even if HW handles it"

parents 7b6e9fe1 745dcaac
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@ struct DisplaySettings {
    // dataspace, in non-linear space.
    mat4 colorTransform = mat4();

    // If true, and colorTransform is non-identity, most client draw calls can
    // ignore it. Some draws (e.g. screen decorations) may need it, though.
    bool deviceHandlesColorTransform = false;

    // An additional orientation flag to be applied after clipping the output.
    // By way of example, this may be used for supporting fullscreen screenshot
    // capture of a device in landscape while the buffer is in portrait
+34 −8
Original line number Diff line number Diff line
@@ -792,7 +792,7 @@ void SkiaGLRenderEngine::drawLayersInternal(

    // setup color filter if necessary
    sk_sp<SkColorFilter> displayColorTransform;
    if (display.colorTransform != mat4()) {
    if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
        displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
    }
    const bool ctModifiesAlpha =
@@ -1107,11 +1107,37 @@ void SkiaGLRenderEngine::drawLayersInternal(

            if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
                LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
                float matrix[] = { 0, 0, 0, 0, 0,
                                   0, 0, 0, 0, 0,
                                   0, 0, 0, 0, 0,
                                   0, 0, 0, -1, 1 };
                paint.setColorFilter(SkColorFilters::Matrix(matrix));

                // SysUI creates the alpha layer as a coverage layer, which is
                // appropriate for the DPU. Use a color matrix to convert it to
                // a mask.
                // TODO (b/219525258): Handle input as a mask.
                //
                // The color matrix will convert A8 pixels with no alpha to
                // black, as described by this vector. If the display handles
                // the color transform, we need to invert it to find the color
                // that will result in black after the DPU applies the transform.
                SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
                if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
                    SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
                    if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
                        black = colorSpaceMatrix * black;
                    } else {
                        // We'll just have to use 0,0,0 as black, which should
                        // be close to correct.
                        ALOGI("Could not invert colorTransform!");
                    }
                }
                SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
                                          0, 0, 0, 0, black[1],
                                          0, 0, 0, 0, black[2],
                                          0, 0, 0, -1, 1);
                if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
                    // On the other hand, if the device doesn't handle it, we
                    // have to apply it ourselves.
                    colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
                }
                paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
            }
        } else {
            ATRACE_NAME("DrawColor");
@@ -1134,8 +1160,8 @@ void SkiaGLRenderEngine::drawLayersInternal(
            paint.setBlendMode(SkBlendMode::kSrc);
        }

        // A color filter will have been set for an A8 buffer. Do not replace
        // it with the displayColorTransform, which shouldn't affect A8.
        // An A8 buffer will already have the proper color filter attached to
        // its paint, including the displayColorTransform as needed.
        if (!paint.getColorFilter()) {
            paint.setColorFilter(displayColorTransform);
        }
+139 −0
Original line number Diff line number Diff line
@@ -2627,6 +2627,7 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) {

    const auto r8Buffer = allocateR8Buffer(2, 1);
    if (!r8Buffer) {
        GTEST_SKIP() << "Test is only necessary on devices that support r8";
        return;
    }
    {
@@ -2677,6 +2678,144 @@ TEST_P(RenderEngineTest, r8_behaves_as_mask) {
    expectBufferColor(Rect(0, 0, 1, 1), 0,   0, 0, 255);
    expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
}

TEST_P(RenderEngineTest, r8_respects_color_transform) {
    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
        return;
    }

    initializeRenderEngine();

    const auto r8Buffer = allocateR8Buffer(2, 1);
    if (!r8Buffer) {
        GTEST_SKIP() << "Test is only necessary on devices that support r8";
        return;
    }
    {
        uint8_t* pixels;
        r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                                    reinterpret_cast<void**>(&pixels));
        pixels[0] = 0;
        pixels[1] = 255;
        r8Buffer->getBuffer()->unlock();
    }

    const auto rect = Rect(0, 0, 2, 1);
    const renderengine::DisplaySettings display{
            .physicalDisplay = rect,
            .clip = rect,
            .outputDataspace = ui::Dataspace::SRGB,
            // Verify that the R8 layer respects the color transform when
            // deviceHandlesColorTransform is false. This transform converts
            // pure red to pure green. That will occur when the R8 buffer is
            // 255. When the R8 buffer is 0, it will still change to black, as
            // with r8_behaves_as_mask.
            .colorTransform = mat4(0, 1, 0, 0,
                                   0, 0, 0, 0,
                                   0, 0, 1, 0,
                                   0, 0, 0, 1),
            .deviceHandlesColorTransform = false,
    };

    const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
    const renderengine::LayerSettings redLayer{
            .geometry.boundaries = rect.toFloatRect(),
            .source =
                    renderengine::PixelSource{
                            .buffer =
                                    renderengine::Buffer{
                                            .buffer = redBuffer,
                                    },
                    },
            .alpha = 1.0f,
    };
    const renderengine::LayerSettings r8Layer{
            .geometry.boundaries = rect.toFloatRect(),
            .source =
                    renderengine::PixelSource{
                            .buffer =
                                    renderengine::Buffer{
                                            .buffer = r8Buffer,
                                    },
                    },
            .alpha = 1.0f,
    };

    std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
    invokeDraw(display, layers);

    expectBufferColor(Rect(0, 0, 1, 1), 0,   0, 0, 255);
    expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
}

TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
        return;
    }

    initializeRenderEngine();

    const auto r8Buffer = allocateR8Buffer(2, 1);
    if (!r8Buffer) {
        GTEST_SKIP() << "Test is only necessary on devices that support r8";
        return;
    }
    {
        uint8_t* pixels;
        r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                                    reinterpret_cast<void**>(&pixels));
        pixels[0] = 0;
        pixels[1] = 255;
        r8Buffer->getBuffer()->unlock();
    }

    const auto rect = Rect(0, 0, 2, 1);
    const renderengine::DisplaySettings display{
            .physicalDisplay = rect,
            .clip = rect,
            .outputDataspace = ui::Dataspace::SRGB,
            // If deviceHandlesColorTransform is true, pixels where the A8
            // buffer is opaque are unaffected. If the colorTransform is
            // invertible, pixels where the A8 buffer are transparent have the
            // inverse applied to them so that the DPU will convert them back to
            // black. Test with an arbitrary, invertible matrix.
            .colorTransform = mat4(1, 0, 0, 2,
                                   3, 1, 2, 5,
                                   0, 5, 3, 0,
                                   0, 1, 0, 2),
            .deviceHandlesColorTransform = true,
    };

    const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
    const renderengine::LayerSettings redLayer{
            .geometry.boundaries = rect.toFloatRect(),
            .source =
                    renderengine::PixelSource{
                            .buffer =
                                    renderengine::Buffer{
                                            .buffer = redBuffer,
                                    },
                    },
            .alpha = 1.0f,
    };
    const renderengine::LayerSettings r8Layer{
            .geometry.boundaries = rect.toFloatRect(),
            .source =
                    renderengine::PixelSource{
                            .buffer =
                                    renderengine::Buffer{
                                            .buffer = r8Buffer,
                                    },
                    },
            .alpha = 1.0f,
    };

    std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
    invokeDraw(display, layers);

    expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red.
    expectBufferColor(Rect(0, 0, 1, 1), 0,  70, 0, 255);
}
} // namespace renderengine
} // namespace android

+3 −3
Original line number Diff line number Diff line
@@ -1079,9 +1079,9 @@ std::optional<base::unique_fd> Output::composeSurfaces(
    clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;

    // Compute the global color transform matrix.
    if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
    clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
    }
    clientCompositionDisplay.deviceHandlesColorTransform =
            outputState.usesDeviceComposition || getSkipColorTransform();

    // Generate the client composition requests for the layers on this output.
    std::vector<LayerFE*> clientCompositionLayersFE;
+10 −4
Original line number Diff line number Diff line
@@ -3487,7 +3487,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi
                                            .maxLuminance = kDefaultMaxLuminance,
                                            .currentLuminanceNits = kDefaultMaxLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = mat4(),
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = true,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()
@@ -3505,7 +3506,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
                                            .maxLuminance = kDefaultMaxLuminance,
                                            .currentLuminanceNits = kDisplayLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = mat4(),
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = true,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()
@@ -3522,7 +3524,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp
                                            .maxLuminance = kDefaultMaxLuminance,
                                            .currentLuminanceNits = kDefaultMaxLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = mat4(),
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = true,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()
@@ -3540,6 +3543,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo
                                            .currentLuminanceNits = kDefaultMaxLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = false,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()
@@ -3557,6 +3561,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien
                                            .currentLuminanceNits = kDefaultMaxLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = false,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()
@@ -3574,7 +3579,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
                                            .maxLuminance = kDefaultMaxLuminance,
                                            .currentLuminanceNits = kDefaultMaxLuminance,
                                            .outputDataspace = kDefaultOutputDataspace,
                                            .colorTransform = mat4(),
                                            .colorTransform = kDefaultColorTransformMat,
                                            .deviceHandlesColorTransform = true,
                                            .orientation = kDefaultOutputOrientationFlags,
                                            .targetLuminanceNits = kClientTargetLuminanceNits})
            .execute()