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