1 /* 2 * Copyright 2019 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 8 #ifndef SkRuntimeEffect_DEFINED 9 #define SkRuntimeEffect_DEFINED 10 11 #include "include/core/SkBlender.h" 12 #include "include/core/SkColorFilter.h" 13 #include "include/core/SkData.h" 14 #include "include/core/SkImageInfo.h" 15 #include "include/core/SkMatrix.h" 16 #include "include/core/SkShader.h" 17 #include "include/core/SkSpan.h" 18 #include "include/core/SkString.h" 19 #include "include/private/SkOnce.h" 20 #include "include/private/SkSLSampleUsage.h" 21 #include "include/private/SkTOptional.h" 22 23 #include <string> 24 #include <vector> 25 26 #ifdef SK_ENABLE_SKSL 27 28 class GrRecordingContext; 29 class SkFilterColorProgram; 30 class SkImage; 31 32 namespace SkSL { 33 class FunctionDefinition; 34 struct Program; 35 enum class ProgramKind : int8_t; 36 } // namespace SkSL 37 38 namespace skvm { 39 class Program; 40 } // namespace skvm 41 42 /* 43 * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL 44 * shading language. 45 * 46 * NOTE: This API is experimental and subject to change. 47 */ 48 class SK_API SkRuntimeEffect : public SkRefCnt { 49 public: 50 // Reflected description of a uniform variable in the effect's SkSL 51 struct Uniform { 52 enum class Type { 53 kFloat, 54 kFloat2, 55 kFloat3, 56 kFloat4, 57 kFloat2x2, 58 kFloat3x3, 59 kFloat4x4, 60 kInt, 61 kInt2, 62 kInt3, 63 kInt4, 64 }; 65 66 enum Flags { 67 kArray_Flag = 0x1, 68 kSRGBUnpremul_Flag = 0x2, 69 }; 70 71 SkString name; 72 size_t offset; 73 Type type; 74 int count; 75 uint32_t flags; 76 isArrayUniform77 bool isArray() const { return SkToBool(this->flags & kArray_Flag); } 78 size_t sizeInBytes() const; 79 }; 80 81 // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL 82 enum class ChildType { 83 kShader, 84 kColorFilter, 85 kBlender, 86 }; 87 88 struct Child { 89 SkString name; 90 ChildType type; 91 int index; 92 }; 93 94 class Options { 95 public: 96 // For testing purposes, completely disable the inliner. (Normally, Runtime Effects don't 97 // run the inliner directly, but they still get an inlining pass once they are painted.) 98 bool forceNoInline = false; 99 100 // Advanced Filter: It indicates whether AF is enabled 101 // The value will pass to ProgramSettings::fUseAF. 102 bool useAF = false; 103 104 private: 105 friend class SkRuntimeEffect; 106 friend class SkRuntimeEffectPriv; 107 108 // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the 109 // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are 110 // still largely ES3-unaware and can still fail or crash if post-ES2 features are used. 111 // This is only intended for use by tests and certain internally created effects. 112 bool enforceES2Restrictions = true; 113 114 // Similarly: Public SkSL does not allow access to sk_FragCoord. The semantics of that 115 // variable are confusing, and expose clients to implementation details of saveLayer and 116 // image filters. 117 bool allowFragCoord = false; 118 }; 119 120 // If the effect is compiled successfully, `effect` will be non-null. 121 // Otherwise, `errorText` will contain the reason for failure. 122 struct Result { 123 sk_sp<SkRuntimeEffect> effect; 124 SkString errorText; 125 }; 126 127 // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of 128 // the Skia pipeline. In all of the signatures described below, color parameters and return 129 // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or 130 // 'float4'. ('vec4' is an alias for 'float4'). 131 132 // We can't use a default argument for `options` due to a bug in Clang. 133 // https://bugs.llvm.org/show_bug.cgi?id=36684 134 135 // Color filter SkSL requires an entry point that looks like: 136 // vec4 main(vec4 inColor) { ... } 137 static Result MakeForColorFilter(SkString sksl, const Options&); MakeForColorFilter(SkString sksl)138 static Result MakeForColorFilter(SkString sksl) { 139 return MakeForColorFilter(std::move(sksl), Options{}); 140 } 141 142 // Shader SkSL requires an entry point that looks like: 143 // vec4 main(vec2 inCoords) { ... } 144 // -or- 145 // vec4 main(vec2 inCoords, vec4 inColor) { ... } 146 // 147 // Most shaders don't use the input color, so that parameter is optional. 148 static Result MakeForShader(SkString sksl, const Options&); MakeForShader(SkString sksl)149 static Result MakeForShader(SkString sksl) { 150 return MakeForShader(std::move(sksl), Options{}); 151 } 152 153 // Blend SkSL requires an entry point that looks like: 154 // vec4 main(vec4 srcColor, vec4 dstColor) { ... } 155 static Result MakeForBlender(SkString sksl, const Options&); MakeForBlender(SkString sksl)156 static Result MakeForBlender(SkString sksl) { 157 return MakeForBlender(std::move(sksl), Options{}); 158 } 159 160 // DSL entry points 161 static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program, const Options&); 162 static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program); 163 164 static Result MakeForShader(std::unique_ptr<SkSL::Program> program, const Options&); 165 static Result MakeForShader(std::unique_ptr<SkSL::Program> program); 166 167 static Result MakeForBlender(std::unique_ptr<SkSL::Program> program, const Options&); 168 static Result MakeForBlender(std::unique_ptr<SkSL::Program> program); 169 170 // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child 171 class ChildPtr { 172 public: 173 ChildPtr() = default; ChildPtr(sk_sp<SkShader> s)174 ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {} ChildPtr(sk_sp<SkColorFilter> cf)175 ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {} ChildPtr(sk_sp<SkBlender> b)176 ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {} 177 178 skstd::optional<ChildType> type() const; 179 180 SkShader* shader() const; 181 SkColorFilter* colorFilter() const; 182 SkBlender* blender() const; flattenable()183 SkFlattenable* flattenable() const { return fChild.get(); } 184 185 private: 186 sk_sp<SkFlattenable> fChild; 187 }; 188 189 sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms, 190 sk_sp<SkShader> children[], 191 size_t childCount, 192 const SkMatrix* localMatrix, 193 bool isOpaque) const; 194 sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms, 195 SkSpan<ChildPtr> children, 196 const SkMatrix* localMatrix, 197 bool isOpaque) const; 198 199 sk_sp<SkImage> makeImage(GrRecordingContext*, 200 sk_sp<SkData> uniforms, 201 SkSpan<ChildPtr> children, 202 const SkMatrix* localMatrix, 203 SkImageInfo resultInfo, 204 bool mipmapped) const; 205 206 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms) const; 207 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms, 208 sk_sp<SkColorFilter> children[], 209 size_t childCount) const; 210 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms, 211 SkSpan<ChildPtr> children) const; 212 213 sk_sp<SkBlender> makeBlender(sk_sp<SkData> uniforms, SkSpan<ChildPtr> children = {}) const; 214 215 const std::string& source() const; 216 217 // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader, 218 // provide an SkData of this size, containing values for all of those variables. 219 size_t uniformSize() const; 220 uniforms()221 SkSpan<const Uniform> uniforms() const { return SkMakeSpan(fUniforms); } children()222 SkSpan<const Child> children() const { return SkMakeSpan(fChildren); } 223 224 // Returns pointer to the named uniform variable's description, or nullptr if not found 225 const Uniform* findUniform(const char* name) const; 226 227 // Returns pointer to the named child's description, or nullptr if not found 228 const Child* findChild(const char* name) const; 229 230 // Advanced Filter: get AF state 231 bool getAF() const; 232 233 static void RegisterFlattenables(); 234 ~SkRuntimeEffect() override; 235 236 private: 237 enum Flags { 238 kUsesSampleCoords_Flag = 0x1, 239 kAllowColorFilter_Flag = 0x2, 240 kAllowShader_Flag = 0x4, 241 kAllowBlender_Flag = 0x8, 242 kSamplesOutsideMain_Flag = 0x10, 243 }; 244 245 SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram, 246 const Options& options, 247 const SkSL::FunctionDefinition& main, 248 std::vector<Uniform>&& uniforms, 249 std::vector<Child>&& children, 250 std::vector<SkSL::SampleUsage>&& sampleUsages, 251 uint32_t flags); 252 253 static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind); 254 255 static Result MakeFromDSL(std::unique_ptr<SkSL::Program> program, 256 const Options& options, 257 SkSL::ProgramKind kind); 258 259 static Result MakeInternal(std::unique_ptr<SkSL::Program> program, 260 const Options& options, 261 SkSL::ProgramKind kind); 262 hash()263 uint32_t hash() const { return fHash; } usesSampleCoords()264 bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } allowShader()265 bool allowShader() const { return (fFlags & kAllowShader_Flag); } allowColorFilter()266 bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } allowBlender()267 bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } samplesOutsideMain()268 bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } 269 270 const SkFilterColorProgram* getFilterColorProgram(); 271 272 #if SK_SUPPORT_GPU 273 friend class GrSkSLFP; // fBaseProgram, fSampleUsages 274 friend class GrGLSLSkSLFP; // 275 #endif 276 277 friend class SkRTShader; // fBaseProgram, fMain 278 friend class SkRuntimeBlender; // 279 friend class SkRuntimeColorFilter; // 280 281 friend class SkFilterColorProgram; 282 friend class SkRuntimeEffectPriv; 283 284 uint32_t fHash; 285 286 std::unique_ptr<SkSL::Program> fBaseProgram; 287 const SkSL::FunctionDefinition& fMain; 288 std::vector<Uniform> fUniforms; 289 std::vector<Child> fChildren; 290 std::vector<SkSL::SampleUsage> fSampleUsages; 291 292 std::unique_ptr<SkFilterColorProgram> fFilterColorProgram; 293 294 uint32_t fFlags; // Flags 295 }; 296 297 /** Base class for SkRuntimeShaderBuilder, defined below. */ 298 class SkRuntimeEffectBuilder { 299 public: 300 struct BuilderUniform { 301 // Copy 'val' to this variable. No type conversion is performed - 'val' must be same 302 // size as expected by the effect. Information about the variable can be queried by 303 // looking at fVar. If the size is incorrect, no copy will be performed, and debug 304 // builds will abort. If this is the result of querying a missing variable, fVar will 305 // be nullptr, and assigning will also do nothing (and abort in debug builds). 306 template <typename T> 307 std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=( 308 const T& val) { 309 if (!fVar) { 310 SkDEBUGFAIL("Assigning to missing variable"); 311 } else if (sizeof(val) != fVar->sizeInBytes()) { 312 SkDEBUGFAIL("Incorrect value size"); 313 } else { 314 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), 315 &val, sizeof(val)); 316 } 317 return *this; 318 } 319 320 BuilderUniform& operator=(const SkMatrix& val) { 321 if (!fVar) { 322 SkDEBUGFAIL("Assigning to missing variable"); 323 } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { 324 SkDEBUGFAIL("Incorrect value size"); 325 } else { 326 float* data = SkTAddOffset<float>(fOwner->writableUniformData(), 327 (ptrdiff_t)fVar->offset); 328 data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6); 329 data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7); 330 data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8); 331 } 332 return *this; 333 } 334 335 template <typename T> setBuilderUniform336 bool set(const T val[], const int count) { 337 static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); 338 if (!fVar) { 339 SkDEBUGFAIL("Assigning to missing variable"); 340 return false; 341 } else if (sizeof(T) * count != fVar->sizeInBytes()) { 342 SkDEBUGFAIL("Incorrect value size"); 343 return false; 344 } else { 345 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), 346 val, sizeof(T) * count); 347 } 348 return true; 349 } 350 351 SkRuntimeEffectBuilder* fOwner; 352 const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found 353 }; 354 355 struct BuilderChild { 356 template <typename T> BuilderChild& operator=(sk_sp<T> val) { 357 if (!fChild) { 358 SkDEBUGFAIL("Assigning to missing child"); 359 } else { 360 fOwner->fChildren[(size_t)fChild->index] = std::move(val); 361 } 362 return *this; 363 } 364 365 BuilderChild& operator=(std::nullptr_t) { 366 if (!fChild) { 367 SkDEBUGFAIL("Assigning to missing child"); 368 } else { 369 fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; 370 } 371 return *this; 372 } 373 374 SkRuntimeEffectBuilder* fOwner; 375 const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found 376 }; 377 effect()378 const SkRuntimeEffect* effect() const { return fEffect.get(); } 379 uniform(const char * name)380 BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; } child(const char * name)381 BuilderChild child(const char* name) { 382 const SkRuntimeEffect::Child* child = fEffect->findChild(name); 383 return { this, child }; 384 } 385 386 protected: 387 SkRuntimeEffectBuilder() = delete; SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)388 explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect) 389 : fEffect(std::move(effect)) 390 , fUniforms(SkData::MakeUninitialized(fEffect->uniformSize())) 391 , fChildren(fEffect->children().size()) {} 392 393 SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; 394 SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; 395 396 SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; 397 SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; 398 uniforms()399 sk_sp<SkData> uniforms() { return fUniforms; } children()400 SkRuntimeEffect::ChildPtr* children() { return fChildren.data(); } numChildren()401 size_t numChildren() { return fChildren.size(); } 402 403 private: writableUniformData()404 void* writableUniformData() { 405 if (!fUniforms->unique()) { 406 fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); 407 } 408 return fUniforms->writable_data(); 409 } 410 411 sk_sp<SkRuntimeEffect> fEffect; 412 sk_sp<SkData> fUniforms; 413 std::vector<SkRuntimeEffect::ChildPtr> fChildren; 414 }; 415 416 /** 417 * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects. 418 * 419 * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change! 420 * 421 * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and 422 * provides named access to the 'uniform' variables in that block, as well as named access 423 * to a list of child shader slots. Usage: 424 * 425 * sk_sp<SkRuntimeEffect> effect = ...; 426 * SkRuntimeShaderBuilder builder(effect); 427 * builder.uniform("some_uniform_float") = 3.14f; 428 * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...); 429 * builder.child("some_child_effect") = mySkImage->makeShader(...); 430 * ... 431 * sk_sp<SkShader> shader = builder.makeShader(nullptr, false); 432 * 433 * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect, 434 * so can be used as-is or serve as inspiration for other interfaces or binding techniques. 435 */ 436 class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder { 437 public: 438 explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>); 439 // This is currently required by Android Framework but may go away if that dependency 440 // can be removed. 441 SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default; 442 ~SkRuntimeShaderBuilder(); 443 444 sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque); 445 sk_sp<SkImage> makeImage(GrRecordingContext*, 446 const SkMatrix* localMatrix, 447 SkImageInfo resultInfo, 448 bool mipmapped); 449 450 private: 451 using INHERITED = SkRuntimeEffectBuilder; 452 }; 453 454 /** 455 * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders. 456 */ 457 class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder { 458 public: 459 explicit SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect>); 460 ~SkRuntimeBlendBuilder(); 461 462 SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete; 463 SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete; 464 465 sk_sp<SkBlender> makeBlender(); 466 467 private: 468 using INHERITED = SkRuntimeEffectBuilder; 469 }; 470 471 #endif // SK_ENABLE_SKSL 472 473 #endif // SkRuntimeEffect_DEFINED 474