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