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