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