1 /* 2 * Copyright 2018 Google Inc. 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 GrSkSLFP_DEFINED 9 #define GrSkSLFP_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 #include "include/effects/SkRuntimeEffect.h" 13 #include "include/gpu/GrContextOptions.h" 14 #include "include/private/SkVx.h" 15 #include "src/gpu/GrFragmentProcessor.h" 16 17 #include <atomic> 18 #include <utility> 19 #include <vector> 20 21 class GrShaderCaps; 22 class SkData; 23 class SkRuntimeEffect; 24 25 #ifdef SK_DEBUG 26 // UNIFORM_TYPE allows C++ types to be mapped onto SkRuntimeEffect::Uniform::Type 27 template <typename T> struct GrFPUniformType { 28 template <typename U> struct add_a_UNIFORM_TYPE_specialization_for {}; 29 static constexpr add_a_UNIFORM_TYPE_specialization_for<T> value = {}; 30 }; 31 #define UNIFORM_TYPE(E, ...) \ 32 template <> struct GrFPUniformType<__VA_ARGS__> { \ 33 static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \ 34 }; \ 35 template <> struct GrFPUniformType<SkSpan<__VA_ARGS__>> { \ 36 static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \ 37 } 38 39 UNIFORM_TYPE(kFloat, float); 40 UNIFORM_TYPE(kFloat2, SkV2); 41 UNIFORM_TYPE(kFloat4, SkPMColor4f); 42 UNIFORM_TYPE(kFloat4, SkRect); 43 UNIFORM_TYPE(kFloat4, SkV4); 44 UNIFORM_TYPE(kFloat4, skvx::Vec<4, float>); 45 UNIFORM_TYPE(kFloat4x4, SkM44); 46 UNIFORM_TYPE(kInt, int); 47 48 #undef UNIFORM_TYPE 49 #endif 50 51 class GrSkSLFP : public GrFragmentProcessor { 52 public: 53 // Advanced Filter: Overwrite parent's method, check if AF is enabled from fEffect isAFEnabled()54 virtual bool isAFEnabled() const override 55 { 56 return fEffect != nullptr ? fEffect->getAF() : false; 57 } 58 59 template <typename T> struct GrSpecializedUniform { 60 bool specialize; 61 T value; 62 }; 63 template <typename T> Specialize(const T & value)64 static GrSpecializedUniform<T> Specialize(const T& value) { 65 return {true, value}; 66 } 67 template <typename T> SpecializeIf(bool condition,const T & value)68 static GrSpecializedUniform<T> SpecializeIf(bool condition, const T& value) { 69 return {condition, value}; 70 } 71 72 template <typename T> struct GrOptionalUniform { 73 bool enabled; 74 T value; 75 }; 76 template <typename T> When(bool condition,const T & value)77 static GrOptionalUniform<T> When(bool condition, const T& value) { 78 return {condition, value}; 79 } 80 81 struct GrIgnoreOptFlags { 82 std::unique_ptr<GrFragmentProcessor> child; 83 }; IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child)84 static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child) { 85 return {std::move(child)}; 86 } 87 88 enum class OptFlags : uint32_t { 89 kNone = kNone_OptimizationFlags, 90 kCompatibleWithCoverageAsAlpha = kCompatibleWithCoverageAsAlpha_OptimizationFlag, 91 kPreservesOpaqueInput = kPreservesOpaqueInput_OptimizationFlag, 92 kAll = kCompatibleWithCoverageAsAlpha | kPreservesOpaqueInput, 93 }; 94 95 /** 96 * Both factories support a single 'input' FP, as well as a collection of other 'child' FPs. 97 * The 'child' FPs correspond to the children declared in the effect's SkSL. The inputFP is 98 * optional, and intended for instances that have color filter semantics. This is an implicit 99 * child - if present, it's evaluated to produce the input color fed to the SkSL. Otherwise, 100 * the SkSL receives this FP's input color directly. 101 */ 102 103 /** 104 * Creates a new fragment processor from an SkRuntimeEffect and a data blob containing values 105 * for all of the 'uniform' variables in the SkSL source. The layout of the uniforms blob is 106 * dictated by the SkRuntimeEffect. 107 */ 108 static std::unique_ptr<GrSkSLFP> MakeWithData( 109 sk_sp<SkRuntimeEffect> effect, 110 const char* name, 111 std::unique_ptr<GrFragmentProcessor> inputFP, 112 std::unique_ptr<GrFragmentProcessor> destColorFP, 113 sk_sp<SkData> uniforms, 114 SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs); 115 116 /* 117 * Constructs a GrSkSLFP from a series of name-value pairs, corresponding to the children and 118 * uniform data members of the effect's SkSL. 119 * The variable length args... must contain all of the children and uniforms expected. 120 * Each individual argument must be preceded by a name that matches the SkSL name of the value 121 * being set. For children, the next argument must be a std::unique_ptr<GrFragmentProcessor>. 122 * For uniforms, the next argument must be data of the correct size and type. 123 * 124 * For example, given: 125 * uniform shader child; 126 * uniform float scale; 127 * uniform half2 pt; 128 * half4 main() { ... } 129 * 130 * A call to GrSkSLFP would be formatted like: 131 * std::unique_ptr<GrFragmentProcessor> child = ...; 132 * float scaleVal = ...; 133 * SkV2 ptVal = ...; 134 * auto fp = GrSkSLFP::Make(effect, "my_effect", nullptr, GrSkSLFP::OptFlags::..., 135 * "child", std::move(child), 136 * "scale", scaleVal, 137 * "pt", ptVal); 138 * 139 * The uniforms must appear in the correct order, as must the children. Technically, the two 140 * lists can be interleaved. In debug builds, the number, names, and sizes of all arguments are 141 * checked with assertions. In release builds, all checks are elided. In either case, the 142 * uniform data is directly copied into the footer allocated after the FP. 143 */ 144 template <typename... Args> Make(sk_sp<SkRuntimeEffect> effect,const char * name,std::unique_ptr<GrFragmentProcessor> inputFP,OptFlags optFlags,Args &&...args)145 static std::unique_ptr<GrSkSLFP> Make(sk_sp<SkRuntimeEffect> effect, 146 const char* name, 147 std::unique_ptr<GrFragmentProcessor> inputFP, 148 OptFlags optFlags, 149 Args&&... args) { 150 #ifdef SK_DEBUG 151 checkArgs(effect->fUniforms.begin(), 152 effect->fUniforms.end(), 153 effect->fChildren.begin(), 154 effect->fChildren.end(), 155 std::forward<Args>(args)...); 156 #endif 157 158 size_t uniformPayloadSize = UniformPayloadSize(effect.get()); 159 std::unique_ptr<GrSkSLFP> fp(new (uniformPayloadSize) 160 GrSkSLFP(std::move(effect), name, optFlags)); 161 fp->appendArgs(fp->uniformData(), fp->uniformFlags(), std::forward<Args>(args)...); 162 if (inputFP) { 163 fp->setInput(std::move(inputFP)); 164 } 165 return fp; 166 } 167 name()168 const char* name() const override { return fName; } 169 std::unique_ptr<GrFragmentProcessor> clone() const override; 170 171 private: 172 class Impl; 173 174 GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags); 175 GrSkSLFP(const GrSkSLFP& other); 176 177 void addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags); 178 void setInput(std::unique_ptr<GrFragmentProcessor> input); 179 void setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP); 180 181 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 182 183 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 184 185 bool onIsEqual(const GrFragmentProcessor&) const override; 186 187 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override; 188 189 // An instance of GrSkSLFP is always allocated with a payload immediately following the FP. 190 // First the values of all the uniforms, and then a set of flags (one per uniform). UniformPayloadSize(const SkRuntimeEffect * effect)191 static size_t UniformPayloadSize(const SkRuntimeEffect* effect) { 192 return effect->uniformSize() + effect->uniforms().size() * sizeof(UniformFlags); 193 } 194 uniformData()195 const uint8_t* uniformData() const { return reinterpret_cast<const uint8_t*>(this + 1); } uniformData()196 uint8_t* uniformData() { return reinterpret_cast< uint8_t*>(this + 1); } 197 198 enum UniformFlags : uint8_t { 199 kSpecialize_Flag = 0x1, 200 }; 201 uniformFlags()202 const UniformFlags* uniformFlags() const { 203 return reinterpret_cast<const UniformFlags*>(this->uniformData() + fUniformSize); 204 } uniformFlags()205 UniformFlags* uniformFlags() { 206 return reinterpret_cast<UniformFlags*>(this->uniformData() + fUniformSize); 207 } 208 209 // Helpers to attach variadic template args to a newly constructed FP: 210 appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr)211 void appendArgs(uint8_t* uniformDataPtr, UniformFlags* uniformFlagsPtr) { 212 // Base case -- no more args to append, so we're done 213 } 214 template <typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,std::unique_ptr<GrFragmentProcessor> && child,Args &&...remainder)215 void appendArgs(uint8_t* uniformDataPtr, 216 UniformFlags* uniformFlagsPtr, 217 const char* name, 218 std::unique_ptr<GrFragmentProcessor>&& child, 219 Args&&... remainder) { 220 // Child FP case -- register the child, then continue processing the remaining arguments. 221 // Children aren't "uniforms" here, so the data & flags pointers don't advance. 222 this->addChild(std::move(child), /*mergeOptFlags=*/true); 223 this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...); 224 } 225 // As above, but we don't merge in the child's optimization flags 226 template <typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,GrIgnoreOptFlags && child,Args &&...remainder)227 void appendArgs(uint8_t* uniformDataPtr, 228 UniformFlags* uniformFlagsPtr, 229 const char* name, 230 GrIgnoreOptFlags&& child, 231 Args&&... remainder) { 232 // Child FP case -- register the child, then continue processing the remaining arguments. 233 // Children aren't "uniforms" here, so the data & flags pointers don't advance. 234 this->addChild(std::move(child.child), /*mergeOptFlags=*/false); 235 this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...); 236 } 237 template <typename T, typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const GrSpecializedUniform<T> & val,Args &&...remainder)238 void appendArgs(uint8_t* uniformDataPtr, 239 UniformFlags* uniformFlagsPtr, 240 const char* name, 241 const GrSpecializedUniform<T>& val, 242 Args&&... remainder) { 243 // Specialized uniform case -- This just handles the specialization logic. If we want to 244 // specialize on this particular value, set the flag. Then, continue processing the actual 245 // value (by just peeling off the wrapper). This lets our generic `const T&` case (below) 246 // handle copying the data into our uniform block, and advancing the per-value uniform 247 // data and flags pointers. 248 if (val.specialize) { 249 *uniformFlagsPtr = static_cast<UniformFlags>(*uniformFlagsPtr | kSpecialize_Flag); 250 } 251 this->appendArgs( 252 uniformDataPtr, uniformFlagsPtr, name, val.value, std::forward<Args>(remainder)...); 253 } 254 template <typename T, typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const GrOptionalUniform<T> & val,Args &&...remainder)255 void appendArgs(uint8_t* uniformDataPtr, 256 UniformFlags* uniformFlagsPtr, 257 const char* name, 258 const GrOptionalUniform<T>& val, 259 Args&&... remainder) { 260 // Optional uniform case. Copy the data and advance pointers, but only if the uniform is 261 // enabled. Then proceed as normal. 262 if (val.enabled) { 263 memcpy(uniformDataPtr, &val.value, sizeof(val.value)); 264 uniformDataPtr += sizeof(val.value); 265 uniformFlagsPtr++; 266 } 267 268 this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...); 269 } 270 template <typename T, typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,SkSpan<T> val,Args &&...remainder)271 void appendArgs(uint8_t* uniformDataPtr, 272 UniformFlags* uniformFlagsPtr, 273 const char* name, 274 SkSpan<T> val, 275 Args&&... remainder) { 276 // Uniform array case -- We copy the supplied values into our uniform data area, 277 // then advance our uniform data and flags pointers. 278 memcpy(uniformDataPtr, val.data(), val.size_bytes()); 279 uniformDataPtr += val.size_bytes(); 280 uniformFlagsPtr++; 281 this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...); 282 } 283 template <typename T, typename... Args> appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const T & val,Args &&...remainder)284 void appendArgs(uint8_t* uniformDataPtr, 285 UniformFlags* uniformFlagsPtr, 286 const char* name, 287 const T& val, 288 Args&&... remainder) { 289 // Raw uniform value case -- We copy the supplied value into our uniform data area, 290 // then advance our uniform data and flags pointers. 291 memcpy(uniformDataPtr, &val, sizeof(val)); 292 uniformDataPtr += sizeof(val); 293 uniformFlagsPtr++; 294 this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...); 295 } 296 297 #ifdef SK_DEBUG 298 using child_iterator = std::vector<SkRuntimeEffect::Child>::const_iterator; 299 using uniform_iterator = std::vector<SkRuntimeEffect::Uniform>::const_iterator; 300 301 // Validates that all args passed to the template factory have the right names, sizes, and types checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd)302 static void checkArgs(uniform_iterator uIter, 303 uniform_iterator uEnd, 304 child_iterator cIter, 305 child_iterator cEnd) { 306 SkASSERTF(uIter == uEnd, "Expected more uniforms, starting with '%s'", uIter->name.c_str()); 307 SkASSERTF(cIter == cEnd, "Expected more children, starting with '%s'", cIter->name.c_str()); 308 } checkOneChild(child_iterator cIter,child_iterator cEnd,const char * name)309 static void checkOneChild(child_iterator cIter, child_iterator cEnd, const char* name) { 310 SkASSERTF(cIter != cEnd, "Too many children, wasn't expecting '%s'", name); 311 SkASSERTF(cIter->name.equals(name), 312 "Expected child '%s', got '%s' instead", 313 cIter->name.c_str(), name); 314 } 315 template <typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,std::unique_ptr<GrFragmentProcessor> && child,Args &&...remainder)316 static void checkArgs(uniform_iterator uIter, 317 uniform_iterator uEnd, 318 child_iterator cIter, 319 child_iterator cEnd, 320 const char* name, 321 std::unique_ptr<GrFragmentProcessor>&& child, 322 Args&&... remainder) { 323 // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately 324 // does not use it. We leave it intact, and our caller (Make) will pass another rvalue 325 // reference to appendArgs, which will then move it to call addChild. 326 checkOneChild(cIter, cEnd, name); 327 checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...); 328 } 329 template <typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,GrIgnoreOptFlags && child,Args &&...remainder)330 static void checkArgs(uniform_iterator uIter, 331 uniform_iterator uEnd, 332 child_iterator cIter, 333 child_iterator cEnd, 334 const char* name, 335 GrIgnoreOptFlags&& child, 336 Args&&... remainder) { 337 // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately 338 // does not use it. We leave it intact, and our caller (Make) will pass another rvalue 339 // reference to appendArgs, which will then move it to call addChild. 340 checkOneChild(cIter, cEnd, name); 341 checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...); 342 } 343 template <typename T, typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const GrSpecializedUniform<T> & val,Args &&...remainder)344 static void checkArgs(uniform_iterator uIter, 345 uniform_iterator uEnd, 346 child_iterator cIter, 347 child_iterator cEnd, 348 const char* name, 349 const GrSpecializedUniform<T>& val, 350 Args&&... remainder) { 351 static_assert(!std::is_array<T>::value); // No specializing arrays 352 checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...); 353 } 354 template <typename T, typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const GrOptionalUniform<T> & val,Args &&...remainder)355 static void checkArgs(uniform_iterator uIter, 356 uniform_iterator uEnd, 357 child_iterator cIter, 358 child_iterator cEnd, 359 const char* name, 360 const GrOptionalUniform<T>& val, 361 Args&&... remainder) { 362 if (val.enabled) { 363 checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...); 364 } else { 365 checkArgs(uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...); 366 } 367 } 368 template <typename T> checkOneUniform(uniform_iterator uIter,uniform_iterator uEnd,const char * name,const T *,size_t valSize)369 static void checkOneUniform(uniform_iterator uIter, 370 uniform_iterator uEnd, 371 const char* name, 372 const T* /*val*/, 373 size_t valSize) { 374 SkASSERTF(uIter != uEnd, "Too many uniforms, wasn't expecting '%s'", name); 375 SkASSERTF(uIter->name.equals(name), 376 "Expected uniform '%s', got '%s' instead", 377 uIter->name.c_str(), name); 378 SkASSERTF(uIter->sizeInBytes() == valSize, 379 "Expected uniform '%s' to be %zu bytes, got %zu instead", 380 name, uIter->sizeInBytes(), valSize); 381 SkASSERTF(GrFPUniformType<T>::value == uIter->type, 382 "Wrong type for uniform '%s'", 383 name); 384 } 385 template <typename T, typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,SkSpan<T> val,Args &&...remainder)386 static void checkArgs(uniform_iterator uIter, 387 uniform_iterator uEnd, 388 child_iterator cIter, 389 child_iterator cEnd, 390 const char* name, 391 SkSpan<T> val, 392 Args&&... remainder) { 393 checkOneUniform(uIter, uEnd, name, val.data(), val.size_bytes()); 394 checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...); 395 } 396 template <typename T, typename... Args> checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const T & val,Args &&...remainder)397 static void checkArgs(uniform_iterator uIter, 398 uniform_iterator uEnd, 399 child_iterator cIter, 400 child_iterator cEnd, 401 const char* name, 402 const T& val, 403 Args&&... remainder) { 404 checkOneUniform(uIter, uEnd, name, &val, sizeof(val)); 405 checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...); 406 } 407 #endif 408 409 sk_sp<SkRuntimeEffect> fEffect; 410 const char* fName; 411 uint32_t fUniformSize; 412 int fInputChildIndex = -1; 413 int fDestColorChildIndex = -1; 414 415 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 416 417 using INHERITED = GrFragmentProcessor; 418 419 friend class GrSkSLFPFactory; 420 }; 421 422 GR_MAKE_BITFIELD_CLASS_OPS(GrSkSLFP::OptFlags) 423 424 #endif 425