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