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

Commit 2901a278 authored by Robert Phillips's avatar Robert Phillips
Browse files

Add PaintOptionsBuilder

This duplicates Skia's PaintOptionsBuilder w/in Android. The PaintOptionsBuilder serves to reduce the amount of boiler-plate needed to create Precompilation PaintOptions.

Test: Tested w/in Skia in the AndroidPrecompileTest

Flag: EXEMPT bug fix
Bug: b/390186667

Change-Id: I8332d14ef0e408fe33df67c0bc2e133e2e9e3fc8
parent 4e0f0bbc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ filegroup {
        "skia/compat/GraphiteBackendTexture.cpp",
        "skia/compat/GraphiteGpuContext.cpp",
        "skia/compat/GraphitePipelineManager.cpp",
        "skia/compat/PaintOptionsBuilder.cpp",
        "skia/debug/CaptureTimer.cpp",
        "skia/debug/CommonPool.cpp",
        "skia/debug/SkiaCapture.cpp",
+73 −273
Original line number Diff line number Diff line
@@ -31,12 +31,13 @@

#include <type_traits>

#include "PaintOptionsBuilder.h"
#include "skia/filters/RuntimeEffectManager.h"

namespace android::renderengine::skia {

using namespace skgpu::graphite;

using namespace PaintOptionsUtils;
using PrecompileShaders::ImageShaderFlags;

using ::skgpu::graphite::DrawTypeFlags;
@@ -151,239 +152,6 @@ skgpu::graphite::PaintOptions LinearEffect(sk_sp<SkRuntimeEffect> linearEffect,
// NOTE: keep in sync with upstream external/skia/tests/graphite/precompile/PrecompileTestUtils.cpp
// clang-format off

PaintOptions SolidSrcover() {
    PaintOptions paintOptions;
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions SolidMatrixCFSrcover() {
    PaintOptions paintOptions;

    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });

    return paintOptions;
}

PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setPaintColorIsOpaque(false);
    return paintOptions;
}

PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFDitherSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setPaintColorIsOpaque(false);
    paintOptions.setDither(true);
    return paintOptions;
}

PaintOptions TransparentPaintImageSRGBHWOnlyMatrixCFDitherSrcover() {
    SkColorInfo ci { kRGBA_8888_SkColorType,
                     kPremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };

    PaintOptions paintOptions;

    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setPaintColorIsOpaque(false);
    paintOptions.setDither(true);
    return paintOptions;
}

PaintOptions TransparentPaintImagePremulHWOnlySrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setPaintColorIsOpaque(false);
    return paintOptions;
}

PaintOptions TransparentPaintImageSRGBHWOnlySrcover() {
    SkColorInfo ci { kRGBA_8888_SkColorType,
                     kPremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };

    PaintOptions paintOptions;

    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setPaintColorIsOpaque(false);
    return paintOptions;
}

PaintOptions SolidSrcSrcover() {
    PaintOptions paintOptions;
    paintOptions.setBlendModes({ SkBlendMode::kSrc, SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImagePremulHWOnlySrc() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setBlendModes({ SkBlendMode::kSrc });
    return paintOptions;
}

PaintOptions ImagePremulHWOnlySrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImageAlphaPremulHWOnlyMatrixCFSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImageAlphaSRGBHWOnlyMatrixCFSrcover() {
    // Note: this is different from the other SRGB ColorInfos
    SkColorInfo ci { kAlpha_8_SkColorType,
                     kUnpremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };

    PaintOptions paintOptions;

    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImageAlphaClampNoCubicSrc() {
    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
    SkTileMode tm = SkTileMode::kClamp;

    PaintOptions paintOptions;
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       { &tm, 1 }) });
    paintOptions.setBlendModes({ SkBlendMode::kSrc });
    return paintOptions;
}

PaintOptions ImagePremulHWOnlyMatrixCFSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImageSRGBHWOnlyMatrixCFSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType,
                     kPremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };

    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

PaintOptions ImagePremulHWOnlyMatrixCFDitherSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setDither(true);

    return paintOptions;
}

PaintOptions ImageSRGBHWOnlyMatrixCFDitherSrcover() {
    SkColorInfo ci { kRGBA_8888_SkColorType,
                     kPremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };

    PaintOptions paintOptions;

    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });
    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    paintOptions.setDither(true);

    return paintOptions;
}

PaintOptions ImageHWOnlySRGBSrcover() {
    PaintOptions paintOptions;

    SkColorInfo ci { kRGBA_8888_SkColorType,
                     kPremul_SkAlphaType,
                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
                                           SkNamedGamut::kAdobeRGB) };
    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                       { &ci, 1 },
                                                       {}) });

    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
    return paintOptions;
}

// TODO(b/426601394): Update this to take an SkColorInfo for the input image.
// The other MouriMap* precompile paint options should use a linear SkColorInfo
// derived from this same input image.
@@ -805,75 +573,105 @@ void GraphitePipelineManager::PrecompilePipelines(
    // external/skia/tests/graphite/precompile/AndroidPrecompileTest.cpp
    // clang-format off
    const PrecompileSettings precompileCases[] = {
/*  0 */ { ImagePremulHWOnlySrcover(),         DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D },
/*  1 */ { ImagePremulHWOnlySrcover(),
         { Builder().hwImg(kPremul).srcOver(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA16F_1_D },

         { Builder().hwImg(kPremul).srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },

/*  2 */ { ImagePremulHWOnlySrcover(),         kRRectAndNonAARect,              kRGBA_4_DS },
         { Builder().hwImg(kPremul).srcOver(),
           kRRectAndNonAARect,
           kRGBA_4_DS },

         { Builder().hwImg(kSRGB).srcOver(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA16F_1_D_SRGB },

/*  3 */ { ImageHWOnlySRGBSrcover(),           DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D_SRGB },
/*  4 */ { ImageHWOnlySRGBSrcover(),
         { Builder().hwImg(kSRGB).srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D_SRGB,
           kWithAnalyticClip },

/*  5 */ { TransparentPaintImagePremulHWOnlySrcover(),
         { Builder().transparent().hwImg(kPremul).srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },
/*  6 */ { TransparentPaintImagePremulHWOnlySrcover(), kRRectAndNonAARect,      kRGBA_4_DS },

/*  7 */ { TransparentPaintImageSRGBHWOnlySrcover(), kRRectAndNonAARect,        kRGBA_1_D_SRGB },
         { Builder().transparent().hwImg(kPremul).srcOver(),
           kRRectAndNonAARect,
           kRGBA_4_DS },

         { Builder().transparent().hwImg(kSRGB).srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D_SRGB },

/*  8 */ { SolidSrcSrcover(),
         { Builder().src().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },

/*  9 */ { SolidSrcover(),                     kRRectAndNonAARect,              kRGBA_4_DS },
         { Builder().srcOver(),
           kRRectAndNonAARect,
           kRGBA_4_DS },

/* 10 */ { ImagePremulHWOnlyMatrixCFSrcover(),
         { Builder().hwImg(kPremul).matrixCF().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },

/* 11 */ { TransparentPaintImagePremulHWOnlyMatrixCFSrcover(),
         { Builder().transparent().hwImg(kPremul).matrixCF().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },

/* 12 */ { TransparentPaintImagePremulHWOnlyMatrixCFDitherSrcover(),
                                               kRRectAndNonAARect,              kRGBA_1_D },
/* 13 */ { TransparentPaintImagePremulHWOnlyMatrixCFDitherSrcover(),
                                               DrawTypeFlags::kNonAAFillRect,   kRGBA_4_DS },
         { Builder().transparent().hwImg(kPremul).matrixCF().dither().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D },

         { Builder().transparent().hwImg(kPremul).matrixCF().dither().srcOver(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA_4_DS },

/* 14 */ { ImagePremulHWOnlyMatrixCFDitherSrcover(),
         { Builder().hwImg(kPremul).matrixCF().dither().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D,
           kWithAnalyticClip },

/* 15 */ { ImagePremulHWOnlyMatrixCFDitherSrcover(), DrawTypeFlags::kNonAAFillRect, kRGBA_4_DS },
         { Builder().hwImg(kPremul).matrixCF().dither().srcOver(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA_4_DS },

/* 16 */ { TransparentPaintImageSRGBHWOnlyMatrixCFDitherSrcover(),
         { Builder().transparent().hwImg(kSRGB).matrixCF().dither().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D_SRGB },

/* 17 */ { ImageSRGBHWOnlyMatrixCFDitherSrcover(),
         { Builder().hwImg(kSRGB).matrixCF().dither().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D_SRGB,
           kWithAnalyticClip },

/* 18 */ { ImageSRGBHWOnlyMatrixCFDitherSrcover(), DrawTypeFlags::kAnalyticRRect, kRGBA_4_DS_SRGB },
         { Builder().hwImg(kSRGB).matrixCF().dither().srcOver(),
           DrawTypeFlags::kAnalyticRRect,
           kRGBA_4_DS_SRGB },

/* 19 */ { ImageAlphaSRGBHWOnlyMatrixCFSrcover(),
         { Builder().hwImg(kAlphaSRGB).matrixCF().srcOver(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA_1D_4DS_SRGB },

/* 20 */ { ImagePremulHWOnlySrc(),             kRRectAndNonAARect,              kRGBA_1_D },
/* 21 */ { ImagePremulHWOnlySrc(),             DrawTypeFlags::kPerEdgeAAQuad,   kRGBA_1_D },
/* 22 */ { ImagePremulHWOnlySrc(),             DrawTypeFlags::kNonAAFillRect,   kRGBA_4_DS },
         { Builder().hwImg(kPremul).src(),
           kRRectAndNonAARect,
           kRGBA_1_D },

         { Builder().hwImg(kPremul).src(),
           DrawTypeFlags::kPerEdgeAAQuad,
           kRGBA_1_D },

         { Builder().hwImg(kPremul).src(),
           DrawTypeFlags::kNonAAFillRect,
           kRGBA_4_DS },

// TODO(b/426601394): Group these paint option settings into a function that accepts an input
// image color space so that the intermediate linear color spaces adapt correctly.
@@ -944,18 +742,20 @@ void GraphitePipelineManager::PrecompilePipelines(
           DrawTypeFlags::kAnalyticRRect,
           kRGBA_1_D_SRGB },

/* 38 */ { SolidSrcover(), DrawTypeFlags::kNonSimpleShape, kRGBA_4_DS },
         { Builder().srcOver(),
           DrawTypeFlags::kNonSimpleShape,
           kRGBA_4_DS },

// AnalyticClip block - all the PrecompileOptions here are just clones of earlier ones
// with an additional kAnalyticClip flag

// Note: this didn't get folded into #2 since the RRect draw isn't appearing w/ a clip
/* 39 */ { ImagePremulHWOnlySrcover(),
         { Builder().hwImg(kPremul).srcOver(),
           DrawTypeFlags::kNonAAFillRect | DrawTypeFlags::kAnalyticClip,
           kRGBA_4_DS },

// Note: this didn't get folded into #9 since the RRect draw isn't appearing w/ a clip
/* 40 */ { SolidSrcSrcover(),
         { Builder().src().srcOver(),
           DrawTypeFlags::kNonAAFillRect | DrawTypeFlags::kAnalyticClip,
           kRGBA_4_DS },

@@ -986,11 +786,11 @@ void GraphitePipelineManager::PrecompilePipelines(
           kRGBA_1_D,
           kWithAnalyticClip },

/* 47 */ { ImageAlphaClampNoCubicSrc(),
         { Builder().hwImg(kAlpha, kClamp).src(),
           DrawTypeFlags::kNonAAFillRect,
           kR_1_D },

/* 48 */ { ImageSRGBHWOnlyMatrixCFSrcover(),
         { Builder().hwImg(kSRGB).matrixCF().srcOver(),
           kRRectAndNonAARect,
           kRGBA_1_D_SRGB },

+139 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// NOTE: keep in sync with upstream external/skia/tests/graphite/precompile/PaintOptionsBuilder.cpp

#include "PaintOptionsBuilder.h"

#include <include/gpu/graphite/precompile/PrecompileColorFilter.h>
#include <include/gpu/graphite/precompile/PrecompileShader.h>

namespace android::renderengine::skia {

namespace PaintOptionsUtils {

using namespace skgpu::graphite;
using PrecompileShaders::GradientShaderFlags;
using PrecompileShaders::ImageShaderFlags;
using PrecompileShaders::YUVImageShaderFlags;

Builder& Builder::hwImg(ImgColorInfo ci, ImgTileModeOptions tmOptions) {
    static const SkColorInfo kAlphaInfo(kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr);
    static const SkColorInfo kAlphaSRGBInfo(kAlpha_8_SkColorType, kUnpremul_SkAlphaType,
                                            SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
                                                                  SkNamedGamut::kAdobeRGB));
    static const SkColorInfo kPremulInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
    static const SkColorInfo kSRGBInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
                                       SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
                                                             SkNamedGamut::kAdobeRGB));

    SkSpan<const SkColorInfo> ciSpan;
    switch (ci) {
        case kAlpha:
            ciSpan = {&kAlphaInfo, 1};
            break;
        case kAlphaSRGB:
            ciSpan = {&kAlphaSRGBInfo, 1};
            break;
        case kPremul:
            ciSpan = {&kPremulInfo, 1};
            break;
        case kSRGB:
            ciSpan = {&kSRGBInfo, 1};
            break;
    }

    static const SkTileMode kClampTM = SkTileMode::kClamp;
    static const SkTileMode kRepeatTM = SkTileMode::kRepeat;

    SkSpan<const SkTileMode> tmSpan;
    switch (tmOptions) {
        case kNone:
            break;
        case kClamp:
            tmSpan = {&kClampTM, 1};
            break;
        case kRepeat:
            tmSpan = {&kRepeatTM, 1};
            break;
    }

    sk_sp<PrecompileShader> img =
            PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic, ciSpan, tmSpan);
    fPaintOptions.setShaders({std::move(img)});
    return *this;
}

Builder& Builder::yuv(YUVSamplingOptions options) {
    static const SkColorInfo kSRGBInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType,
                                       SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
                                                             SkNamedGamut::kAdobeRGB));

    YUVImageShaderFlags flags = YUVImageShaderFlags::kNone;
    switch (options) {
        case kNoCubic:
            flags = YUVImageShaderFlags::kExcludeCubic;
            break;
        case kHWAndShader:
            flags = YUVImageShaderFlags::kNoCubicNoNonSwizzledHW;
            break;
    }

    sk_sp<PrecompileShader> img = PrecompileShaders::YUVImage(flags, {&kSRGBInfo, 1});
    fPaintOptions.setShaders({std::move(img)});
    return *this;
}

Builder& Builder::linearGrad(LinearGradientOptions options) {
    sk_sp<PrecompileShader> gradient;

    if (options == kSmall) {
        gradient = PrecompileShaders::LinearGradient(GradientShaderFlags::kSmall);
    } else if (options == kComplex) {
        gradient = PrecompileShaders::
                LinearGradient(GradientShaderFlags::kNoLarge,
                               {SkGradientShader::Interpolation::InPremul::kNo,
                                SkGradientShader::Interpolation::ColorSpace::kSRGB,
                                SkGradientShader::Interpolation::HueMethod::kShorter});
    }

    fPaintOptions.setShaders({std::move(gradient)});
    return *this;
}

Builder& Builder::blend() {
    SkColorInfo ci{kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr};
    sk_sp<PrecompileShader> img =
            PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic, {&ci, 1}, {});
    SkBlendMode kBlendModes = SkBlendMode::kPlus;
    fPaintOptions.setShaders({PrecompileShaders::Blend({&kBlendModes, 1}, {std::move(img)},
                                                       {PrecompileShaders::Color()})});
    return *this;
}

Builder& Builder::matrixCF() {
    fPaintOptions.setColorFilters({PrecompileColorFilters::Matrix()});
    return *this;
}

Builder& Builder::porterDuffCF() {
    fPaintOptions.setColorFilters({PrecompileColorFilters::Blend({SkBlendMode::kSrcOver})});
    return *this;
}

} // namespace PaintOptionsUtils

} // namespace android::renderengine::skia
+98 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// NOTE: keep in sync with upstream external/skia/tests/graphite/precompile/PaintOptionsBuilder.h

#ifndef PaintOptionsBuilder_DEFINED
#define PaintOptionsBuilder_DEFINED

#include <include/gpu/graphite/precompile/PaintOptions.h>

namespace android::renderengine::skia {

namespace PaintOptionsUtils {

enum ImgColorInfo {
    kAlpha,
    kAlphaSRGB,
    kPremul,
    kSRGB,
};

enum ImgTileModeOptions {
    kNone,
    kClamp,
    kRepeat,
};

// This enum directly maps to YUVImageShaderFlags but, crucially, is more compact.
enum YUVSamplingOptions {
    kNoCubic,     // YUVImageShaderFlags::kExcludeCubic
    kHWAndShader, // YUVImageShaderFlags::kNoCubicNoNonSwizzledHW
};

enum LinearGradientOptions {
    kSmall,
    kComplex, // idiosyncratic case - c.f. Builder::linearGrad
};

// This is a minimal builder object that allows for compact construction of the most common
// PaintOptions combinations - eliminating a lot of boilerplate.
class Builder {
public:
    Builder() {}

    // Shaders
    Builder& hwImg(ImgColorInfo ci, ImgTileModeOptions tmOptions = kNone);
    Builder& yuv(YUVSamplingOptions options);
    Builder& linearGrad(LinearGradientOptions options);
    Builder& blend();

    // ColorFilters
    Builder& matrixCF();
    Builder& porterDuffCF();

    // Blendmodes
    Builder& clear() { return this->addBlendMode(SkBlendMode::kClear); }
    Builder& dstIn() { return this->addBlendMode(SkBlendMode::kDstIn); }
    Builder& src() { return this->addBlendMode(SkBlendMode::kSrc); }
    Builder& srcOver() { return this->addBlendMode(SkBlendMode::kSrcOver); }

    // Misc settings
    Builder& transparent() {
        fPaintOptions.setPaintColorIsOpaque(false);
        return *this;
    }
    Builder& dither() {
        fPaintOptions.setDither(true);
        return *this;
    }

    operator skgpu::graphite::PaintOptions() const { return fPaintOptions; }

private:
    skgpu::graphite::PaintOptions fPaintOptions;

    Builder& addBlendMode(SkBlendMode bm) {
        fPaintOptions.addBlendMode(bm);
        return *this;
    }
};

} // namespace PaintOptionsUtils

} // namespace android::renderengine::skia
#endif // PaintOptionsBuilder_DEFINED