1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkRuntimeEffect_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkRuntimeEffect_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlender.h" // IWYU pragma: keep 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h" // IWYU pragma: keep 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFlattenable.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkSLSampleUsage.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h" 23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h" 24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h" 25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTypeTraits.h" 26*c8dee2aaSAndroid Build Coastguard Worker #include "include/sksl/SkSLDebugTrace.h" 27*c8dee2aaSAndroid Build Coastguard Worker #include "include/sksl/SkSLVersion.h" 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 31*c8dee2aaSAndroid Build Coastguard Worker #include <cstring> 32*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 33*c8dee2aaSAndroid Build Coastguard Worker #include <optional> 34*c8dee2aaSAndroid Build Coastguard Worker #include <string> 35*c8dee2aaSAndroid Build Coastguard Worker #include <string_view> 36*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 37*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker struct SkIPoint; 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL { 42*c8dee2aaSAndroid Build Coastguard Worker class DebugTracePriv; 43*c8dee2aaSAndroid Build Coastguard Worker class FunctionDefinition; 44*c8dee2aaSAndroid Build Coastguard Worker struct Program; 45*c8dee2aaSAndroid Build Coastguard Worker enum class ProgramKind : int8_t; 46*c8dee2aaSAndroid Build Coastguard Worker struct ProgramSettings; 47*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkSL 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL::RP { 50*c8dee2aaSAndroid Build Coastguard Worker class Program; 51*c8dee2aaSAndroid Build Coastguard Worker } 52*c8dee2aaSAndroid Build Coastguard Worker 53*c8dee2aaSAndroid Build Coastguard Worker /* 54*c8dee2aaSAndroid Build Coastguard Worker * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL 55*c8dee2aaSAndroid Build Coastguard Worker * shading language. 56*c8dee2aaSAndroid Build Coastguard Worker * 57*c8dee2aaSAndroid Build Coastguard Worker * NOTE: This API is experimental and subject to change. 58*c8dee2aaSAndroid Build Coastguard Worker */ 59*c8dee2aaSAndroid Build Coastguard Worker class SK_API SkRuntimeEffect : public SkRefCnt { 60*c8dee2aaSAndroid Build Coastguard Worker public: 61*c8dee2aaSAndroid Build Coastguard Worker // Reflected description of a uniform variable in the effect's SkSL 62*c8dee2aaSAndroid Build Coastguard Worker struct SK_API Uniform { 63*c8dee2aaSAndroid Build Coastguard Worker enum class Type { 64*c8dee2aaSAndroid Build Coastguard Worker kFloat, 65*c8dee2aaSAndroid Build Coastguard Worker kFloat2, 66*c8dee2aaSAndroid Build Coastguard Worker kFloat3, 67*c8dee2aaSAndroid Build Coastguard Worker kFloat4, 68*c8dee2aaSAndroid Build Coastguard Worker kFloat2x2, 69*c8dee2aaSAndroid Build Coastguard Worker kFloat3x3, 70*c8dee2aaSAndroid Build Coastguard Worker kFloat4x4, 71*c8dee2aaSAndroid Build Coastguard Worker kInt, 72*c8dee2aaSAndroid Build Coastguard Worker kInt2, 73*c8dee2aaSAndroid Build Coastguard Worker kInt3, 74*c8dee2aaSAndroid Build Coastguard Worker kInt4, 75*c8dee2aaSAndroid Build Coastguard Worker }; 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker enum Flags { 78*c8dee2aaSAndroid Build Coastguard Worker // Uniform is declared as an array. 'count' contains array length. 79*c8dee2aaSAndroid Build Coastguard Worker kArray_Flag = 0x1, 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker // Uniform is declared with layout(color). Colors should be supplied as unpremultiplied, 82*c8dee2aaSAndroid Build Coastguard Worker // extended-range (unclamped) sRGB (ie SkColor4f). The uniform will be automatically 83*c8dee2aaSAndroid Build Coastguard Worker // transformed to unpremultiplied extended-range working-space colors. 84*c8dee2aaSAndroid Build Coastguard Worker kColor_Flag = 0x2, 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker // When used with SkMeshSpecification, indicates that the uniform is present in the 87*c8dee2aaSAndroid Build Coastguard Worker // vertex shader. Not used with SkRuntimeEffect. 88*c8dee2aaSAndroid Build Coastguard Worker kVertex_Flag = 0x4, 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker // When used with SkMeshSpecification, indicates that the uniform is present in the 91*c8dee2aaSAndroid Build Coastguard Worker // fragment shader. Not used with SkRuntimeEffect. 92*c8dee2aaSAndroid Build Coastguard Worker kFragment_Flag = 0x8, 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker // This flag indicates that the SkSL uniform uses a medium-precision type 95*c8dee2aaSAndroid Build Coastguard Worker // (i.e., `half` instead of `float`). 96*c8dee2aaSAndroid Build Coastguard Worker kHalfPrecision_Flag = 0x10, 97*c8dee2aaSAndroid Build Coastguard Worker }; 98*c8dee2aaSAndroid Build Coastguard Worker 99*c8dee2aaSAndroid Build Coastguard Worker std::string_view name; 100*c8dee2aaSAndroid Build Coastguard Worker size_t offset; 101*c8dee2aaSAndroid Build Coastguard Worker Type type; 102*c8dee2aaSAndroid Build Coastguard Worker int count; 103*c8dee2aaSAndroid Build Coastguard Worker uint32_t flags; 104*c8dee2aaSAndroid Build Coastguard Worker isArrayUniform105*c8dee2aaSAndroid Build Coastguard Worker bool isArray() const { return SkToBool(this->flags & kArray_Flag); } isColorUniform106*c8dee2aaSAndroid Build Coastguard Worker bool isColor() const { return SkToBool(this->flags & kColor_Flag); } 107*c8dee2aaSAndroid Build Coastguard Worker size_t sizeInBytes() const; 108*c8dee2aaSAndroid Build Coastguard Worker }; 109*c8dee2aaSAndroid Build Coastguard Worker 110*c8dee2aaSAndroid Build Coastguard Worker // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL 111*c8dee2aaSAndroid Build Coastguard Worker enum class ChildType { 112*c8dee2aaSAndroid Build Coastguard Worker kShader, 113*c8dee2aaSAndroid Build Coastguard Worker kColorFilter, 114*c8dee2aaSAndroid Build Coastguard Worker kBlender, 115*c8dee2aaSAndroid Build Coastguard Worker }; 116*c8dee2aaSAndroid Build Coastguard Worker 117*c8dee2aaSAndroid Build Coastguard Worker struct Child { 118*c8dee2aaSAndroid Build Coastguard Worker std::string_view name; 119*c8dee2aaSAndroid Build Coastguard Worker ChildType type; 120*c8dee2aaSAndroid Build Coastguard Worker int index; 121*c8dee2aaSAndroid Build Coastguard Worker }; 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker class Options { 124*c8dee2aaSAndroid Build Coastguard Worker public: 125*c8dee2aaSAndroid Build Coastguard Worker // For testing purposes, disables optimization and inlining. (Normally, Runtime Effects 126*c8dee2aaSAndroid Build Coastguard Worker // don't run the inliner directly, but they still get an inlining pass once they are 127*c8dee2aaSAndroid Build Coastguard Worker // painted.) 128*c8dee2aaSAndroid Build Coastguard Worker bool forceUnoptimized = false; 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Worker private: 131*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeEffect; 132*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeEffectPriv; 133*c8dee2aaSAndroid Build Coastguard Worker 134*c8dee2aaSAndroid Build Coastguard Worker // This flag allows Runtime Effects to access Skia implementation details like sk_FragCoord 135*c8dee2aaSAndroid Build Coastguard Worker // and functions with private identifiers (e.g. $rgb_to_hsl). 136*c8dee2aaSAndroid Build Coastguard Worker bool allowPrivateAccess = false; 137*c8dee2aaSAndroid Build Coastguard Worker // When not 0, this field allows Skia to assign a stable key to a known runtime effect 138*c8dee2aaSAndroid Build Coastguard Worker uint32_t fStableKey = 0; 139*c8dee2aaSAndroid Build Coastguard Worker 140*c8dee2aaSAndroid Build Coastguard Worker // TODO(skia:11209) - Replace this with a promised SkCapabilities? 141*c8dee2aaSAndroid Build Coastguard Worker // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the 142*c8dee2aaSAndroid Build Coastguard Worker // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are 143*c8dee2aaSAndroid Build Coastguard Worker // still largely ES3-unaware and can still fail or crash if post-ES2 features are used. 144*c8dee2aaSAndroid Build Coastguard Worker // This is only intended for use by tests and certain internally created effects. 145*c8dee2aaSAndroid Build Coastguard Worker SkSL::Version maxVersionAllowed = SkSL::Version::k100; 146*c8dee2aaSAndroid Build Coastguard Worker }; 147*c8dee2aaSAndroid Build Coastguard Worker 148*c8dee2aaSAndroid Build Coastguard Worker // If the effect is compiled successfully, `effect` will be non-null. 149*c8dee2aaSAndroid Build Coastguard Worker // Otherwise, `errorText` will contain the reason for failure. 150*c8dee2aaSAndroid Build Coastguard Worker struct Result { 151*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> effect; 152*c8dee2aaSAndroid Build Coastguard Worker SkString errorText; 153*c8dee2aaSAndroid Build Coastguard Worker }; 154*c8dee2aaSAndroid Build Coastguard Worker 155*c8dee2aaSAndroid Build Coastguard Worker // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of 156*c8dee2aaSAndroid Build Coastguard Worker // the Skia pipeline. In all of the signatures described below, color parameters and return 157*c8dee2aaSAndroid Build Coastguard Worker // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or 158*c8dee2aaSAndroid Build Coastguard Worker // 'float4'. ('vec4' is an alias for 'float4'). 159*c8dee2aaSAndroid Build Coastguard Worker 160*c8dee2aaSAndroid Build Coastguard Worker // We can't use a default argument for `options` due to a bug in Clang. 161*c8dee2aaSAndroid Build Coastguard Worker // https://bugs.llvm.org/show_bug.cgi?id=36684 162*c8dee2aaSAndroid Build Coastguard Worker 163*c8dee2aaSAndroid Build Coastguard Worker // Color filter SkSL requires an entry point that looks like: 164*c8dee2aaSAndroid Build Coastguard Worker // vec4 main(vec4 inColor) { ... } 165*c8dee2aaSAndroid Build Coastguard Worker // https://fiddle.skia.org/c/@runtimeeffect_colorfilter_grid 166*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForColorFilter(SkString sksl, const Options&); MakeForColorFilter(SkString sksl)167*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForColorFilter(SkString sksl) { 168*c8dee2aaSAndroid Build Coastguard Worker return MakeForColorFilter(std::move(sksl), Options{}); 169*c8dee2aaSAndroid Build Coastguard Worker } 170*c8dee2aaSAndroid Build Coastguard Worker 171*c8dee2aaSAndroid Build Coastguard Worker // Shader SkSL requires an entry point that looks like: 172*c8dee2aaSAndroid Build Coastguard Worker // vec4 main(vec2 inCoords) { ... } 173*c8dee2aaSAndroid Build Coastguard Worker // The color that is returned should be premultiplied. 174*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForShader(SkString sksl, const Options&); MakeForShader(SkString sksl)175*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForShader(SkString sksl) { 176*c8dee2aaSAndroid Build Coastguard Worker return MakeForShader(std::move(sksl), Options{}); 177*c8dee2aaSAndroid Build Coastguard Worker } 178*c8dee2aaSAndroid Build Coastguard Worker 179*c8dee2aaSAndroid Build Coastguard Worker // Blend SkSL requires an entry point that looks like: 180*c8dee2aaSAndroid Build Coastguard Worker // vec4 main(vec4 srcColor, vec4 dstColor) { ... } 181*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForBlender(SkString sksl, const Options&); MakeForBlender(SkString sksl)182*c8dee2aaSAndroid Build Coastguard Worker static Result MakeForBlender(SkString sksl) { 183*c8dee2aaSAndroid Build Coastguard Worker return MakeForBlender(std::move(sksl), Options{}); 184*c8dee2aaSAndroid Build Coastguard Worker } 185*c8dee2aaSAndroid Build Coastguard Worker 186*c8dee2aaSAndroid Build Coastguard Worker // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child 187*c8dee2aaSAndroid Build Coastguard Worker class SK_API ChildPtr { 188*c8dee2aaSAndroid Build Coastguard Worker public: 189*c8dee2aaSAndroid Build Coastguard Worker ChildPtr() = default; ChildPtr(sk_sp<SkShader> s)190*c8dee2aaSAndroid Build Coastguard Worker ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {} ChildPtr(sk_sp<SkColorFilter> cf)191*c8dee2aaSAndroid Build Coastguard Worker ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {} ChildPtr(sk_sp<SkBlender> b)192*c8dee2aaSAndroid Build Coastguard Worker ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {} 193*c8dee2aaSAndroid Build Coastguard Worker 194*c8dee2aaSAndroid Build Coastguard Worker // Asserts that the flattenable is either null, or one of the legal derived types 195*c8dee2aaSAndroid Build Coastguard Worker ChildPtr(sk_sp<SkFlattenable> f); 196*c8dee2aaSAndroid Build Coastguard Worker 197*c8dee2aaSAndroid Build Coastguard Worker std::optional<ChildType> type() const; 198*c8dee2aaSAndroid Build Coastguard Worker 199*c8dee2aaSAndroid Build Coastguard Worker SkShader* shader() const; 200*c8dee2aaSAndroid Build Coastguard Worker SkColorFilter* colorFilter() const; 201*c8dee2aaSAndroid Build Coastguard Worker SkBlender* blender() const; flattenable()202*c8dee2aaSAndroid Build Coastguard Worker SkFlattenable* flattenable() const { return fChild.get(); } 203*c8dee2aaSAndroid Build Coastguard Worker 204*c8dee2aaSAndroid Build Coastguard Worker using sk_is_trivially_relocatable = std::true_type; 205*c8dee2aaSAndroid Build Coastguard Worker 206*c8dee2aaSAndroid Build Coastguard Worker private: 207*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkFlattenable> fChild; 208*c8dee2aaSAndroid Build Coastguard Worker 209*c8dee2aaSAndroid Build Coastguard Worker static_assert(::sk_is_trivially_relocatable<decltype(fChild)>::value); 210*c8dee2aaSAndroid Build Coastguard Worker }; 211*c8dee2aaSAndroid Build Coastguard Worker 212*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms, 213*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> children[], 214*c8dee2aaSAndroid Build Coastguard Worker size_t childCount, 215*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix* localMatrix = nullptr) const; 216*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms, 217*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const ChildPtr> children, 218*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix* localMatrix = nullptr) const; 219*c8dee2aaSAndroid Build Coastguard Worker 220*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms) const; 221*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms, 222*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> children[], 223*c8dee2aaSAndroid Build Coastguard Worker size_t childCount) const; 224*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms, 225*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const ChildPtr> children) const; 226*c8dee2aaSAndroid Build Coastguard Worker 227*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkBlender> makeBlender(sk_sp<const SkData> uniforms, 228*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const ChildPtr> children = {}) const; 229*c8dee2aaSAndroid Build Coastguard Worker 230*c8dee2aaSAndroid Build Coastguard Worker /** 231*c8dee2aaSAndroid Build Coastguard Worker * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves 232*c8dee2aaSAndroid Build Coastguard Worker * like the original, but also creates a debug trace of its execution at the requested 233*c8dee2aaSAndroid Build Coastguard Worker * coordinate. After painting with this shader, the associated DebugTrace object will contain a 234*c8dee2aaSAndroid Build Coastguard Worker * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace 235*c8dee2aaSAndroid Build Coastguard Worker * suitable for a debugger, or call `dump` to emit a human-readable trace. 236*c8dee2aaSAndroid Build Coastguard Worker * 237*c8dee2aaSAndroid Build Coastguard Worker * Debug traces are only supported on a raster (non-GPU) canvas. 238*c8dee2aaSAndroid Build Coastguard Worker 239*c8dee2aaSAndroid Build Coastguard Worker * Debug traces are currently only supported on shaders. Color filter and blender tracing is a 240*c8dee2aaSAndroid Build Coastguard Worker * work-in-progress. 241*c8dee2aaSAndroid Build Coastguard Worker */ 242*c8dee2aaSAndroid Build Coastguard Worker struct TracedShader { 243*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> shader; 244*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSL::DebugTrace> debugTrace; 245*c8dee2aaSAndroid Build Coastguard Worker }; 246*c8dee2aaSAndroid Build Coastguard Worker static TracedShader MakeTraced(sk_sp<SkShader> shader, const SkIPoint& traceCoord); 247*c8dee2aaSAndroid Build Coastguard Worker 248*c8dee2aaSAndroid Build Coastguard Worker // Returns the SkSL source of the runtime effect shader. 249*c8dee2aaSAndroid Build Coastguard Worker const std::string& source() const; 250*c8dee2aaSAndroid Build Coastguard Worker 251*c8dee2aaSAndroid Build Coastguard Worker // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader, 252*c8dee2aaSAndroid Build Coastguard Worker // provide an SkData of this size, containing values for all of those variables. 253*c8dee2aaSAndroid Build Coastguard Worker size_t uniformSize() const; 254*c8dee2aaSAndroid Build Coastguard Worker uniforms()255*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); } children()256*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Child> children() const { return SkSpan(fChildren); } 257*c8dee2aaSAndroid Build Coastguard Worker 258*c8dee2aaSAndroid Build Coastguard Worker // Returns pointer to the named uniform variable's description, or nullptr if not found 259*c8dee2aaSAndroid Build Coastguard Worker const Uniform* findUniform(std::string_view name) const; 260*c8dee2aaSAndroid Build Coastguard Worker 261*c8dee2aaSAndroid Build Coastguard Worker // Returns pointer to the named child's description, or nullptr if not found 262*c8dee2aaSAndroid Build Coastguard Worker const Child* findChild(std::string_view name) const; 263*c8dee2aaSAndroid Build Coastguard Worker 264*c8dee2aaSAndroid Build Coastguard Worker // Allows the runtime effect type to be identified. allowShader()265*c8dee2aaSAndroid Build Coastguard Worker bool allowShader() const { return (fFlags & kAllowShader_Flag); } allowColorFilter()266*c8dee2aaSAndroid Build Coastguard Worker bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } allowBlender()267*c8dee2aaSAndroid Build Coastguard Worker bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } 268*c8dee2aaSAndroid Build Coastguard Worker 269*c8dee2aaSAndroid Build Coastguard Worker static void RegisterFlattenables(); 270*c8dee2aaSAndroid Build Coastguard Worker ~SkRuntimeEffect() override; 271*c8dee2aaSAndroid Build Coastguard Worker 272*c8dee2aaSAndroid Build Coastguard Worker private: 273*c8dee2aaSAndroid Build Coastguard Worker enum Flags { 274*c8dee2aaSAndroid Build Coastguard Worker kUsesSampleCoords_Flag = 0x001, 275*c8dee2aaSAndroid Build Coastguard Worker kAllowColorFilter_Flag = 0x002, 276*c8dee2aaSAndroid Build Coastguard Worker kAllowShader_Flag = 0x004, 277*c8dee2aaSAndroid Build Coastguard Worker kAllowBlender_Flag = 0x008, 278*c8dee2aaSAndroid Build Coastguard Worker kSamplesOutsideMain_Flag = 0x010, 279*c8dee2aaSAndroid Build Coastguard Worker kUsesColorTransform_Flag = 0x020, 280*c8dee2aaSAndroid Build Coastguard Worker kAlwaysOpaque_Flag = 0x040, 281*c8dee2aaSAndroid Build Coastguard Worker kAlphaUnchanged_Flag = 0x080, 282*c8dee2aaSAndroid Build Coastguard Worker kDisableOptimization_Flag = 0x100, 283*c8dee2aaSAndroid Build Coastguard Worker }; 284*c8dee2aaSAndroid Build Coastguard Worker 285*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram, 286*c8dee2aaSAndroid Build Coastguard Worker const Options& options, 287*c8dee2aaSAndroid Build Coastguard Worker const SkSL::FunctionDefinition& main, 288*c8dee2aaSAndroid Build Coastguard Worker std::vector<Uniform>&& uniforms, 289*c8dee2aaSAndroid Build Coastguard Worker std::vector<Child>&& children, 290*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkSL::SampleUsage>&& sampleUsages, 291*c8dee2aaSAndroid Build Coastguard Worker uint32_t flags); 292*c8dee2aaSAndroid Build Coastguard Worker 293*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> makeUnoptimizedClone(); 294*c8dee2aaSAndroid Build Coastguard Worker 295*c8dee2aaSAndroid Build Coastguard Worker static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind); 296*c8dee2aaSAndroid Build Coastguard Worker 297*c8dee2aaSAndroid Build Coastguard Worker static Result MakeInternal(std::unique_ptr<SkSL::Program> program, 298*c8dee2aaSAndroid Build Coastguard Worker const Options& options, 299*c8dee2aaSAndroid Build Coastguard Worker SkSL::ProgramKind kind); 300*c8dee2aaSAndroid Build Coastguard Worker 301*c8dee2aaSAndroid Build Coastguard Worker static SkSL::ProgramSettings MakeSettings(const Options& options); 302*c8dee2aaSAndroid Build Coastguard Worker hash()303*c8dee2aaSAndroid Build Coastguard Worker uint32_t hash() const { return fHash; } usesSampleCoords()304*c8dee2aaSAndroid Build Coastguard Worker bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } samplesOutsideMain()305*c8dee2aaSAndroid Build Coastguard Worker bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } usesColorTransform()306*c8dee2aaSAndroid Build Coastguard Worker bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); } alwaysOpaque()307*c8dee2aaSAndroid Build Coastguard Worker bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); } isAlphaUnchanged()308*c8dee2aaSAndroid Build Coastguard Worker bool isAlphaUnchanged() const { return (fFlags & kAlphaUnchanged_Flag); } 309*c8dee2aaSAndroid Build Coastguard Worker 310*c8dee2aaSAndroid Build Coastguard Worker const SkSL::RP::Program* getRPProgram(SkSL::DebugTracePriv* debugTrace) const; 311*c8dee2aaSAndroid Build Coastguard Worker 312*c8dee2aaSAndroid Build Coastguard Worker friend class GrSkSLFP; // usesColorTransform 313*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeShader; // fBaseProgram, fMain, fSampleUsages, getRPProgram() 314*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeBlender; // 315*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeColorFilter; // 316*c8dee2aaSAndroid Build Coastguard Worker 317*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeEffectPriv; 318*c8dee2aaSAndroid Build Coastguard Worker 319*c8dee2aaSAndroid Build Coastguard Worker uint32_t fHash; 320*c8dee2aaSAndroid Build Coastguard Worker uint32_t fStableKey; 321*c8dee2aaSAndroid Build Coastguard Worker 322*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkSL::Program> fBaseProgram; 323*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkSL::RP::Program> fRPProgram; 324*c8dee2aaSAndroid Build Coastguard Worker mutable SkOnce fCompileRPProgramOnce; 325*c8dee2aaSAndroid Build Coastguard Worker const SkSL::FunctionDefinition& fMain; 326*c8dee2aaSAndroid Build Coastguard Worker std::vector<Uniform> fUniforms; 327*c8dee2aaSAndroid Build Coastguard Worker std::vector<Child> fChildren; 328*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkSL::SampleUsage> fSampleUsages; 329*c8dee2aaSAndroid Build Coastguard Worker 330*c8dee2aaSAndroid Build Coastguard Worker uint32_t fFlags; // Flags 331*c8dee2aaSAndroid Build Coastguard Worker }; 332*c8dee2aaSAndroid Build Coastguard Worker 333*c8dee2aaSAndroid Build Coastguard Worker /** 334*c8dee2aaSAndroid Build Coastguard Worker * SkRuntimeEffectBuilder is a utility to simplify creating SkShader, SkColorFilter, and SkBlender 335*c8dee2aaSAndroid Build Coastguard Worker * objects from SkRuntimeEffects. 336*c8dee2aaSAndroid Build Coastguard Worker * 337*c8dee2aaSAndroid Build Coastguard Worker * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change! 338*c8dee2aaSAndroid Build Coastguard Worker * 339*c8dee2aaSAndroid Build Coastguard Worker * Given an SkRuntimeEffect, the SkRuntimeEffectBuilder manages creating an input data block and 340*c8dee2aaSAndroid Build Coastguard Worker * provides named access to the 'uniform' variables in that block, as well as named access 341*c8dee2aaSAndroid Build Coastguard Worker * to a list of child shader slots. Usage: 342*c8dee2aaSAndroid Build Coastguard Worker * 343*c8dee2aaSAndroid Build Coastguard Worker * sk_sp<SkRuntimeEffect> effect = ...; 344*c8dee2aaSAndroid Build Coastguard Worker * SkRuntimeEffectBuilder builder(effect); 345*c8dee2aaSAndroid Build Coastguard Worker * builder.uniform("some_uniform_float") = 3.14f; 346*c8dee2aaSAndroid Build Coastguard Worker * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...); 347*c8dee2aaSAndroid Build Coastguard Worker * builder.child("some_child_effect") = mySkImage->makeShader(...); 348*c8dee2aaSAndroid Build Coastguard Worker * ... 349*c8dee2aaSAndroid Build Coastguard Worker * sk_sp<SkShader> shader = builder.makeShader(nullptr, false); 350*c8dee2aaSAndroid Build Coastguard Worker * 351*c8dee2aaSAndroid Build Coastguard Worker * Upon calling makeShader, makeColorFilter, or makeBlender, the builder will check the validity 352*c8dee2aaSAndroid Build Coastguard Worker * of the SkSL to see if the entry point is correct. 353*c8dee2aaSAndroid Build Coastguard Worker * 354*c8dee2aaSAndroid Build Coastguard Worker * Note that SkRuntimeEffectBuilder is built entirely on the public API of SkRuntimeEffect, 355*c8dee2aaSAndroid Build Coastguard Worker * so can be used as-is or serve as inspiration for other interfaces or binding techniques. 356*c8dee2aaSAndroid Build Coastguard Worker */ 357*c8dee2aaSAndroid Build Coastguard Worker class SK_API SkRuntimeEffectBuilder { 358*c8dee2aaSAndroid Build Coastguard Worker public: SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)359*c8dee2aaSAndroid Build Coastguard Worker explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect) 360*c8dee2aaSAndroid Build Coastguard Worker : fEffect(std::move(effect)) 361*c8dee2aaSAndroid Build Coastguard Worker , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize())) 362*c8dee2aaSAndroid Build Coastguard Worker , fChildren(fEffect->children().size()) {} SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect,sk_sp<SkData> uniforms)363*c8dee2aaSAndroid Build Coastguard Worker explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms) 364*c8dee2aaSAndroid Build Coastguard Worker : fEffect(std::move(effect)) 365*c8dee2aaSAndroid Build Coastguard Worker , fUniforms(std::move(uniforms)) 366*c8dee2aaSAndroid Build Coastguard Worker , fChildren(fEffect->children().size()) {} 367*c8dee2aaSAndroid Build Coastguard Worker 368*c8dee2aaSAndroid Build Coastguard Worker // This is currently required by Android Framework but may go away if that dependency 369*c8dee2aaSAndroid Build Coastguard Worker // can be removed. 370*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; 371*c8dee2aaSAndroid Build Coastguard Worker 372*c8dee2aaSAndroid Build Coastguard Worker struct BuilderUniform { 373*c8dee2aaSAndroid Build Coastguard Worker // Copy 'val' to this variable. No type conversion is performed - 'val' must be same 374*c8dee2aaSAndroid Build Coastguard Worker // size as expected by the effect. Information about the variable can be queried by 375*c8dee2aaSAndroid Build Coastguard Worker // looking at fVar. If the size is incorrect, no copy will be performed, and debug 376*c8dee2aaSAndroid Build Coastguard Worker // builds will abort. If this is the result of querying a missing variable, fVar will 377*c8dee2aaSAndroid Build Coastguard Worker // be nullptr, and assigning will also do nothing (and abort in debug builds). 378*c8dee2aaSAndroid Build Coastguard Worker template <typename T> 379*c8dee2aaSAndroid Build Coastguard Worker std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=( 380*c8dee2aaSAndroid Build Coastguard Worker const T& val) { 381*c8dee2aaSAndroid Build Coastguard Worker if (!fVar) { 382*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Assigning to missing variable"); 383*c8dee2aaSAndroid Build Coastguard Worker } else if (sizeof(val) != fVar->sizeInBytes()) { 384*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Incorrect value size"); 385*c8dee2aaSAndroid Build Coastguard Worker } else { 386*c8dee2aaSAndroid Build Coastguard Worker memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), 387*c8dee2aaSAndroid Build Coastguard Worker &val, sizeof(val)); 388*c8dee2aaSAndroid Build Coastguard Worker } 389*c8dee2aaSAndroid Build Coastguard Worker return *this; 390*c8dee2aaSAndroid Build Coastguard Worker } 391*c8dee2aaSAndroid Build Coastguard Worker 392*c8dee2aaSAndroid Build Coastguard Worker BuilderUniform& operator=(const SkMatrix& val) { 393*c8dee2aaSAndroid Build Coastguard Worker if (!fVar) { 394*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Assigning to missing variable"); 395*c8dee2aaSAndroid Build Coastguard Worker } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { 396*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Incorrect value size"); 397*c8dee2aaSAndroid Build Coastguard Worker } else { 398*c8dee2aaSAndroid Build Coastguard Worker float* data = SkTAddOffset<float>(fOwner->writableUniformData(), 399*c8dee2aaSAndroid Build Coastguard Worker (ptrdiff_t)fVar->offset); 400*c8dee2aaSAndroid Build Coastguard Worker data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6); 401*c8dee2aaSAndroid Build Coastguard Worker data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7); 402*c8dee2aaSAndroid Build Coastguard Worker data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8); 403*c8dee2aaSAndroid Build Coastguard Worker } 404*c8dee2aaSAndroid Build Coastguard Worker return *this; 405*c8dee2aaSAndroid Build Coastguard Worker } 406*c8dee2aaSAndroid Build Coastguard Worker 407*c8dee2aaSAndroid Build Coastguard Worker template <typename T> setBuilderUniform408*c8dee2aaSAndroid Build Coastguard Worker bool set(const T val[], const int count) { 409*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); 410*c8dee2aaSAndroid Build Coastguard Worker if (!fVar) { 411*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Assigning to missing variable"); 412*c8dee2aaSAndroid Build Coastguard Worker return false; 413*c8dee2aaSAndroid Build Coastguard Worker } else if (sizeof(T) * count != fVar->sizeInBytes()) { 414*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Incorrect value size"); 415*c8dee2aaSAndroid Build Coastguard Worker return false; 416*c8dee2aaSAndroid Build Coastguard Worker } else { 417*c8dee2aaSAndroid Build Coastguard Worker memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), 418*c8dee2aaSAndroid Build Coastguard Worker val, sizeof(T) * count); 419*c8dee2aaSAndroid Build Coastguard Worker } 420*c8dee2aaSAndroid Build Coastguard Worker return true; 421*c8dee2aaSAndroid Build Coastguard Worker } 422*c8dee2aaSAndroid Build Coastguard Worker 423*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder* fOwner; 424*c8dee2aaSAndroid Build Coastguard Worker const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found 425*c8dee2aaSAndroid Build Coastguard Worker }; 426*c8dee2aaSAndroid Build Coastguard Worker 427*c8dee2aaSAndroid Build Coastguard Worker struct BuilderChild { 428*c8dee2aaSAndroid Build Coastguard Worker template <typename T> BuilderChild& operator=(sk_sp<T> val) { 429*c8dee2aaSAndroid Build Coastguard Worker if (!fChild) { 430*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Assigning to missing child"); 431*c8dee2aaSAndroid Build Coastguard Worker } else { 432*c8dee2aaSAndroid Build Coastguard Worker fOwner->fChildren[(size_t)fChild->index] = std::move(val); 433*c8dee2aaSAndroid Build Coastguard Worker } 434*c8dee2aaSAndroid Build Coastguard Worker return *this; 435*c8dee2aaSAndroid Build Coastguard Worker } 436*c8dee2aaSAndroid Build Coastguard Worker 437*c8dee2aaSAndroid Build Coastguard Worker BuilderChild& operator=(std::nullptr_t) { 438*c8dee2aaSAndroid Build Coastguard Worker if (!fChild) { 439*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Assigning to missing child"); 440*c8dee2aaSAndroid Build Coastguard Worker } else { 441*c8dee2aaSAndroid Build Coastguard Worker fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; 442*c8dee2aaSAndroid Build Coastguard Worker } 443*c8dee2aaSAndroid Build Coastguard Worker return *this; 444*c8dee2aaSAndroid Build Coastguard Worker } 445*c8dee2aaSAndroid Build Coastguard Worker 446*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder* fOwner; 447*c8dee2aaSAndroid Build Coastguard Worker const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found 448*c8dee2aaSAndroid Build Coastguard Worker }; 449*c8dee2aaSAndroid Build Coastguard Worker effect()450*c8dee2aaSAndroid Build Coastguard Worker const SkRuntimeEffect* effect() const { return fEffect.get(); } 451*c8dee2aaSAndroid Build Coastguard Worker uniform(std::string_view name)452*c8dee2aaSAndroid Build Coastguard Worker BuilderUniform uniform(std::string_view name) { return { this, fEffect->findUniform(name) }; } child(std::string_view name)453*c8dee2aaSAndroid Build Coastguard Worker BuilderChild child(std::string_view name) { return { this, fEffect->findChild(name) }; } 454*c8dee2aaSAndroid Build Coastguard Worker 455*c8dee2aaSAndroid Build Coastguard Worker // Get access to the collated uniforms and children (in the order expected by APIs like 456*c8dee2aaSAndroid Build Coastguard Worker // makeShader on the effect): uniforms()457*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const SkData> uniforms() const { return fUniforms; } children()458*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkRuntimeEffect::ChildPtr> children() const { return fChildren; } 459*c8dee2aaSAndroid Build Coastguard Worker 460*c8dee2aaSAndroid Build Coastguard Worker // Build methods, at this point checks are made to ensure the SkSL entry point `main` is correct 461*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const; 462*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> makeColorFilter() const; 463*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkBlender> makeBlender() const; 464*c8dee2aaSAndroid Build Coastguard Worker 465*c8dee2aaSAndroid Build Coastguard Worker ~SkRuntimeEffectBuilder() = default; 466*c8dee2aaSAndroid Build Coastguard Worker 467*c8dee2aaSAndroid Build Coastguard Worker protected: 468*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder() = delete; 469*c8dee2aaSAndroid Build Coastguard Worker 470*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; 471*c8dee2aaSAndroid Build Coastguard Worker 472*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; 473*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; 474*c8dee2aaSAndroid Build Coastguard Worker 475*c8dee2aaSAndroid Build Coastguard Worker private: writableUniformData()476*c8dee2aaSAndroid Build Coastguard Worker void* writableUniformData() { 477*c8dee2aaSAndroid Build Coastguard Worker if (!fUniforms->unique()) { 478*c8dee2aaSAndroid Build Coastguard Worker fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); 479*c8dee2aaSAndroid Build Coastguard Worker } 480*c8dee2aaSAndroid Build Coastguard Worker return fUniforms->writable_data(); 481*c8dee2aaSAndroid Build Coastguard Worker } 482*c8dee2aaSAndroid Build Coastguard Worker 483*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> fEffect; 484*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fUniforms; 485*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkRuntimeEffect::ChildPtr> fChildren; 486*c8dee2aaSAndroid Build Coastguard Worker 487*c8dee2aaSAndroid Build Coastguard Worker friend class SkRuntimeImageFilter; 488*c8dee2aaSAndroid Build Coastguard Worker }; 489*c8dee2aaSAndroid Build Coastguard Worker 490*c8dee2aaSAndroid Build Coastguard Worker /** 491*c8dee2aaSAndroid Build Coastguard Worker * DEPRECATED: Subclass logic has been moved to base class SkRuntimeEffectBuilder. 492*c8dee2aaSAndroid Build Coastguard Worker */ 493*c8dee2aaSAndroid Build Coastguard Worker using SkRuntimeShaderBuilder = SkRuntimeEffectBuilder; 494*c8dee2aaSAndroid Build Coastguard Worker using SkRuntimeColorFilterBuilder = SkRuntimeEffectBuilder; 495*c8dee2aaSAndroid Build Coastguard Worker using SkRuntimeBlendBuilder = SkRuntimeEffectBuilder; 496*c8dee2aaSAndroid Build Coastguard Worker 497*c8dee2aaSAndroid Build Coastguard Worker #endif // SkRuntimeEffect_DEFINED 498