tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SkRuntimeShader.cpp (7423B)


      1 /*
      2 * Copyright 2023 Google LLC
      3 *
      4 * Use of this source code is governed by a BSD-style license that can be
      5 * found in the LICENSE file.
      6 */
      7 #include "src/shaders/SkRuntimeShader.h"
      8 
      9 #include "include/core/SkCapabilities.h"
     10 #include "include/core/SkData.h"
     11 #include "include/core/SkMatrix.h"
     12 #include "include/core/SkShader.h"
     13 #include "include/core/SkString.h"
     14 #include "include/effects/SkRuntimeEffect.h"
     15 #include "include/private/SkSLSampleUsage.h"
     16 #include "include/private/base/SkAssert.h"
     17 #include "include/private/base/SkDebug.h"
     18 #include "include/private/base/SkTArray.h"
     19 #include "include/sksl/SkSLDebugTrace.h"
     20 #include "src/base/SkTLazy.h"
     21 #include "src/core/SkEffectPriv.h"
     22 #include "src/core/SkKnownRuntimeEffects.h"
     23 #include "src/core/SkPicturePriv.h"
     24 #include "src/core/SkReadBuffer.h"
     25 #include "src/core/SkRuntimeEffectPriv.h"
     26 #include "src/core/SkWriteBuffer.h"
     27 #include "src/shaders/SkShaderBase.h"
     28 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
     29 #include "src/sksl/tracing/SkSLDebugTracePriv.h"
     30 
     31 #include <cstdint>
     32 #include <optional>
     33 #include <string>
     34 #include <utility>
     35 
     36 #if defined(SK_BUILD_FOR_DEBUGGER)
     37    constexpr bool kLenientSkSLDeserialization = true;
     38 #else
     39    constexpr bool kLenientSkSLDeserialization = false;
     40 #endif
     41 
     42 class SkColorSpace;
     43 struct SkIPoint;
     44 
     45 SkRuntimeShader::SkRuntimeShader(sk_sp<SkRuntimeEffect> effect,
     46                                 sk_sp<SkSL::DebugTracePriv> debugTrace,
     47                                 sk_sp<const SkData> uniforms,
     48                                 SkSpan<const SkRuntimeEffect::ChildPtr> children)
     49        : fEffect(std::move(effect))
     50        , fDebugTrace(std::move(debugTrace))
     51        , fUniformData(std::move(uniforms))
     52        , fChildren(children.begin(), children.end()) {}
     53 
     54 SkRuntimeShader::SkRuntimeShader(sk_sp<SkRuntimeEffect> effect,
     55                                 sk_sp<SkSL::DebugTracePriv> debugTrace,
     56                                 UniformsCallback uniformsCallback,
     57                                 SkSpan<const SkRuntimeEffect::ChildPtr> children)
     58        : fEffect(std::move(effect))
     59        , fDebugTrace(std::move(debugTrace))
     60        , fUniformsCallback(std::move(uniformsCallback))
     61        , fChildren(children.begin(), children.end()) {}
     62 
     63 static sk_sp<SkSL::DebugTracePriv> make_debug_trace(SkRuntimeEffect* effect,
     64                                                    const SkIPoint& coord) {
     65    auto debugTrace = sk_make_sp<SkSL::DebugTracePriv>();
     66    debugTrace->setSource(effect->source());
     67    debugTrace->setTraceCoord(coord);
     68    return debugTrace;
     69 }
     70 
     71 SkRuntimeEffect::TracedShader SkRuntimeShader::makeTracedClone(const SkIPoint& coord) {
     72    sk_sp<SkRuntimeEffect> unoptimized = fEffect->makeUnoptimizedClone();
     73    sk_sp<SkSL::DebugTracePriv> debugTrace = make_debug_trace(unoptimized.get(), coord);
     74    auto debugShader = sk_make_sp<SkRuntimeShader>(
     75            unoptimized, debugTrace, this->uniformData(nullptr), SkSpan(fChildren));
     76 
     77    return SkRuntimeEffect::TracedShader{std::move(debugShader), std::move(debugTrace)};
     78 }
     79 
     80 bool SkRuntimeShader::appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const {
     81    if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
     82        // SkRP has support for many parts of #version 300 already, but for now, we restrict its
     83        // usage in runtime effects to just #version 100.
     84        return false;
     85    }
     86    if (const SkSL::RP::Program* program = fEffect->getRPProgram(fDebugTrace.get())) {
     87        std::optional<SkShaders::MatrixRec> newMRec = mRec.apply(rec);
     88        if (!newMRec.has_value()) {
     89            return false;
     90        }
     91        SkSpan<const float> uniforms =
     92                SkRuntimeEffectPriv::UniformsAsSpan(fEffect->uniforms(),
     93                                                    this->uniformData(rec.fDstCS),
     94                                                    /*alwaysCopyIntoAlloc=*/fUniformData == nullptr,
     95                                                    rec.fDstCS,
     96                                                    rec.fAlloc);
     97        RuntimeEffectRPCallbacks callbacks(rec, *newMRec, fChildren, fEffect->fSampleUsages);
     98        bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
     99        return success;
    100    }
    101    return false;
    102 }
    103 
    104 sk_sp<const SkData> SkRuntimeShader::uniformData(const SkColorSpace* dstCS) const {
    105    if (fUniformData) {
    106        return fUniformData;
    107    }
    108 
    109    // We want to invoke the uniforms-callback each time a paint occurs.
    110    SkASSERT(fUniformsCallback);
    111    sk_sp<const SkData> uniforms = fUniformsCallback({dstCS});
    112    SkASSERT(uniforms && uniforms->size() == fEffect->uniformSize());
    113    return uniforms;
    114 }
    115 
    116 void SkRuntimeShader::flatten(SkWriteBuffer& buffer) const {
    117    if (SkKnownRuntimeEffects::IsSkiaKnownRuntimeEffect(fEffect->fStableKey)) {
    118        // We only serialize Skia-internal stableKeys. First party stable keys are not serialized.
    119        buffer.write32(fEffect->fStableKey);
    120    } else {
    121        buffer.write32(0);
    122        buffer.writeString(fEffect->source().c_str());
    123    }
    124    buffer.writeDataAsByteArray(this->uniformData(nullptr).get());
    125    SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
    126 }
    127 
    128 sk_sp<SkFlattenable> SkRuntimeShader::CreateProc(SkReadBuffer& buffer) {
    129    if (!buffer.validate(buffer.allowSkSL())) {
    130        return nullptr;
    131    }
    132 
    133    sk_sp<SkRuntimeEffect> effect;
    134    if (!buffer.isVersionLT(SkPicturePriv::kSerializeStableKeys)) {
    135        uint32_t candidateStableKey = buffer.readUInt();
    136        effect = SkKnownRuntimeEffects::MaybeGetKnownRuntimeEffect(candidateStableKey);
    137        if (!effect && !buffer.validate(candidateStableKey == 0)) {
    138            return nullptr;
    139        }
    140    }
    141 
    142    if (!effect) {
    143        SkString sksl;
    144        buffer.readString(&sksl);
    145        effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForShader, std::move(sksl));
    146    }
    147    if constexpr (!kLenientSkSLDeserialization) {
    148        if (!buffer.validate(effect != nullptr)) {
    149            return nullptr;
    150        }
    151    }
    152 
    153    sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
    154 
    155    std::optional<SkMatrix> localM;
    156    if (buffer.isVersionLT(SkPicturePriv::kNoShaderLocalMatrix)) {
    157        uint32_t flags = buffer.read32();
    158        if (flags & kHasLegacyLocalMatrix_Flag) {
    159            buffer.readMatrix(&localM.emplace());
    160        }
    161    }
    162 
    163    skia_private::STArray<4, SkRuntimeEffect::ChildPtr> children;
    164    if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
    165        return nullptr;
    166    }
    167 
    168    if constexpr (kLenientSkSLDeserialization) {
    169        if (!effect) {
    170            // If any children were SkShaders, return the first one. This is a reasonable fallback.
    171            for (int i = 0; i < children.size(); i++) {
    172                if (children[i].shader()) {
    173                    SkDebugf("Serialized SkSL failed to compile. Replacing shader with child %d.\n",
    174                             i);
    175                    return sk_ref_sp(children[i].shader());
    176                }
    177            }
    178 
    179            // We don't know what to do, so just return nullptr (but *don't* poison the buffer).
    180            SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL shader.\n");
    181            return nullptr;
    182        }
    183    }
    184 
    185    return effect->makeShader(std::move(uniforms), SkSpan(children), SkOptAddressOrNull(localM));
    186 }