Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/core/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 24 kB image not shown  

Quelle  SkKnownRuntimeEffects.cpp

  Sprache: C
 

/*
 * Copyright 2024 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "src/core/SkKnownRuntimeEffects.h"

#include "include/core/SkString.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/private/base/SkAssert.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/effects/imagefilters/SkMatrixConvolutionImageFilter.h"

namespace SkKnownRuntimeEffects {

namespace {

SkRuntimeEffect::Options get_options(StableKey stableKey) {
    SkRuntimeEffect::Options options;
    SkRuntimeEffectPriv::SetStableKeyOnOptions(&options, static_cast<uint32_t>(stableKey));
    SkRuntimeEffectPriv::AllowPrivateAccess(&options);
    return options;
}

// This must be kept in sync w/ the version in BlurUtils.h
static constexpr int kMaxBlurSamples = 28;

SkRuntimeEffect* make_blur_1D_shader(int kernelWidth, StableKey stableKey) {
    SkRuntimeEffect::Options options = get_options(stableKey);

    SkASSERT(kernelWidth <= kMaxBlurSamples);
    // The SkSL structure performs two kernel taps; if the kernel has an odd width the last
    // sample will be skipped with the current loop limit calculation.
    SkASSERT(kernelWidth % 2 == 0);
    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
            SkStringPrintf(
                    // The coefficients are always stored for the max radius to keep the
                    // uniform block consistent across all effects.
                    "const int kMaxUniformKernelSize = %d / 2;"
                    // But we generate an exact loop over the kernel size. Note that this
                    // program can be used for kernels smaller than the constructed max as long
                    // as the kernel weights for excess entries are set to 0.
                    "const int kMaxLoopLimit = %d / 2;"

                    "uniform half4 offsetsAndKernel[kMaxUniformKernelSize];"
                    "uniform half2 dir;"

                    "uniform shader child;"

                    "half4 main(float2 coord) {"
                        "half4 sum = half4(0);"
                        "for (int i = 0; i < kMaxLoopLimit; ++i) {"
                            "half4 s = offsetsAndKernel[i];"
                            "sum += s.y * child.eval(coord + s.x*dir);"
                            "sum += s.w * child.eval(coord + s.z*dir);"
                        "}"
                        "return sum;"
                    "}", kMaxBlurSamples, kernelWidth).c_str(),
                    options);
}

SkRuntimeEffect* make_blur_2D_shader(int maxKernelSize, StableKey stableKey) {
    SkRuntimeEffect::Options options = get_options(stableKey);

    SkASSERT(maxKernelSize % 4 == 0);
    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
            SkStringPrintf(
                    // The coefficients are always stored for the max radius to keep the
                    // uniform block consistent across all effects.
                    "const int kMaxUniformKernelSize = %d / 4;"
                    "const int kMaxUniformOffsetsSize = 2*kMaxUniformKernelSize;"
                    // But we generate an exact loop over the kernel size. Note that this
                    // program can be used for kernels smaller than the constructed max as long
                    // as the kernel weights for excess entries are set to 0.
                    "const int kMaxLoopLimit = %d / 4;"

                    // Pack scalar coefficients into half4 for better packing on std140, and
                    // upload offsets to avoid having to transform the 1D index into a 2D coord
                    "uniform half4 kernel[kMaxUniformKernelSize];"
                    "uniform half4 offsets[kMaxUniformOffsetsSize];"

                    "uniform shader child;"

                    "half4 main(float2 coord) {"
                        "half4 sum = half4(0);"

                        "for (int i = 0; i < kMaxLoopLimit; ++i) {"
                            "half4 k = kernel[i];"
                            "half4 o = offsets[2*i];"
                            "sum += k.x * child.eval(coord + o.xy);"
                            "sum += k.y * child.eval(coord + o.zw);"
                            "o = offsets[2*i + 1];"
                            "sum += k.z * child.eval(coord + o.xy);"
                            "sum += k.w * child.eval(coord + o.zw);"
                        "}"
                        "return sum;"
                    "}", kMaxBlurSamples, maxKernelSize).c_str(),
                    options);
}

SkRuntimeEffect* make_blend_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kBlend);

    static constexpr char kBlendShaderCode[] =
        "uniform shader s, d;"
        "uniform blender b;"
        "half4 main(float2 xy) {"
            "return b.eval(s.eval(xy), d.eval(xy));"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kBlendShaderCode,
                               options);
}

SkRuntimeEffect* make_lerp_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kLerp);

    static constexpr char kLerpFilterCode[] =
        "uniform colorFilter cf0;"
        "uniform colorFilter cf1;"
        "uniform half weight;"

        "half4 main(half4 color) {"
            "return mix(cf0.eval(color), cf1.eval(color), weight);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                               kLerpFilterCode,
                               options);
}

enum class MatrixConvolutionImpl {
    kUniformBased,
    kTextureBasedSm,
    kTextureBasedLg,
};

// There are three shader variants:
//    a smaller kernel version that stores the matrix in uniforms and iterates in 1D
//    a larger kernel version that stores the matrix in a 1D texture. The texture version has small
//    and large variants w/ the actual kernel size uploaded as a uniform.
SkRuntimeEffect* make_matrix_conv_shader(MatrixConvolutionImpl impl, StableKey stableKey) {
    SkRuntimeEffect::Options options = get_options(stableKey);

    // While the uniforms and kernel access are different, pieces of the algorithm are common and
    // defined statically for re-use in the two shaders:
    static const char* kHeaderAndBeginLoopSkSL =
        "uniform int2 size;"
        "uniform int2 offset;"
        "uniform half2 gainAndBias;"
        "uniform int convolveAlpha;" // FIXME not a full  int? Put in a half3 w/ gainAndBias?

        "uniform shader child;"

        "half4 main(float2 coord) {"
            "half4 sum = half4(0);"
            "half origAlpha = 0;"
            "int2 kernelPos = int2(0);"
            "for (int i = 0; i < kMaxKernelSize; ++i) {"
                "if (kernelPos.y >= size.y) { break; }";

    // Used in the inner loop to accumulate convolution sum and increment the kernel position
    static const char* kAccumulateAndIncrementSkSL =
                "half4 c = child.eval(coord + half2(kernelPos) - half2(offset));"
                "if (convolveAlpha == 0) {"
                    // When not convolving alpha, remember the original alpha for actual sample
                    // coord, and perform accumulation on unpremul colors.
                    "if (kernelPos == offset) {"
                        "origAlpha = c.a;"
                    "}"
                    "c = unpremul(c);"
                "}"
                "sum += c*k;"
                "kernelPos.x += 1;"
                "if (kernelPos.x >= size.x) {"
                    "kernelPos.x = 0;"
                    "kernelPos.y += 1;"
                "}";

    // Closes the loop and calculates final color
    static const char* kCloseLoopAndFooterSkSL =
            "}"
            "half4 color = sum*gainAndBias.x + gainAndBias.y;"
            "if (convolveAlpha == 0) {"
                // Reset the alpha to the original and convert to premul RGB
                "color = half4(color.rgb*origAlpha, origAlpha);"
            "} else {"
                // Ensure convolved alpha is within [0, 1]
                "color.a = saturate(color.a);"
            "}"
            // Make RGB valid premul w/ respect to the alpha (either original or convolved)
            "color.rgb = clamp(color.rgb, 0, color.a);"
            "return color;"
        "}";

    static const auto makeTextureEffect = [](int maxTextureKernelSize,
                                             const SkRuntimeEffect::Options& options) {
        return SkMakeRuntimeEffect(
                        SkRuntimeEffect::MakeForShader,
                        SkStringPrintf("const int kMaxKernelSize = %d;"
                                       "uniform shader kernel;"
                                       "uniform half2 innerGainAndBias;"
                                       "%s" // kHeaderAndBeginLoopSkSL
                                               "half k = kernel.eval(half2(half(i) + 0.5, 0.5)).a;"
                                               "k = k * innerGainAndBias.x + innerGainAndBias.y;"
                                               "%s" // kAccumulateAndIncrementSkSL
                                       "%s"// kCloseLoopAndFooterSkSL
                                       maxTextureKernelSize,
                                       kHeaderAndBeginLoopSkSL,
                                       kAccumulateAndIncrementSkSL,
                                       kCloseLoopAndFooterSkSL).c_str(),
                        options);
    };

    switch (impl) {
        case MatrixConvolutionImpl::kUniformBased: {
            return SkMakeRuntimeEffect(
                        SkRuntimeEffect::MakeForShader,
                        SkStringPrintf("const int kMaxKernelSize = %d / 4;"
                                       "uniform half4 kernel[kMaxKernelSize];"
                                       "%s" // kHeaderAndBeginLoopSkSL
                                                "half4 k4 = kernel[i];"
                                                "for (int j = 0; j < 4; ++j) {"
                                                    "if (kernelPos.y >= size.y) { break; }"
                                                    "half k = k4[j];"
                                                    "%s" // kAccumulateAndIncrementSkSL
                                                "}"
                                       "%s"// kCloseLoopAndFooterSkSL
                                       MatrixConvolutionImageFilter::kMaxUniformKernelSize,
                                       kHeaderAndBeginLoopSkSL,
                                       kAccumulateAndIncrementSkSL,
                                       kCloseLoopAndFooterSkSL).c_str(),
                        options);
        }
        case MatrixConvolutionImpl::kTextureBasedSm:
            return makeTextureEffect(MatrixConvolutionImageFilter::kSmallKernelSize, options);
        case MatrixConvolutionImpl::kTextureBasedLg:
            return makeTextureEffect(MatrixConvolutionImageFilter::kLargeKernelSize, options);
    }

    SkUNREACHABLE;
}

SkRuntimeEffect* make_decal_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kDecal);

    static constexpr char kDecalShaderCode[] =
        "uniform shader image;"
        "uniform float4 decalBounds;"

        "half4 main(float2 coord) {"
            "return sk_decal(image, coord, decalBounds);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kDecalShaderCode,
                               options);
}

SkRuntimeEffect* make_displacement_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kDisplacement);

    // NOTE: This uses dot product selection to work on all GLES2 hardware (enforced by
    // public runtime effect restrictions). Otherwise, this would use a "uniform ivec2"
    // and component indexing to convert the displacement color into a vector.
    static constexpr char kDisplacementShaderCode[] =
        "uniform shader displMap;"
        "uniform shader colorMap;"
        "uniform half2 scale;"
        "uniform half4 xSelect;" // Only one of RGBA will be 1, the rest are 0
        "uniform half4 ySelect;"

        "half4 main(float2 coord) {"
            "return sk_displacement(displMap, colorMap, coord, scale, xSelect, ySelect);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kDisplacementShaderCode,
                               options);
}

SkRuntimeEffect* make_lighting_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kLighting);

   static constexpr char kLightingShaderCode[] =
        "uniform shader normalMap;"

        // Packs surface depth, shininess, material type (0 == diffuse) and light type
        // (< 0 = distant, 0 = point, > 0 = spot)
        "uniform half4 materialAndLightType;"

        "uniform half4 lightPosAndSpotFalloff;" // (x,y,z) are lightPos, w is spot falloff
                                                // exponent
        "uniform half4 lightDirAndSpotCutoff;" // (x,y,z) are lightDir,
                                               // w is spot cos(cutoffAngle)
        "uniform half3 lightColor;" // Material's k has already been multiplied in

        "half4 main(float2 coord) {"
            "return sk_lighting(normalMap, coord,"
                                /*depth=*/"materialAndLightType.x,"
                                /*shininess=*/"materialAndLightType.y,"
                                /*materialType=*/"materialAndLightType.z,"
                                /*lightType=*/"materialAndLightType.w,"
                                /*lightPos=*/"lightPosAndSpotFalloff.xyz,"
                                /*spotFalloff=*/"lightPosAndSpotFalloff.w,"
                                /*lightDir=*/"lightDirAndSpotCutoff.xyz,"
                                /*cosCutoffAngle=*/"lightDirAndSpotCutoff.w,"
                                "lightColor);"
        "}";

   return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                              kLightingShaderCode,
                              options);
}

