Flutter Engine
The Flutter Engine
GrSkSLFP.cpp
Go to the documentation of this file.
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
9
12#include "include/core/SkData.h"
22#include "src/base/SkRandom.h"
29#include "src/gpu/KeyBuilder.h"
36#include "src/sksl/SkSLString.h"
37#include "src/sksl/SkSLUtil.h"
44
45#include <algorithm>
46
47namespace SkSL { class Context; }
48struct GrShaderCaps;
49
51public:
52 void emitCode(EmitArgs& args) override {
53 const GrSkSLFP& fp = args.fFp.cast<GrSkSLFP>();
54 const SkSL::Program& program = *fp.fEffect->fBaseProgram;
55
56 class FPCallbacks : public SkSL::PipelineStage::Callbacks {
57 public:
58 FPCallbacks(Impl* self,
60 const char* inputColor,
61 const SkSL::Context& context,
62 const uint8_t* uniformData,
63 const Specialized* specialized)
64 : fSelf(self)
65 , fArgs(args)
66 , fInputColor(inputColor)
67 , fContext(context)
68 , fUniformData(uniformData)
69 , fSpecialized(specialized) {}
70
71 std::string declareUniform(const SkSL::VarDeclaration* decl) override {
72 const SkSL::Variable* var = decl->var();
73 if (var->type().isOpaque()) {
74 // Nothing to do. The only opaque types we should see are children, and those
75 // are handled specially.
76 SkASSERT(var->type().isEffectChild());
77 return std::string(var->name());
78 }
79
80 const SkSL::Type* type = &var->type();
81 size_t sizeInBytes = type->slotCount() * sizeof(float);
82 const float* floatData = reinterpret_cast<const float*>(fUniformData);
83 const int* intData = reinterpret_cast<const int*>(fUniformData);
84 fUniformData += sizeInBytes;
85
86 bool isArray = false;
87 if (type->isArray()) {
88 type = &type->componentType();
89 isArray = true;
90 }
91
92 SkSLType gpuType;
94
95 if (*fSpecialized++ == Specialized::kYes) {
96 SkASSERTF(!isArray, "specializing array uniforms is not allowed");
97 std::string value = SkSLTypeString(gpuType);
98 value.append("(");
99
100 bool isFloat = SkSLTypeIsFloatType(gpuType);
101 size_t slots = type->slotCount();
102 for (size_t i = 0; i < slots; ++i) {
103 value.append(isFloat ? skstd::to_string(floatData[i])
104 : std::to_string(intData[i]));
105 value.append(",");
106 }
107 value.back() = ')';
108 return value;
109 }
110
111 const char* uniformName = nullptr;
112 auto handle =
113 fArgs.fUniformHandler->addUniformArray(&fArgs.fFp.cast<GrSkSLFP>(),
115 gpuType,
116 SkString(var->name()).c_str(),
117 isArray ? var->type().columns() : 0,
118 &uniformName);
119 fSelf->fUniformHandles.push_back(handle);
120 return std::string(uniformName);
121 }
122
123 std::string getMangledName(const char* name) override {
124 return std::string(fArgs.fFragBuilder->getMangledFunctionName(name).c_str());
125 }
126
127 void defineFunction(const char* decl, const char* body, bool isMain) override {
128 if (isMain) {
129 fArgs.fFragBuilder->codeAppend(body);
130 } else {
131 fArgs.fFragBuilder->emitFunction(decl, body);
132 }
133 }
134
135 void declareFunction(const char* decl) override {
136 fArgs.fFragBuilder->emitFunctionPrototype(decl);
137 }
138
139 void defineStruct(const char* definition) override {
140 fArgs.fFragBuilder->definitionAppend(definition);
141 }
142
143 void declareGlobal(const char* declaration) override {
144 fArgs.fFragBuilder->definitionAppend(declaration);
145 }
146
147 std::string sampleShader(int index, std::string coords) override {
148 // If the child was sampled using the coords passed to main (and they are never
149 // modified), then we will have marked the child as PassThrough. The code generator
150 // doesn't know that, and still supplies coords. Inside invokeChild, we assert that
151 // any coords passed for a PassThrough child match args.fSampleCoords exactly.
152 //
153 // Normally, this is valid. Here, we *copied* the sample coords to a local variable
154 // (so that they're mutable in the runtime effect SkSL). Thus, the coords string we
155 // get here is the name of the local copy, and fSampleCoords still points to the
156 // unmodified original (which might be a varying, for example).
157 // To prevent the assert, we pass the empty string in this case. Note that for
158 // children sampled like this, invokeChild doesn't even use the coords parameter,
159 // except for that assert.
160 const GrFragmentProcessor* child = fArgs.fFp.childProcessor(index);
161 if (child && child->sampleUsage().isPassThrough()) {
162 coords.clear();
163 }
164 return child ? std::string(fSelf->invokeChild(index, fInputColor, fArgs, coords)
165 .c_str())
166 : std::string("half4(0)");
167 }
168
169 std::string sampleColorFilter(int index, std::string color) override {
170 return std::string(fSelf->invokeChild(index,
171 color.empty() ? fInputColor : color.c_str(),
172 fArgs)
173 .c_str());
174 }
175
176 std::string sampleBlender(int index, std::string src, std::string dst) override {
177 if (!fSelf->childProcessor(index)) {
178 return SkSL::String::printf("blend_src_over(%s, %s)", src.c_str(), dst.c_str());
179 }
180 return std::string(
181 fSelf->invokeChild(index, src.c_str(), dst.c_str(), fArgs).c_str());
182 }
183
184 // These intrinsics take and return 3-component vectors, but child FPs operate on
185 // 4-component vectors. We use swizzles here to paper over the difference.
186 std::string toLinearSrgb(std::string color) override {
187 const GrSkSLFP& fp = fArgs.fFp.cast<GrSkSLFP>();
188 if (fp.fToLinearSrgbChildIndex < 0) {
189 return color;
190 }
191 color = SkSL::String::printf("(%s).rgb1", color.c_str());
192 SkString xformedColor = fSelf->invokeChild(
193 fp.fToLinearSrgbChildIndex, color.c_str(), fArgs);
194 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
195 }
196
197 std::string fromLinearSrgb(std::string color) override {
198 const GrSkSLFP& fp = fArgs.fFp.cast<GrSkSLFP>();
199 if (fp.fFromLinearSrgbChildIndex < 0) {
200 return color;
201 }
202 color = SkSL::String::printf("(%s).rgb1", color.c_str());
203 SkString xformedColor = fSelf->invokeChild(
204 fp.fFromLinearSrgbChildIndex, color.c_str(), fArgs);
205 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
206 }
207
208 Impl* fSelf;
209 EmitArgs& fArgs;
210 const char* fInputColor;
211 const SkSL::Context& fContext;
212 const uint8_t* fUniformData;
213 const Specialized* fSpecialized;
214 int fUniformIndex = 0;
215 };
216
217 // If we have an input child, we invoke it now, and make the result of that be the "input
218 // color" for all other purposes later (eg, the default passed via sample calls, etc.)
219 if (fp.fInputChildIndex >= 0) {
220 args.fFragBuilder->codeAppendf("%s = %s;\n",
221 args.fInputColor,
222 this->invokeChild(fp.fInputChildIndex, args).c_str());
223 }
224
225 if (fp.fEffect->allowBlender()) {
226 // If we have an dest-color child, we invoke it now, and make the result of that be the
227 // "dest color" for all other purposes later.
228 if (fp.fDestColorChildIndex >= 0) {
229 args.fFragBuilder->codeAppendf(
230 "%s = %s;\n",
231 args.fDestColor,
232 this->invokeChild(fp.fDestColorChildIndex, args.fDestColor, args).c_str());
233 }
234 } else {
235 // We're not making a blender, so we don't expect a dest-color child FP to exist.
236 SkASSERT(fp.fDestColorChildIndex < 0);
237 }
238
239 // Snap off a global copy of the input color at the start of main. We need this when
240 // we call child processors (particularly from helper functions, which can't "see" the
241 // parameter to main). Even from within main, if the code mutates the parameter, calls to
242 // sample should still be passing the original color (by default).
243 SkString inputColorName;
244 if (fp.fEffect->samplesOutsideMain()) {
245 GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
247 args.fFragBuilder->declareGlobal(inputColorCopy);
248 inputColorName = inputColorCopy.getName();
249 args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorName.c_str(), args.fInputColor);
250 } else {
251 inputColorName = args.fFragBuilder->newTmpVarName("inColor");
252 args.fFragBuilder->codeAppendf(
253 "half4 %s = %s;\n", inputColorName.c_str(), args.fInputColor);
254 }
255
256 // Copy the incoming coords to a local variable. Code in main might modify the coords
257 // parameter. fSampleCoord could be a varying, so writes to it would be illegal.
258 const char* coords = "float2(0)";
259 SkString coordsVarName;
260 if (fp.usesSampleCoordsDirectly()) {
261 coordsVarName = args.fFragBuilder->newTmpVarName("coords");
262 coords = coordsVarName.c_str();
263 args.fFragBuilder->codeAppendf("float2 %s = %s;\n", coords, args.fSampleCoord);
264 }
265
266 FPCallbacks callbacks(this,
267 args,
268 inputColorName.c_str(),
269 *program.fContext,
270 fp.uniformData(),
271 fp.specialized());
273 program, coords, args.fInputColor, args.fDestColor, &callbacks);
274 }
275
276private:
277 void onSetData(const GrGLSLProgramDataManager& pdman,
278 const GrFragmentProcessor& _proc) override {
279 const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
280 pdman.setRuntimeEffectUniforms(outer.fEffect->uniforms(),
281 SkSpan(fUniformHandles),
282 SkSpan(outer.specialized(), outer.uniformCount()),
283 outer.uniformData());
284 }
285
286 std::vector<UniformHandle> fUniformHandles;
287};
288
289std::unique_ptr<GrSkSLFP> GrSkSLFP::MakeWithData(
291 const char* name,
292 sk_sp<SkColorSpace> dstColorSpace,
293 std::unique_ptr<GrFragmentProcessor> inputFP,
294 std::unique_ptr<GrFragmentProcessor> destColorFP,
295 const sk_sp<const SkData>& uniforms,
296 SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs) {
297 if (uniforms->size() != effect->uniformSize()) {
298 return nullptr;
299 }
300 size_t uniformSize = uniforms->size();
301 size_t specializedSize = effect->uniforms().size() * sizeof(Specialized);
302 std::unique_ptr<GrSkSLFP> fp(new (uniformSize + specializedSize)
303 GrSkSLFP(std::move(effect), name, OptFlags::kNone));
304 sk_careful_memcpy(fp->uniformData(), uniforms->data(), uniformSize);
305 for (auto& childFP : childFPs) {
306 fp->addChild(std::move(childFP), /*mergeOptFlags=*/true);
307 }
308 if (inputFP) {
309 fp->setInput(std::move(inputFP));
310 }
311 if (destColorFP) {
312 fp->setDestColorFP(std::move(destColorFP));
313 }
314 if (fp->fEffect->usesColorTransform() && dstColorSpace) {
315 fp->addColorTransformChildren(dstColorSpace.get());
316 }
317 return fp;
318}
319
320GrFragmentProcessor::OptimizationFlags GrSkSLFP::DetermineOptimizationFlags(
321 OptFlags of, SkRuntimeEffect* effect) {
322 OptimizationFlags optFlags = static_cast<OptimizationFlags>(of);
325 }
326 return optFlags;
327}
328
329GrSkSLFP::GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags)
330 : INHERITED(kGrSkSLFP_ClassID, DetermineOptimizationFlags(optFlags, effect.get()))
331 , fEffect(std::move(effect))
332 , fName(name)
333 , fUniformSize(SkToU32(fEffect->uniformSize())) {
334 std::fill_n(this->specialized(), this->uniformCount(), Specialized::kNo);
335 if (fEffect->usesSampleCoords()) {
337 }
338 if (fEffect->allowBlender()) {
339 this->setIsBlendFunction();
340 }
341}
342
343GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
344 : INHERITED(other)
345 , fEffect(other.fEffect)
346 , fName(other.fName)
347 , fUniformSize(other.fUniformSize)
348 , fInputChildIndex(other.fInputChildIndex)
349 , fDestColorChildIndex(other.fDestColorChildIndex)
350 , fToLinearSrgbChildIndex(other.fToLinearSrgbChildIndex)
351 , fFromLinearSrgbChildIndex(other.fFromLinearSrgbChildIndex) {
352 std::copy_n(other.specialized(), this->uniformCount(), this->specialized());
353 sk_careful_memcpy(this->uniformData(), other.uniformData(), fUniformSize);
354}
355
356void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags) {
357 SkASSERTF(fInputChildIndex == -1, "all addChild calls must happen before setInput");
358 SkASSERTF(fDestColorChildIndex == -1, "all addChild calls must happen before setDestColorFP");
359 int childIndex = this->numChildProcessors();
360 SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size());
361 if (mergeOptFlags) {
363 }
365 this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]);
366}
367
368void GrSkSLFP::setInput(std::unique_ptr<GrFragmentProcessor> input) {
369 SkASSERTF(fInputChildIndex == -1, "setInput should not be called more than once");
370 fInputChildIndex = this->numChildProcessors();
371 SkASSERT((size_t)fInputChildIndex >= fEffect->fSampleUsages.size());
373 this->registerChild(std::move(input), SkSL::SampleUsage::PassThrough());
374}
375
376void GrSkSLFP::setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP) {
377 SkASSERTF(fEffect->allowBlender(), "dest colors are only used by blend effects");
378 SkASSERTF(fDestColorChildIndex == -1, "setDestColorFP should not be called more than once");
379 fDestColorChildIndex = this->numChildProcessors();
380 SkASSERT((size_t)fDestColorChildIndex >= fEffect->fSampleUsages.size());
381 this->mergeOptimizationFlags(ProcessorOptimizationFlags(destColorFP.get()));
382 this->registerChild(std::move(destColorFP), SkSL::SampleUsage::PassThrough());
383}
384
385void GrSkSLFP::addColorTransformChildren(SkColorSpace* dstColorSpace) {
386 SkASSERTF(fToLinearSrgbChildIndex == -1 && fFromLinearSrgbChildIndex == -1,
387 "addColorTransformChildren should not be called more than once");
388
389 // We use child FPs for the color transforms. They're really just code snippets that get
390 // invoked, but each one injects a collection of uniforms and helper functions. Doing it
391 // this way leverages per-FP name mangling to avoid conflicts.
392 auto workingToLinear = GrColorSpaceXformEffect::Make(nullptr,
393 dstColorSpace,
397 auto linearToWorking = GrColorSpaceXformEffect::Make(nullptr,
400 dstColorSpace,
402
403 fToLinearSrgbChildIndex = this->numChildProcessors();
404 SkASSERT((size_t)fToLinearSrgbChildIndex >= fEffect->fSampleUsages.size());
405 this->registerChild(std::move(workingToLinear), SkSL::SampleUsage::PassThrough());
406
407 fFromLinearSrgbChildIndex = this->numChildProcessors();
408 SkASSERT((size_t)fFromLinearSrgbChildIndex >= fEffect->fSampleUsages.size());
409 this->registerChild(std::move(linearToWorking), SkSL::SampleUsage::PassThrough());
410}
411
412std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrSkSLFP::onMakeProgramImpl() const {
413 return std::make_unique<Impl>();
414}
415
416void GrSkSLFP::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
417 // In the unlikely event of a hash collision, we also include the uniform size in the key.
418 // That ensures that we will (at worst) use the wrong program, but one that expects the same
419 // amount of uniform data.
420 b->add32(fEffect->hash());
421 b->add32(fUniformSize);
422
423 const Specialized* specialized = this->specialized();
424 const uint8_t* uniformData = this->uniformData();
425 size_t uniformCount = this->uniformCount();
426 auto iter = fEffect->uniforms().begin();
427
428 for (size_t i = 0; i < uniformCount; ++i, ++iter) {
429 bool specialize = specialized[i] == Specialized::kYes;
430 b->addBool(specialize, "specialize");
431 if (specialize) {
432 b->addBytes(iter->sizeInBytes(), uniformData + iter->offset, iter->name);
433 }
434 }
435}
436
437bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
438 const GrSkSLFP& sk = other.cast<GrSkSLFP>();
439 const size_t specializedSize = this->uniformCount() * sizeof(Specialized);
440 return fEffect->hash() == sk.fEffect->hash() &&
441 this->uniformCount() == sk.uniformCount() &&
442 fUniformSize == sk.fUniformSize &&
443 !sk_careful_memcmp(this->uniformData(),
444 sk.uniformData(),
445 fUniformSize + specializedSize);
446}
447
448std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
449 return std::unique_ptr<GrFragmentProcessor>(new (UniformPayloadSize(fEffect.get()))
450 GrSkSLFP(*this));
451}
452
453SkPMColor4f GrSkSLFP::constantOutputForConstantInput(const SkPMColor4f& inputColor) const {
454 SkPMColor4f color = (fInputChildIndex >= 0)
455 ? ConstantOutputForConstantInput(this->childProcessor(fInputChildIndex), inputColor)
456 : inputColor;
457
458 class ConstantOutputForConstantInput_SkRPCallbacks : public SkSL::RP::Callbacks {
459 public:
460 bool appendShader(int index) override {
461 SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
462 return false;
463 }
464 bool appendColorFilter(int index) override {
465 SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
466 return false;
467 }
468 bool appendBlender(int index) override {
469 SkDEBUGFAIL("constant-output-for-constant-input unsupported when child shaders present");
470 return false;
471 }
472 void toLinearSrgb(const void* color) override { /* identity color conversion */ }
473 void fromLinearSrgb(const void* color) override { /* identity color conversion */ }
474 };
475
476 if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
477 // No color conversion is happening here, so we can use untransformed uniforms.
478 SkSpan<const float> uniforms{reinterpret_cast<const float*>(this->uniformData()),
479 fUniformSize / sizeof(float)};
480 SkSTArenaAlloc<2048> alloc; // sufficient for a tiny SkSL program
481 SkRasterPipeline pipeline(&alloc);
482 pipeline.appendConstantColor(&alloc, color.vec());
483 ConstantOutputForConstantInput_SkRPCallbacks callbacks;
484 if (program->appendStages(&pipeline, &alloc, &callbacks, uniforms)) {
485 SkPMColor4f outputColor;
486 SkRasterPipeline_MemoryCtx outputCtx = {&outputColor, 0};
487 pipeline.append(SkRasterPipelineOp::store_f32, &outputCtx);
488 pipeline.run(0, 0, 1, 1);
489 return outputColor;
490 }
491 }
492
493 // We weren't able to run the Raster Pipeline program.
494 return color;
495}
496
497/**************************************************************************************************/
498
500
501#if defined(GR_TEST_UTILS)
502
503std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
505 for (SkColor& c : colors) {
506 c = d->fRandom->nextU();
507 }
509 SkSurfaceProps props; // default props for testing
510 auto [success, fp] = GrFragmentProcessors::Make(
511 d->context(), filter.get(), /*inputFP=*/nullptr, GrColorInfo{}, props);
512 SkASSERT(success);
513 return std::move(fp);
514}
515
516#endif
const char * fName
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(...)
@ kFragment_GrShaderFlag
Definition: GrTypesPriv.h:287
kUnpremul_SkAlphaType
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
SkColorSpace * sk_srgb_linear_singleton()
uint32_t SkColor
Definition: SkColor.h:37
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
Definition: SkMalloc.h:125
static int sk_careful_memcmp(const void *a, const void *b, size_t len)
Definition: SkMalloc.h:143
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
const Context & fContext
const char * SkSLTypeString(SkSLType t)
SkSLType
static constexpr bool SkSLTypeIsFloatType(SkSLType type)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr uint32_t SkToU32(S x)
Definition: SkTo.h:26
GLenum type
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > child, SkColorSpace *src, SkAlphaType srcAT, SkColorSpace *dst, SkAlphaType dstAT)
void clearConstantOutputForConstantInputFlag()
static OptimizationFlags ProcessorOptimizationFlags(const GrFragmentProcessor *fp)
void mergeOptimizationFlags(OptimizationFlags flags)
GrFragmentProcessor * childProcessor(int index)
void registerChild(std::unique_ptr< GrFragmentProcessor > child, SkSL::SampleUsage sampleUsage=SkSL::SampleUsage::PassThrough())
const SkSL::SampleUsage & sampleUsage() const
static SkPMColor4f ConstantOutputForConstantInput(const GrFragmentProcessor *fp, const SkPMColor4f &input)
void setRuntimeEffectUniforms(SkSpan< const SkRuntimeEffect::Uniform >, SkSpan< const UniformHandle >, SkSpan< const Specialized >, const void *src) const
const T & cast() const
Definition: GrProcessor.h:127
const SkString & getName() const
Definition: GrShaderVar.h:91
void emitCode(EmitArgs &args) override
Definition: GrSkSLFP.cpp:52
std::unique_ptr< GrFragmentProcessor > clone() const override
Definition: GrSkSLFP.cpp:448
static std::unique_ptr< GrSkSLFP > MakeWithData(sk_sp< SkRuntimeEffect > effect, const char *name, sk_sp< SkColorSpace > dstColorSpace, std::unique_ptr< GrFragmentProcessor > inputFP, std::unique_ptr< GrFragmentProcessor > destColorFP, const sk_sp< const SkData > &uniforms, SkSpan< std::unique_ptr< GrFragmentProcessor > > childFPs)
Definition: GrSkSLFP.cpp:289
const char * name() const override
Definition: GrSkSLFP.h:186
const void * data() const
Definition: SkData.h:37
size_t size() const
Definition: SkData.h:30
static sk_sp< SkColorFilter > MakeWithSkColors(const SkColor[kNumColors])
static constexpr int kNumColors
static bool SupportsConstantOutputForConstantInput(const SkRuntimeEffect *effect)
size_t uniformSize() const
bool allowBlender() const
SkSpan< const Uniform > uniforms() const
bool isPassThrough() const
static SampleUsage PassThrough()
std::string_view name() const
Definition: SkSLSymbol.h:51
const Type & type() const
Definition: SkSLSymbol.h:42
bool isEffectChild() const
Definition: SkSLType.h:550
bool isOpaque() const
Definition: SkSLType.h:353
virtual int columns() const
Definition: SkSLType.h:429
Variable * var() const
const char * c_str() const
Definition: SkString.h:133
T * get() const
Definition: SkRefCnt.h:303
DlColor color
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
static bool b
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
std::unique_ptr< GrFragmentProcessor > Make(const SkMaskFilter *maskfilter, const GrFPArgs &args, const SkMatrix &ctm)
PODArray< SkColor > colors
Definition: SkRecords.h:276
void ConvertProgram(const Program &program, const char *sampleCoords, const char *inputColor, const char *destColor, Callbacks *callbacks)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
bool type_to_sksltype(const Context &context, const Type &type, SkSLType *outType)
Definition: SkSLUtil.cpp:46
const uint32_t fp
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
dst
Definition: cp.py:12
const myers::Point & get(const myers::Segment &)
std::string to_string(float value)
Definition: SkSLString.cpp:50
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119