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