SkRuntimeEffect* make_linear_morphology_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kLinearMorphology);

    static constexpr char kLinearMorphologyShaderCode[] =
        "uniform shader child;"
        "uniform half2 offset;"
        "uniform half flip;" // -1 converts the max() calls to min()
        "uniform int radius;"

        "half4 main(float2 coord) {"
            "return sk_linear_morphology(child, coord, offset, flip, radius);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kLinearMorphologyShaderCode,
                               options);
}

SkRuntimeEffect* make_magnifier_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kMagnifier);

    static constexpr char kMagnifierShaderCode[] =
        "uniform shader src;"
        "uniform float4 lensBounds;"
        "uniform float4 zoomXform;"
        "uniform float2 invInset;"

        "half4 main(float2 coord) {"
            "return sk_magnifier(src, coord, lensBounds, zoomXform, invInset);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kMagnifierShaderCode,
                               options);
}

SkRuntimeEffect* make_normal_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kNormal);

    static constexpr char kNormalShaderCode[] =
        "uniform shader alphaMap;"
        "uniform float4 edgeBounds;"
        "uniform half negSurfaceDepth;"

        "half4 main(float2 coord) {"
           "return sk_normal(alphaMap, coord, edgeBounds, negSurfaceDepth);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kNormalShaderCode,
                               options);
}

SkRuntimeEffect* make_sparse_morphology_shader() {
    SkRuntimeEffect::Options options = get_options(StableKey::kSparseMorphology);

    static constexpr char kSparseMorphologyShaderCode[] =
        "uniform shader child;"
        "uniform half2 offset;"
        "uniform half flip;"

        "half4 main(float2 coord) {"
            "return sk_sparse_morphology(child, coord, offset, flip);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                               kSparseMorphologyShaderCode,
                               options);
}

SkRuntimeEffect* make_arithmetic_blender() {
    SkRuntimeEffect::Options options = get_options(StableKey::kArithmetic);

    static constexpr char kArithmeticBlenderCode[] =
        "uniform half4 k;"
        "uniform half pmClamp;"

        "half4 main(half4 src, half4 dst) {"
            "return sk_arithmetic_blend(src, dst, k, pmClamp);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender,
                               kArithmeticBlenderCode,
                               options);
}

SkRuntimeEffect* make_high_contrast_color_filter() {
    SkRuntimeEffect::Options options = get_options(StableKey::kHighContrast);

    static constexpr char kHighContrastFilterCode[] =
        "uniform half grayscale, invertStyle, contrast;"
        "half4 main(half4 color) {"
            "return half4(sk_high_contrast(color.rgb, grayscale, invertStyle, contrast), color.a);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                               kHighContrastFilterCode,
                               options);
}

