Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


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 "src/core/SkRuntimeEffectPriv.h"
#include "src/effects/imagefilters/SkMatrixConvolutionImageFilter.h"

namespace SkKnownRuntimeEffects {

namespace {

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

SkRuntimeEffect* make_blur_1D_effect(int kernelWidth, const SkRuntimeEffect::Options& options) {
    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_effect(int maxKernelSize, const SkRuntimeEffect::Options& options) {
    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);
}

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_effect(MatrixConvolutionImpl impl,
                                         const SkRuntimeEffect::Options& options) {
    // 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;
}

// anonymous namespace

const SkRuntimeEffect* GetKnownRuntimeEffect(StableKey stableKey) {
    SkRuntimeEffect::Options options;
    SkRuntimeEffectPriv::SetStableKey(&options, static_cast<uint32_t>(stableKey));
    SkRuntimeEffectPriv::AllowPrivateAccess(&options);

    switch (stableKey) {
        case StableKey::kInvalid:
            return nullptr;

        // Shaders
        case StableKey::k1DBlur4: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(4, options);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur8: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(8, options);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur12: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(12, options);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur16: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(16, options);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur20: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(20, options);
            return s1DBlurEffect;
        }
        case StableKey::k1DBlur28: {
            static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(28, options);
            return s1DBlurEffect;
        }
        case StableKey::k2DBlur4: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(4, options);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur8: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(8, options);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur12: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(12, options);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur16: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(16, options);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur20: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(20, options);
            return s2DBlurEffect;
        }
        case StableKey::k2DBlur28: {
            static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(28, options);
            return s2DBlurEffect;
        }
        case 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));"
                "}";

            static const SkRuntimeEffect* sBlendEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kBlendShaderCode,
                                        options);
            return sBlendEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sLerpEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                                        kLerpFilterCode,
                                        options);
            return sLerpEffect;
        }
        case StableKey::kMatrixConvUniforms: {
            static const SkRuntimeEffect* sMatrixConvUniformsEffect =
                    make_matrix_conv_effect(MatrixConvolutionImpl::kUniformBased, options);
            return sMatrixConvUniformsEffect;
        }

        case StableKey::kMatrixConvTexSm: {
            static const SkRuntimeEffect* sMatrixConvTexSmEffect =
                    make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedSm, options);
            return sMatrixConvTexSmEffect;
        }

        case StableKey::kMatrixConvTexLg: {
            static const SkRuntimeEffect* sMatrixConvTexMaxEffect =
                    make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedLg, options);
            return sMatrixConvTexMaxEffect;
        }
        case StableKey::kDecal: {
            static constexpr char kDecalShaderCode[] =
                "uniform shader image;"
                "uniform float4 decalBounds;"

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

            static const SkRuntimeEffect* sDecalEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kDecalShaderCode,
                                        options);
            return sDecalEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sDisplacementEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kDisplacementShaderCode,
                                        options);
            return sDisplacementEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sLightingEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kLightingShaderCode,
                                        options);
            return sLightingEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sLinearMorphologyEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kLinearMorphologyShaderCode,
                                        options);
            return sLinearMorphologyEffect;
        }

        case 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);"
                "}";

            static const SkRuntimeEffect* sMagnifierEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kMagnifierShaderCode,
                                        options);
            return sMagnifierEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sNormalEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kNormalShaderCode,
                                        options);
            return sNormalEffect;
        }
        case 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);"
                "}";

            static const SkRuntimeEffect* sSparseMorphologyEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
                                        kSparseMorphologyShaderCode,
                                        options);
            return sSparseMorphologyEffect;
        }

        // Blenders
        case 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);"
                "}";

            static const SkRuntimeEffect* sArithmeticEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender,
                                        kArithmeticBlenderCode,
                                        options);
            return sArithmeticEffect;
        }

        // Color Filters
        case 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);"
                "}";

            static const SkRuntimeEffect* sHighContrastEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                                        kHighContrastFilterCode,
                                        options);
            return sHighContrastEffect;
        }

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

            static const SkRuntimeEffect* sLumaEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                                        kLumaFilterCode,
                                        options);
            return sLumaEffect;
        }

        case 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);"
                "}";

            static const SkRuntimeEffect* sOverdrawEffect =
                    SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
                                        kOverdrawFilterCode,
                                        options);
            return sOverdrawEffect;
        }
    }

    SkUNREACHABLE;
}

// namespace SkKnownRuntimeEffects

Messung V0.5
C=91 H=94 G=92

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge