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