SkRuntimeEffect* make_luma_color_filter() {
    SkRuntimeEffect::Options options = get_options(StableKey::kLuma);

    static constexpr char kLumaFilterCode[] =
        "half4 main(half4 color) {"
            "return sk_luma(color.rgb);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                               kLumaFilterCode,
                               options);
}

SkRuntimeEffect* make_overdraw_color_filter() {
    SkRuntimeEffect::Options options = get_options(StableKey::kOverdraw);

    static constexpr char kOverdrawFilterCode[] =
        "uniform half4 color0, color1, color2, color3, color4, color5;"

        "half4 main(half4 color) {"
            "return sk_overdraw(color.a, color0, color1, color2, color3, color4, color5);"
        "}";

    return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                               kOverdrawFilterCode,
                               options);
}

// anonymous namespace

bool IsSkiaKnownRuntimeEffect(int candidate) {
    return (candidate >= static_cast<int>(StableKey::kStart) &&
            candidate <= static_cast<int>(StableKey::kLast));
}

bool IsUserDefinedRuntimeEffect(int candidate) {
    return candidate >= kUnknownRuntimeEffectIDStart;
}

bool IsViableUserDefinedKnownRuntimeEffect(int candidate) {
    return candidate >= kUserDefinedKnownRuntimeEffectsStart &&
           candidate < kUserDefinedKnownRuntimeEffectsEnd;
}

sk_sp<SkRuntimeEffect> MaybeGetKnownRuntimeEffect(uint32_t candidate) {
    if (IsSkiaKnownRuntimeEffect(candidate)) {
        SkKnownRuntimeEffects::StableKey stableKey =
                static_cast<SkKnownRuntimeEffects::StableKey>(candidate);

        return sk_ref_sp(GetKnownRuntimeEffect(stableKey));
    }

    return nullptr;
}

const SkRuntimeEffect* GetKnownRuntimeEffect(StableKey stableKey) {
    switch (stableKey) {
        case StableKey::kInvalid:
            return nullptr;

        // Shaders
        case StableKey::k1DBlur4: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(4, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur8: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(8, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur12: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(12, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur16: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(16, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur20: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(20, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur28: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_shader(28, stableKey);
            return s1DBlurEffect;
        }
        case StableKey::k2DBlur4: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(4, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur8: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(8, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur12: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(12, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur16: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(16, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur20: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(20, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur28: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_shader(28, stableKey);
            return s2DBlurEffect;
        }
        case StableKey::kBlend: {
            static const SkRuntimeEffect* sBlendEffect = make_blend_shader();
            return sBlendEffect;
        }
        case StableKey::kLerp: {
            static const SkRuntimeEffect* sLerpEffect = make_lerp_shader();
            return sLerpEffect;
        }
        case StableKey::kMatrixConvUniforms: {
            static const SkRuntimeEffect* sMatrixConvUniformsEffect =
                    make_matrix_conv_shader(MatrixConvolutionImpl::kUniformBased, stableKey);
            return sMatrixConvUniformsEffect;
        }
        case StableKey::kMatrixConvTexSm: {
            static const SkRuntimeEffect* sMatrixConvTexSmEffect =
                    make_matrix_conv_shader(MatrixConvolutionImpl::kTextureBasedSm, stableKey);
            return sMatrixConvTexSmEffect;
        }
        case StableKey::kMatrixConvTexLg: {
            static const SkRuntimeEffect* sMatrixConvTexMaxEffect =
                    make_matrix_conv_shader(MatrixConvolutionImpl::kTextureBasedLg, stableKey);
            return sMatrixConvTexMaxEffect;
        }
        case StableKey::kDecal: {
            static const SkRuntimeEffect* sDecalEffect = make_decal_shader();
            return sDecalEffect;
        }
        case StableKey::kDisplacement: {
            static const SkRuntimeEffect* sDisplacementEffect = make_displacement_shader();
            return sDisplacementEffect;
        }
        case StableKey::kLighting: {
            static const SkRuntimeEffect* sLightingEffect = make_lighting_shader();
            return sLightingEffect;
        }
        case StableKey::kLinearMorphology: {
            static const SkRuntimeEffect* sLinearMorphologyEffect = make_linear_morphology_shader();
            return sLinearMorphologyEffect;
        }
        case StableKey::kMagnifier: {
            static const SkRuntimeEffect* sMagnifierEffect = make_magnifier_shader();
            return sMagnifierEffect;
        }
        case StableKey::kNormal: {
            static const SkRuntimeEffect* sNormalEffect = make_normal_shader();
            return sNormalEffect;
        }
        case StableKey::kSparseMorphology: {
            static const SkRuntimeEffect* sSparseMorphologyEffect = make_sparse_morphology_shader();
            return sSparseMorphologyEffect;
        }

        // Blenders
        case StableKey::kArithmetic: {
            static const SkRuntimeEffect* sArithmeticEffect = make_arithmetic_blender();
            return sArithmeticEffect;
        }

        // Color Filters
        case StableKey::kHighContrast: {
            static const SkRuntimeEffect* sHighContrastEffect = make_high_contrast_color_filter();
            return sHighContrastEffect;
        }
        case StableKey::kLuma: {
            static const SkRuntimeEffect* sLumaEffect = make_luma_color_filter();
            return sLumaEffect;
        }
        case StableKey::kOverdraw: {
            static const SkRuntimeEffect* sOverdrawEffect = make_overdraw_color_filter();
            return sOverdrawEffect;
        }
    }

    SkUNREACHABLE;
}

// namespace SkKnownRuntimeEffects

Messung V0.5 in Prozent
C=90 H=100 G=95

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.