Flutter Engine
The Flutter Engine
DrawMeshOp.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
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
10#include "include/core/SkData.h"
11#include "include/core/SkMesh.h"
13#include "src/core/SkMeshPriv.h"
17#include "src/gpu/KeyBuilder.h"
32
33using namespace skia_private;
34
35namespace {
36
37GrPrimitiveType primitive_type(SkMesh::Mode mode) {
38 switch (mode) {
41 }
43}
44
45using MeshAttributeType = SkMeshSpecification::Attribute::Type;
46
47GrVertexAttribType attrib_type(MeshAttributeType type) {
48 switch (type) {
50 case MeshAttributeType::kFloat2: return kFloat2_GrVertexAttribType;
51 case MeshAttributeType::kFloat3: return kFloat3_GrVertexAttribType;
52 case MeshAttributeType::kFloat4: return kFloat4_GrVertexAttribType;
53 case MeshAttributeType::kUByte4_unorm: return kUByte4_norm_GrVertexAttribType;
54 }
56}
57
58class MeshGP : public GrGeometryProcessor {
59private:
60 using ChildPtr = SkRuntimeEffect::ChildPtr;
61
62public:
64 SkArenaAlloc* arena,
66 sk_sp<GrColorSpaceXform> colorSpaceXform,
67 const SkMatrix& viewMatrix,
68 const std::optional<SkPMColor4f>& color,
69 bool needsLocalCoords,
70 sk_sp<const SkData> uniforms,
71 SkSpan<std::unique_ptr<GrFragmentProcessor>> children) {
72 return arena->make([&](void* ptr) {
73 return new (ptr) MeshGP(std::move(spec),
74 std::move(colorSpaceXform),
75 viewMatrix,
76 std::move(color),
77 needsLocalCoords,
78 std::move(uniforms),
79 children);
80 });
81 }
82
83 const char* name() const override { return "MeshGP"; }
84
85 void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override {
86 b->add32(SkMeshSpecificationPriv::Hash(*fSpec), "custom mesh spec hash");
87 b->add32(ProgramImpl::ComputeMatrixKey(caps, fViewMatrix), "view matrix key");
89 SkMeshSpecificationPriv::ColorType::kNone) {
90 b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()), "colorspace xform key");
91 }
92 for (const std::unique_ptr<GrFragmentProcessor>& fp : fChildren) {
93 if (fp) {
94 fp->addToKey(caps, b);
95 } else {
96 b->addBool(false, "null effect");
97 }
98 }
99 }
100
101 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
102 return std::make_unique<Impl>();
103 }
104
105private:
106 class Impl : public ProgramImpl {
107 public:
108 void setData(const GrGLSLProgramDataManager& pdman,
109 const GrShaderCaps& shaderCaps,
110 const GrGeometryProcessor& geomProc) override {
111 const auto& mgp = geomProc.cast<MeshGP>();
112 SetTransform(pdman, shaderCaps, fViewMatrixUniform, mgp.fViewMatrix, &fViewMatrix);
113 // Set up uniforms for the color-space transform.
114 fColorSpaceHelper.setData(pdman, mgp.fColorSpaceXform.get());
115 // Assign the paint color to a uniform.
116 if (fColorUniform.isValid()) {
117 pdman.set4fv(fColorUniform, 1, mgp.fColor.vec());
118 }
119 // Update uniforms associated with the mesh vertex/fragment program.
120 if (mgp.fUniforms) {
121 pdman.setRuntimeEffectUniforms(mgp.fSpec->uniforms(),
122 SkSpan(fSpecUniformHandles),
123 mgp.fUniforms->data());
124 }
125 // Recursively update uniforms associated with the mesh child FPs.
126 for (size_t index = 0; index < mgp.fChildren.size(); ++index) {
127 if (const GrFragmentProcessor* fp = mgp.fChildren[index].get()) {
128 GrFragmentProcessor::ProgramImpl* impl = fChildImpls[index].get();
129 SkASSERT(impl);
130
131 fp->visitWithImpls([&](const GrFragmentProcessor& fp,
133 impl.setData(pdman, fp);
134 },
135 *impl);
136 }
137 }
138 }
139
140 private:
141 class MeshCallbacks : public SkSL::PipelineStage::Callbacks {
142 public:
143 MeshCallbacks(Impl* self,
144 const MeshGP& gp,
146 GrGLSLUniformHandler* uniformHandler,
147 const char* mainName,
148 const SkSL::Context& context)
149 : fSelf(self)
150 , fGP(gp)
151 , fBuilder(builder)
152 , fUniformHandler(uniformHandler)
153 , fMainName(mainName)
154 , fContext(context) {}
155
156 std::string declareUniform(const SkSL::VarDeclaration* decl) override {
157 const SkSL::Variable* var = decl->var();
158 if (var->type().isOpaque()) {
159 // Nothing to do. The only opaque types we should see are children, and those
160 // will be handled in the `sample` overloads below.
161 SkASSERT(var->type().isEffectChild());
162 return std::string(var->name());
163 }
164
165 const SkSL::Type* type = &var->type();
166 bool isArray = false;
167 if (type->isArray()) {
168 type = &type->componentType();
169 isArray = true;
170 }
171
172 SkSLType gpuType;
174
175 SkString name(var->name());
176 const SkSpan<const SkMeshSpecification::Uniform> uniforms = fGP.fSpec->uniforms();
177 auto it = std::find_if(uniforms.begin(),
178 uniforms.end(),
180 return uniform.name == std::string_view(name.c_str(), name.size());
181 });
182 SkASSERT(it != uniforms.end());
183
184 size_t handleIdx = std::distance(uniforms.begin(), it);
185 UniformHandle* handle = &fSelf->fSpecUniformHandles[handleIdx];
186 if (handle->isValid()) {
187 const GrShaderVar& uniformVar = fUniformHandler->getUniformVariable(*handle);
188 return std::string(uniformVar.getName().c_str());
189 }
190
191 const SkMeshSpecification::Uniform& uniform = *it;
193 if (uniform.flags & SkMeshSpecification::Uniform::Flags::kVertex_Flag) {
194 shaderFlags |= kVertex_GrShaderFlag;
195 }
196 if (uniform.flags & SkMeshSpecification::Uniform::Flags::kFragment_Flag) {
197 shaderFlags |= kFragment_GrShaderFlag;
198 }
199 SkASSERT(shaderFlags != kNone_GrShaderFlags);
200
201 const char* mangledName = nullptr;
202 *handle = fUniformHandler->addUniformArray(&fGP,
203 shaderFlags,
204 gpuType,
205 name.c_str(),
206 isArray ? var->type().columns() : 0,
207 &mangledName);
208 return std::string(mangledName);
209 }
210
211 std::string getMangledName(const char* name) override {
212 return std::string(fBuilder->getMangledFunctionName(name).c_str());
213 }
214
215 std::string getMainName() override { return fMainName; }
216
217 void defineFunction(const char* decl, const char* body, bool isMain) override {
218 fBuilder->emitFunction(decl, body);
219 }
220
221 void declareFunction(const char* decl) override {
222 fBuilder->emitFunctionPrototype(decl);
223 }
224
225 void defineStruct(const char* definition) override {
226 fBuilder->definitionAppend(definition);
227 }
228
229 void declareGlobal(const char* declaration) override {
230 fBuilder->definitionAppend(declaration);
231 }
232
233 std::string sampleShader(int index, std::string coords) override {
234 const GrFragmentProcessor* fp = fGP.fChildren[index].get();
235 if (!fp) {
236 // For a null shader, return transparent black.
237 return "half4(0)";
238 }
239 GrFragmentProcessor::ProgramImpl* impl = fSelf->fChildImpls[index].get();
240 SkASSERT(impl);
241 return fBuilder->getProgramBuilder()->invokeFP(*fp,
242 *impl,
243 /*inputColor=*/"half4(0)",
244 /*destColor=*/"half4(1)",
245 coords.c_str());
246 }
247
248 std::string sampleColorFilter(int index, std::string color) override {
249 const GrFragmentProcessor* fp = fGP.fChildren[index].get();
250 if (!fp) {
251 // For a null color filter, return the color as-is.
252 return color;
253 }
254 GrFragmentProcessor::ProgramImpl* impl = fSelf->fChildImpls[index].get();
255 SkASSERT(impl);
256 return fBuilder->getProgramBuilder()->invokeFP(*fp,
257 *impl,
258 color.c_str(),
259 /*destColor=*/"half4(1)",
260 /*coords=*/"float2(0)");
261 }
262
263 std::string sampleBlender(int index, std::string src, std::string dst) override {
264 const GrFragmentProcessor* fp = fGP.fChildren[index].get();
265 if (!fp) {
266 // For a null blend, perform src-over.
267 return SkSL::String::printf("blend_src_over(%s, %s)", src.c_str(), dst.c_str());
268 }
269 GrFragmentProcessor::ProgramImpl* impl = fSelf->fChildImpls[index].get();
270 SkASSERT(impl);
271 return fBuilder->getProgramBuilder()->invokeFP(*fp,
272 *impl,
273 src.c_str(),
274 dst.c_str(),
275 /*coords=*/"float2(0)");
276 }
277
278 std::string toLinearSrgb(std::string color) override {
279 SK_ABORT("Color transform intrinsics not allowed.");
280 }
281
282 std::string fromLinearSrgb(std::string Color) override {
283 SK_ABORT("Color transform intrinsics not allowed.");
284 }
285
286 Impl* fSelf;
287 const MeshGP& fGP;
288 GrGLSLShaderBuilder* fBuilder;
289 GrGLSLUniformHandler* fUniformHandler;
290 const char* fMainName;
291 const SkSL::Context& fContext;
292 };
293
294 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
295 const MeshGP& mgp = args.fGeomProc.cast<MeshGP>();
296 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
297 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
298 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
299 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
300 SkSpan<std::unique_ptr<GrFragmentProcessor>> children = mgp.fChildren;
301
302 // Create Impls for any child fragment processors.
303 fChildImpls.reserve_exact(children.size());
304 for (const std::unique_ptr<GrFragmentProcessor>& fp : children) {
305 fChildImpls.push_back(fp ? fp->makeProgramImpl() : nullptr);
306 }
307
308 SkASSERT(fSpecUniformHandles.empty());
309 fSpecUniformHandles.reserve_exact(mgp.fSpec->uniforms().size());
310 fSpecUniformHandles.push_back_n(mgp.fSpec->uniforms().size());
311
312 SkMeshSpecificationPriv::ColorType meshColorType =
314 int passthroughLCVaryingIndex =
316
317 // If the user's fragment shader doesn't output color and we also don't need its local
318 // coords then it isn't necessary to call it at all. We might not need its local coords
319 // because local coords aren't required for the paint or because we detected a
320 // passthrough varying returned from the user's FS.
321 bool needUserFS = (passthroughLCVaryingIndex < 0 && mgp.fNeedsLocalCoords) ||
322 meshColorType != SkMeshSpecificationPriv::ColorType::kNone;
323
324 if (!needUserFS && !mgp.fNeedsLocalCoords) {
325 // Don't bother with it if we don't need it.
326 passthroughLCVaryingIndex = -1;
327 }
328
331
332 ////// VS
333
334 // emit attributes
335 varyingHandler->emitAttributes(mgp);
336
337 // Define the user's vert function.
338 SkString userVertName = vertBuilder->getMangledFunctionName("custom_mesh_vs");
339 const SkSL::Program* customVS = SkMeshSpecificationPriv::VS(*mgp.fSpec);
340 MeshCallbacks vsCallbacks(this,
341 mgp,
342 vertBuilder,
343 uniformHandler,
344 userVertName.c_str(),
345 *customVS->fContext);
347 /*sampleCoords=*/"",
348 /*inputColor=*/"",
349 /*destColor=*/"",
350 &vsCallbacks);
351
352 // Copy the individual attributes into a struct
353 vertBuilder->codeAppendf("%s attributes;",
354 vsCallbacks.getMangledName("Attributes").c_str());
355 {
356 size_t i = 0;
357 SkASSERT(mgp.vertexAttributes().count() == (int)mgp.fSpec->attributes().size());
358 for (auto attr : mgp.vertexAttributes()) {
359 vertBuilder->codeAppendf("attributes.%s = %s;",
360 mgp.fSpec->attributes()[i++].name.c_str(),
361 attr.name());
362 }
363 }
364
365 // Call the user's vert function.
366 vertBuilder->codeAppendf("%s varyings = %s(attributes);",
367 vsCallbacks.getMangledName("Varyings").c_str(),
368 userVertName.c_str());
369
370 if (passthroughLCVaryingIndex >= 0 &&
371 SkMeshSpecificationPriv::VaryingIsDead(*mgp.fSpec, passthroughLCVaryingIndex)) {
372 vertBuilder->codeAppendf("float2 local = varyings.%s\n;",
373 specVaryings[passthroughLCVaryingIndex].name.c_str());
374 gpArgs->fLocalCoordVar = GrShaderVar("local", SkSLType::kFloat2);
375 gpArgs->fLocalCoordShader = kVertex_GrShaderType;
376 }
377
378 // Unpack the "varyings" from the struct into individual real varyings if they are
379 // required.
380 struct RealVarying {
381 size_t specIndex;
382 GrGLSLVarying varying;
383 };
385 if (needUserFS) {
386 for (size_t i = 0; i < specVaryings.size(); ++i) {
387 const auto& v = specVaryings[i];
388 if (SkMeshSpecificationPriv::VaryingIsDead(*mgp.fSpec, i)) {
389 continue;
390 }
392 realVaryings.push_back(rv);
393 varyingHandler->addVarying(v.name.c_str(), &realVaryings.back().varying);
394 vertBuilder->codeAppendf("%s = varyings.%s;",
395 realVaryings.back().varying.vsOut(),
396 v.name.c_str());
397 if (passthroughLCVaryingIndex == SkToInt(i)) {
398 SkASSERT(gpArgs->fLocalCoordVar.getType() == SkSLType::kVoid);
399 gpArgs->fLocalCoordVar = realVaryings.back().varying.vsOutVar();
400 gpArgs->fLocalCoordShader = kVertex_GrShaderType;
401 }
402 }
403 }
404
405 vertBuilder->codeAppend("float2 pos = varyings.position;");
406 // Setup position
407 WriteOutputPosition(vertBuilder,
408 uniformHandler,
409 *args.fShaderCaps,
410 gpArgs,
411 "pos",
412 mgp.fViewMatrix,
413 &fViewMatrixUniform);
414
415 ////// FS
416
417 int samplerIndex = 0;
418 for (size_t fpIdx = 0; fpIdx < mgp.fChildren.size(); ++fpIdx) {
419 if (const GrFragmentProcessor* fp = mgp.fChildren[fpIdx].get()) {
420 GrFragmentProcessor::ProgramImpl* impl = fChildImpls[fpIdx].get();
421 SkASSERT(impl);
422
423 // Hook up sampler handles to texture effects. This code needs to keep
424 // consistent with the code that up sampler handles (in the MeshGP ctor).
425 fp->visitWithImpls([&](const GrFragmentProcessor& fp,
427 if (fp.asTextureEffect()) {
428 static_cast<GrTextureEffect::Impl&>(impl).setSamplerHandle(
429 args.fTexSamplers[samplerIndex++]);
430 }
431 },
432 *impl);
433
434 // Write functions associated with this FP.
435 args.fFragBuilder->getProgramBuilder()->advanceStage();
436 args.fFragBuilder->getProgramBuilder()->writeFPFunction(*fp, *impl);
437 }
438 }
439
440 // Define the user's frag function.
441 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
442 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
443
444 SkString userFragName = fragBuilder->getMangledFunctionName("custom_mesh_fs");
445 const SkSL::Program* customFS = SkMeshSpecificationPriv::FS(*mgp.fSpec);
446 MeshCallbacks fsCallbacks(this,
447 mgp,
448 fragBuilder,
449 uniformHandler,
450 userFragName.c_str(),
451 *customFS->fContext);
453 /*sampleCoords=*/"",
454 /*inputColor=*/"",
455 /*destColor=*/"",
456 &fsCallbacks);
457 const char* uniformColorName = nullptr;
458 if (mgp.fColor != SK_PMColor4fILLEGAL) {
459 fColorUniform = uniformHandler->addUniform(nullptr,
462 "color",
463 &uniformColorName);
464 }
465 if (meshColorType == SkMeshSpecificationPriv::ColorType::kNone) {
466 SkASSERT(uniformColorName);
467 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, uniformColorName);
468 }
469
470 if (needUserFS) {
471 // Pack the real varyings into a struct to call the user's frag code.
472 fragBuilder->codeAppendf("%s varyings;",
473 fsCallbacks.getMangledName("Varyings").c_str());
474 for (const auto& rv : realVaryings) {
475 const auto& v = specVaryings[rv.specIndex];
476 fragBuilder->codeAppendf("varyings.%s = %s;",
477 v.name.c_str(),
478 rv.varying.vsOut());
479 }
480
481 // Grab the return local coords from the user's FS code only if we actually need it.
483 if (gpArgs->fLocalCoordVar.getType() == SkSLType::kVoid && mgp.fNeedsLocalCoords) {
484 gpArgs->fLocalCoordVar = GrShaderVar("local", SkSLType::kFloat2);
485 gpArgs->fLocalCoordShader = kFragment_GrShaderType;
486 local = "float2 local = ";
487 }
488 if (meshColorType == SkMeshSpecificationPriv::ColorType::kNone) {
489 fragBuilder->codeAppendf("%s%s(varyings);",
490 local.c_str(),
491 userFragName.c_str());
492 } else {
493 fColorSpaceHelper.emitCode(uniformHandler,
494 mgp.fColorSpaceXform.get(),
496 if (meshColorType == SkMeshSpecificationPriv::ColorType::kFloat4) {
497 fragBuilder->codeAppendf("float4 color;");
498 } else {
499 SkASSERT(meshColorType == SkMeshSpecificationPriv::ColorType::kHalf4);
500 fragBuilder->codeAppendf("half4 color;");
501 }
502
503 fragBuilder->codeAppendf("%s%s(varyings, color);",
504 local.c_str(),
505 userFragName.c_str());
506 // We ignore the user's color if analysis told us to emit a specific color.
507 // The user color might be float4 and we expect a half4 in the colorspace
508 // helper.
509 const char* color = uniformColorName ? uniformColorName : "half4(color)";
510 SkString xformedColor;
511 fragBuilder->appendColorGamutXform(&xformedColor, color, &fColorSpaceHelper);
512 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
513 }
514 }
515 SkASSERT(!mgp.fNeedsLocalCoords ||
516 gpArgs->fLocalCoordVar.getType() == SkSLType::kFloat2);
517 }
518
519 private:
521
523 UniformHandle fViewMatrixUniform;
524 UniformHandle fColorUniform;
525 STArray<8, UniformHandle> fSpecUniformHandles;
526
527 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
528 };
529
530 MeshGP(sk_sp<SkMeshSpecification> spec,
531 sk_sp<GrColorSpaceXform> colorSpaceXform,
532 const SkMatrix& viewMatrix,
533 const std::optional<SkPMColor4f>& color,
534 bool needsLocalCoords,
535 sk_sp<const SkData> uniforms,
536 SkSpan<std::unique_ptr<GrFragmentProcessor>> children)
537 : INHERITED(kVerticesGP_ClassID)
538 , fSpec(std::move(spec))
539 , fUniforms(std::move(uniforms))
540 , fChildren(children)
541 , fViewMatrix(viewMatrix)
542 , fColorSpaceXform(std::move(colorSpaceXform))
543 , fNeedsLocalCoords(needsLocalCoords) {
544 fColor = color.value_or(SK_PMColor4fILLEGAL);
545 for (const auto& srcAttr : fSpec->attributes()) {
546 fAttributes.emplace_back(srcAttr.name.c_str(),
547 attrib_type(srcAttr.type),
549 srcAttr.offset);
550 }
551 this->setVertexAttributes(fAttributes.data(), fAttributes.size(), fSpec->stride());
552
553 // We are relying here on the fact that `visitTextureEffects` and `visitWithImpls` walk the
554 // FP tree in the same order.
555 for (const std::unique_ptr<GrFragmentProcessor>& fp : fChildren) {
556 if (fp) {
557 fp->visitTextureEffects([&](const GrTextureEffect& te) {
558 fTextureSamplers.push_back({te.samplerState(),
559 te.view().proxy()->backendFormat(),
560 te.view().swizzle()});
561 });
562 }
563 }
564 this->setTextureSamplerCnt(fTextureSamplers.size());
565 }
566
567 const TextureSampler& onTextureSampler(int index) const override {
568 return fTextureSamplers[index];
569 }
570
572 sk_sp<const SkData> fUniforms;
573 SkSpan<std::unique_ptr<GrFragmentProcessor>> fChildren; // backed by a TArray in MeshOp
574 TArray<TextureSampler> fTextureSamplers;
575 std::vector<Attribute> fAttributes;
577 SkPMColor4f fColor;
578 sk_sp<GrColorSpaceXform> fColorSpaceXform;
579 bool fNeedsLocalCoords;
580
582};
583
584class MeshOp final : public GrMeshDrawOp {
585private:
587 using ChildPtr = SkRuntimeEffect::ChildPtr;
588
589public:
591
592 MeshOp(GrProcessorSet*,
593 const SkPMColor4f&,
594 const SkMesh&,
595 TArray<std::unique_ptr<GrFragmentProcessor>> children,
596 GrAAType,
598 const SkMatrix&);
599
600 MeshOp(GrProcessorSet*,
601 const SkPMColor4f&,
603 const GrPrimitiveType*,
604 GrAAType,
606 const SkMatrix&);
607
608 const char* name() const override { return "MeshOp"; }
609
610 void visitProxies(const GrVisitProxyFunc& func) const override {
611 for (const std::unique_ptr<GrFragmentProcessor>& fp : fChildren) {
612 if (fp) {
613 fp->visitTextureEffects([&](const GrTextureEffect& te) {
614 func(te.view().proxy(), te.view().mipmapped());
615 });
616 }
617 }
618 if (fProgramInfo) {
619 fProgramInfo->visitFPProxies(func);
620 } else {
621 fHelper.visitProxies(func);
622 }
623 }
624
625 FixedFunctionFlags fixedFunctionFlags() const override;
626
628
629private:
630 GrProgramInfo* programInfo() override { return fProgramInfo; }
631
632 void onCreateProgramInfo(const GrCaps*,
634 const GrSurfaceProxyView& writeView,
635 bool usesMSAASurface,
637 const GrDstProxyView&,
638 GrXferBarrierFlags renderPassXferBarriers,
639 GrLoadOp colorLoadOp) override;
640
641 void onPrepareDraws(GrMeshDrawTarget*) override;
642 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
643#if defined(GR_TEST_UTILS)
644 SkString onDumpInfo() const override;
645#endif
646
648
649 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps&) override;
650
651 /**
652 * Built either from a SkMesh or a SkVertices. In the former case the data is owned
653 * by Mesh and in the latter it is not. Meshes made from SkVertices can contain a SkMatrix
654 * to enable CPU-based transformation but Meshes made from SkMesh cannot.
655 */
656 class Mesh {
657 public:
658 Mesh() = delete;
659 explicit Mesh(const SkMesh& mesh);
660 Mesh(sk_sp<SkVertices>, const SkMatrix& viewMatrix);
661 Mesh(const Mesh&) = delete;
662 Mesh(Mesh&& m);
663
664 Mesh& operator=(const Mesh&) = delete;
665 Mesh& operator=(Mesh&&) = delete; // not used by SkSTArray but could be implemented.
666
667 ~Mesh();
668
669 bool isFromVertices() const { return SkToBool(fVertices); }
670
671 const SkVertices* vertices() const {
672 SkASSERT(this->isFromVertices());
673 return fVertices.get();
674 }
675
676 std::tuple<sk_sp<const GrGpuBuffer>, size_t> gpuVB() const {
677 if (this->isFromVertices()) {
678 return {};
679 }
680 SkASSERT(fMeshData.vb);
681 if (!fMeshData.vb->isGaneshBacked()) {
682 // This is a signal to upload the vertices which weren't already uploaded
683 // to the GPU (e.g. SkPicture containing a mesh).
684 return {nullptr, 0};
685 }
686 if (auto buf = static_cast<const SkMeshPriv::GaneshVertexBuffer*>(fMeshData.vb.get())) {
687 return {buf->asGpuBuffer(), fMeshData.voffset};
688 }
689 return {};
690 }
691
692 std::tuple<sk_sp<const GrGpuBuffer>, size_t> gpuIB() const {
693 if (this->isFromVertices() || !fMeshData.ib) {
694 return {};
695 }
696 if (!fMeshData.ib->isGaneshBacked()) {
697 // This is a signal to upload the indices which weren't already uploaded
698 // to the GPU (e.g. SkPicture containing a mesh).
699 return {nullptr, 0};
700 }
701 if (auto buf = static_cast<const SkMeshPriv::GaneshIndexBuffer*>(fMeshData.ib.get())) {
702 return {buf->asGpuBuffer(), fMeshData.ioffset};
703 }
704 return {};
705 }
706
707 void writeVertices(skgpu::VertexWriter& writer,
708 const SkMeshSpecification& spec,
709 bool transform) const;
710
711 int vertexCount() const {
712 return this->isFromVertices() ? fVertices->priv().vertexCount() : fMeshData.vcount;
713 }
714
715 const uint16_t* indices() const {
716 if (this->isFromVertices()) {
717 return fVertices->priv().indices();
718 }
719 if (!fMeshData.ib) {
720 return nullptr;
721 }
722 auto data = fMeshData.ib->peek();
723 if (!data) {
724 return nullptr;
725 }
726 return SkTAddOffset<const uint16_t>(data, fMeshData.ioffset);
727 }
728
729 int indexCount() const {
730 return this->isFromVertices() ? fVertices->priv().indexCount() : fMeshData.icount;
731 }
732
733 using sk_is_trivially_relocatable = std::true_type;
734
735 private:
736 struct MeshData {
739
740 size_t vcount = 0;
741 size_t icount = 0;
742
743 size_t voffset = 0;
744 size_t ioffset = 0;
745
746 static_assert(::sk_is_trivially_relocatable<decltype(vb)>::value);
747 static_assert(::sk_is_trivially_relocatable<decltype(ib)>::value);
748
749 using sk_is_trivially_relocatable = std::true_type;
750 };
751
752 sk_sp<SkVertices> fVertices;
753
754 union {
756 MeshData fMeshData;
757 };
758
759 static_assert(::sk_is_trivially_relocatable<decltype(fVertices)>::value);
760 static_assert(::sk_is_trivially_relocatable<decltype(fViewMatrix)>::value);
761 };
762
763 Helper fHelper;
764 sk_sp<SkMeshSpecification> fSpecification;
765 bool fIgnoreSpecColor = false;
766 GrPrimitiveType fPrimitiveType;
768 sk_sp<GrColorSpaceXform> fColorSpaceXform;
769 SkPMColor4f fColor; // Used if no color from spec or analysis overrides.
771 sk_sp<const SkData> fUniforms;
772 int fVertexCount;
773 int fIndexCount;
774 GrSimpleMesh* fMesh = nullptr;
775 GrProgramInfo* fProgramInfo = nullptr;
777
778 using INHERITED = GrMeshDrawOp;
779};
780
781MeshOp::Mesh::Mesh(const SkMesh& mesh) {
782 new (&fMeshData) MeshData();
784 fMeshData.vb = sk_ref_sp(static_cast<SkMeshPriv::VB*>(mesh.vertexBuffer()));
785 if (mesh.indexBuffer()) {
786 fMeshData.ib = sk_ref_sp(static_cast<SkMeshPriv::IB*>(mesh.indexBuffer()));
787 }
788 fMeshData.vcount = mesh.vertexCount();
789 fMeshData.voffset = mesh.vertexOffset();
790 fMeshData.icount = mesh.indexCount();
791 fMeshData.ioffset = mesh.indexOffset();
792
793 // The caller could modify CPU buffers after the draw so we must copy the data.
794 if (fMeshData.vb->peek()) {
795 auto data = SkTAddOffset<const void>(fMeshData.vb->peek(), fMeshData.voffset);
796 size_t size = fMeshData.vcount * mesh.spec()->stride();
798 fMeshData.voffset = 0;
799 }
800
801 if (fMeshData.ib && fMeshData.ib->peek()) {
802 auto data = SkTAddOffset<const void>(fMeshData.ib->peek(), fMeshData.ioffset);
803 size_t size = fMeshData.icount * sizeof(uint16_t);
805 fMeshData.ioffset = 0;
806 }
807}
808
809MeshOp::Mesh::Mesh(sk_sp<SkVertices> vertices, const SkMatrix& viewMatrix)
810 : fVertices(std::move(vertices)), fViewMatrix(viewMatrix) {
811 SkASSERT(fVertices);
812}
813
814MeshOp::Mesh::Mesh(Mesh&& that) {
815 fVertices = std::move(that.fVertices);
816 if (fVertices) {
817 fViewMatrix = that.fViewMatrix;
818 // 'that' is now not-a-vertices. Make sure it can be safely destroyed.
819 new (&that.fMeshData) MeshData();
820 } else {
821 fMeshData = std::move(that.fMeshData);
822 }
823}
824
825MeshOp::Mesh::~Mesh() {
826 if (!this->isFromVertices()) {
827 fMeshData.~MeshData();
828 }
829}
830
831void MeshOp::Mesh::writeVertices(skgpu::VertexWriter& writer,
832 const SkMeshSpecification& spec,
833 bool transform) const {
834 SkASSERT(!transform || this->isFromVertices());
835 if (this->isFromVertices()) {
836 int vertexCount = fVertices->priv().vertexCount();
837 for (int i = 0; i < vertexCount; ++i) {
838 SkPoint pos = fVertices->priv().positions()[i];
839 if (transform) {
842 }
843 writer << pos;
845 SkASSERT(fVertices->priv().hasColors());
846 writer << fVertices->priv().colors()[i];
847 }
848 if (fVertices->priv().hasTexCoords()) {
849 writer << fVertices->priv().texCoords()[i];
850 }
851 }
852 } else {
853 const void* data = fMeshData.vb->peek();
854 if (data) {
855 auto vdata = SkTAddOffset<const char>(data, fMeshData.voffset);
856 writer << skgpu::VertexWriter::Array(vdata, spec.stride()*fMeshData.vcount);
857 }
858 }
859}
860
861MeshOp::MeshOp(GrProcessorSet* processorSet,
862 const SkPMColor4f& color,
863 const SkMesh& mesh,
864 TArray<std::unique_ptr<GrFragmentProcessor>> children,
865 GrAAType aaType,
866 sk_sp<GrColorSpaceXform> colorSpaceXform,
867 const SkMatrix& viewMatrix)
868 : INHERITED(ClassID())
869 , fHelper(processorSet, aaType)
870 , fPrimitiveType(primitive_type(mesh.mode()))
871 , fColorSpaceXform(std::move(colorSpaceXform))
872 , fColor(color)
873 , fViewMatrix(viewMatrix) {
874 fMeshes.emplace_back(mesh);
875
876 fSpecification = mesh.refSpec();
879
880 fChildren = std::move(children);
881
882 fVertexCount = fMeshes.back().vertexCount();
883 fIndexCount = fMeshes.back().indexCount();
884
885 this->setTransformedBounds(mesh.bounds(), fViewMatrix, HasAABloat::kNo, IsHairline::kNo);
886}
887
888static SkMeshSpecification* make_vertices_spec(bool hasColors, bool hasTex) {
891 std::vector<Attribute> attributes;
892 attributes.reserve(3);
893 attributes.push_back({Attribute::Type::kFloat2, 0, SkString{"pos"}});
894 size_t size = 8;
895
896 std::vector<Varying> varyings;
897 attributes.reserve(2);
898
899 SkString vs("Varyings main(const Attributes a) {\nVaryings v;");
900 SkString fs("float2 ");
901
902 if (hasColors) {
903 attributes.push_back({Attribute::Type::kUByte4_unorm, size, SkString{"color"}});
904 varyings.push_back({Varying::Type::kHalf4, SkString{"color"}});
905 vs += "v.color = a.color;\n";
906 // Using float4 for the output color to work around skbug.com/12761
907 fs += "main(const Varyings v, out float4 color) {\n"
908 "color = float4(v.color.bgr*v.color.a, v.color.a);\n";
909 size += 4;
910 } else {
911 fs += "main(const Varyings v) {\n";
912 }
913
914 if (hasTex) {
915 attributes.push_back({Attribute::Type::kFloat2, size, SkString{"tex"}});
916 varyings.push_back({Varying::Type::kFloat2, SkString{"tex"}});
917 vs += "v.tex = a.tex;\n";
918 fs += "return v.tex;\n";
919 size += 8;
920 } else {
921 fs += "return v.position;\n";
922 }
923 vs += "v.position = a.pos;\nreturn v;\n}";
924 fs += "}";
925 auto [spec, error] = SkMeshSpecification::Make(SkSpan(attributes),
926 size,
927 SkSpan(varyings),
928 vs,
929 fs);
930 SkASSERT(spec);
931 return spec.release();
932}
933
934MeshOp::MeshOp(GrProcessorSet* processorSet,
935 const SkPMColor4f& color,
936 sk_sp<SkVertices> vertices,
937 const GrPrimitiveType* overridePrimitiveType,
938 GrAAType aaType,
939 sk_sp<GrColorSpaceXform> colorSpaceXform,
940 const SkMatrix& viewMatrix)
941 : INHERITED(ClassID())
942 , fHelper(processorSet, aaType)
943 , fColorSpaceXform(std::move(colorSpaceXform))
944 , fColor(color)
945 , fViewMatrix(viewMatrix) {
946 int attrs = (vertices->priv().hasColors() ? 0b01 : 0b00) |
947 (vertices->priv().hasTexCoords() ? 0b10 : 0b00);
948 switch (attrs) {
949 case 0b00: {
950 static const SkMeshSpecification* kSpec = make_vertices_spec(false, false);
951 fSpecification = sk_ref_sp(kSpec);
952 break;
953 }
954 case 0b01: {
955 static const SkMeshSpecification* kSpec = make_vertices_spec(true, false);
956 fSpecification = sk_ref_sp(kSpec);
957 break;
958 }
959 case 0b10: {
960 static const SkMeshSpecification* kSpec = make_vertices_spec(false, true);
961 fSpecification = sk_ref_sp(kSpec);
962 break;
963 }
964 case 0b11: {
965 static const SkMeshSpecification* kSpec = make_vertices_spec(true, true);
966 fSpecification = sk_ref_sp(kSpec);
967 break;
968 }
969 }
970 SkASSERT(fSpecification);
971
972 if (overridePrimitiveType) {
973 fPrimitiveType = *overridePrimitiveType;
974 } else {
975 switch (vertices->priv().mode()) {
977 fPrimitiveType = GrPrimitiveType::kTriangles;
978 break;
980 fPrimitiveType = GrPrimitiveType::kTriangleStrip;
981 break;
984 }
985 }
986
987 IsHairline isHairline = IsHairline::kNo;
988 if (GrIsPrimTypeLines(fPrimitiveType) || fPrimitiveType == GrPrimitiveType::kPoints) {
989 isHairline = IsHairline::kYes;
990 }
991 this->setTransformedBounds(vertices->bounds(), fViewMatrix, HasAABloat::kNo, isHairline);
992
993 fMeshes.emplace_back(std::move(vertices), fViewMatrix);
994
995 fVertexCount = fMeshes.back().vertexCount();
996 fIndexCount = fMeshes.back().indexCount();
997}
998
999#if defined(GR_TEST_UTILS)
1000SkString MeshOp::onDumpInfo() const { return {}; }
1001#endif
1002
1003GrDrawOp::FixedFunctionFlags MeshOp::fixedFunctionFlags() const {
1004 return fHelper.fixedFunctionFlags();
1005}
1006
1007GrProcessorSet::Analysis MeshOp::finalize(const GrCaps& caps,
1008 const GrAppliedClip* clip,
1009 GrClampType clampType) {
1011 gpColor.setToUnknown();
1012 auto result = fHelper.finalizeProcessors(caps,
1013 clip,
1014 clampType,
1016 &gpColor);
1017 if (gpColor.isConstant(&fColor)) {
1018 fIgnoreSpecColor = true;
1019 }
1020 return result;
1021}
1022
1023GrGeometryProcessor* MeshOp::makeGP(SkArenaAlloc* arena) {
1024 std::optional<SkPMColor4f> color;
1025 if (fIgnoreSpecColor || !SkMeshSpecificationPriv::HasColors(*fSpecification)) {
1026 color.emplace(fColor);
1027 }
1028 // Check if we're pre-transforming the vertices on the CPU.
1030 return MeshGP::Make(arena,
1031 fSpecification,
1032 fColorSpaceXform,
1033 vm,
1034 color,
1035 fHelper.usesLocalCoords(),
1036 fUniforms,
1037 SkSpan(fChildren));
1038}
1039
1040void MeshOp::onCreateProgramInfo(const GrCaps* caps,
1041 SkArenaAlloc* arena,
1042 const GrSurfaceProxyView& writeView,
1043 bool usesMSAASurface,
1044 GrAppliedClip&& appliedClip,
1045 const GrDstProxyView& dstProxyView,
1046 GrXferBarrierFlags renderPassXferBarriers,
1047 GrLoadOp colorLoadOp) {
1048 fProgramInfo = fHelper.createProgramInfo(caps,
1049 arena,
1050 writeView,
1051 usesMSAASurface,
1052 std::move(appliedClip),
1053 dstProxyView,
1054 this->makeGP(arena),
1055 fPrimitiveType,
1056 renderPassXferBarriers,
1057 colorLoadOp);
1058}
1059
1060void MeshOp::onPrepareDraws(GrMeshDrawTarget* target) {
1061 size_t vertexStride = fSpecification->stride();
1062 sk_sp<const GrBuffer> vertexBuffer;
1063 int firstVertex;
1064 std::tie(vertexBuffer, firstVertex) = fMeshes[0].gpuVB();
1065
1066 if (!vertexBuffer) {
1067 skgpu::VertexWriter verts = target->makeVertexWriter(vertexStride,
1068 fVertexCount,
1069 &vertexBuffer,
1070 &firstVertex);
1071 if (!verts) {
1072 SkDebugf("Could not allocate vertices.\n");
1073 return;
1074 }
1075
1077 for (const auto& m : fMeshes) {
1078 m.writeVertices(verts, *fSpecification, transform);
1079 }
1080 } else {
1081 SkASSERT(fMeshes.size() == 1);
1082 SkASSERT(firstVertex % fSpecification->stride() == 0);
1083 firstVertex /= fSpecification->stride();
1084 }
1085
1086 sk_sp<const GrBuffer> indexBuffer;
1087 int firstIndex = 0;
1088
1089 std::tie(indexBuffer, firstIndex) = fMeshes[0].gpuIB();
1090 if (fIndexCount && !indexBuffer) {
1091 uint16_t* indices = nullptr;
1092 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
1093 if (!indices) {
1094 SkDebugf("Could not allocate indices.\n");
1095 return;
1096 }
1097 // We can just copy the first mesh's indices. Subsequent meshes need their indices adjusted.
1098 std::copy_n(fMeshes[0].indices(), fMeshes[0].indexCount(), indices);
1099 int voffset = fMeshes[0].vertexCount();
1100 int ioffset = fMeshes[0].indexCount();
1101 for (int m = 1; m < fMeshes.size(); ++m) {
1102 for (int i = 0; i < fMeshes[m].indexCount(); ++i) {
1103 indices[ioffset++] = fMeshes[m].indices()[i] + voffset;
1104 }
1105 voffset += fMeshes[m].vertexCount();
1106 }
1107 SkASSERT(voffset == fVertexCount);
1108 SkASSERT(ioffset == fIndexCount);
1109 } else if (indexBuffer) {
1110 SkASSERT(fMeshes.size() == 1);
1111 SkASSERT(firstIndex % sizeof(uint16_t) == 0);
1112 firstIndex /= sizeof(uint16_t);
1113 }
1114
1115 SkASSERT(!fMesh);
1116 fMesh = target->allocMesh();
1117
1118 if (indexBuffer) {
1119 fMesh->setIndexed(std::move(indexBuffer),
1120 fIndexCount,
1121 firstIndex,
1122 /*minIndexValue=*/0,
1123 fVertexCount - 1,
1125 std::move(vertexBuffer),
1126 firstVertex);
1127 } else {
1128 fMesh->set(std::move(vertexBuffer), fVertexCount, firstVertex);
1129 }
1130}
1131
1132void MeshOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
1133 if (!fProgramInfo) {
1134 this->createProgramInfo(flushState);
1135 }
1136
1137 if (!fProgramInfo || !fMesh) {
1138 return;
1139 }
1140
1141 TArray<GrSurfaceProxy*> geomProcTextures;
1142 for (const std::unique_ptr<GrFragmentProcessor>& fp : fChildren) {
1143 if (fp) {
1144 fp->visitTextureEffects([&](const GrTextureEffect& te) {
1145 geomProcTextures.push_back(te.view().proxy());
1146 });
1147 }
1148 }
1149
1150 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
1151 flushState->bindTextures(fProgramInfo->geomProc(),
1152 geomProcTextures.data(),
1153 fProgramInfo->pipeline());
1154 flushState->drawMesh(*fMesh);
1155}
1156
1157GrOp::CombineResult MeshOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) {
1158 auto that = t->cast<MeshOp>();
1159 if (!fMeshes[0].isFromVertices() || !that->fMeshes[0].isFromVertices()) {
1160 // We *could* make this work when the vertex/index buffers are CPU-backed but that isn't an
1161 // important use case.
1163 }
1164
1165 // Check for a combinable primitive type.
1166 if (!(fPrimitiveType == GrPrimitiveType::kTriangles ||
1167 fPrimitiveType == GrPrimitiveType::kLines ||
1168 fPrimitiveType == GrPrimitiveType::kPoints)) {
1169 return CombineResult::kCannotCombine;
1170 }
1171
1172 if (fPrimitiveType != that->fPrimitiveType) {
1173 return CombineResult::kCannotCombine;
1174 }
1175
1176 if (fVertexCount > INT32_MAX - that->fVertexCount) {
1177 return CombineResult::kCannotCombine;
1178 }
1179 if (SkToBool(fIndexCount) != SkToBool(that->fIndexCount)) {
1180 return CombineResult::kCannotCombine;
1181 }
1182 if (SkToBool(fIndexCount) && fVertexCount > SkToInt(UINT16_MAX) - that->fVertexCount) {
1183 return CombineResult::kCannotCombine;
1184 }
1185
1186 if (SkMeshSpecificationPriv::Hash(*this->fSpecification) !=
1187 SkMeshSpecificationPriv::Hash(*that->fSpecification)) {
1188 return CombineResult::kCannotCombine;
1189 }
1190
1191 // Our specs made for vertices don't have uniforms.
1192 SkASSERT(fSpecification->uniforms().empty());
1193
1194 if (!SkMeshSpecificationPriv::HasColors(*fSpecification) && fColor != that->fColor) {
1195 return CombineResult::kCannotCombine;
1196 }
1197
1198 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
1199 return CombineResult::kCannotCombine;
1200 }
1201
1202 if (fViewMatrix != that->fViewMatrix) {
1203 // If we use local coords and the local coords come from positions then we can't pre-
1204 // transform the positions on the CPU.
1205 if (fHelper.usesLocalCoords() && !fMeshes[0].vertices()->priv().hasTexCoords()) {
1206 return CombineResult::kCannotCombine;
1207 }
1208 // We only support two-component position attributes. This means we would not get
1209 // perspective-correct interpolation of attributes if we transform on the CPU.
1210 if ((this->fViewMatrix.isFinite() && this->fViewMatrix.hasPerspective()) ||
1211 (that->fViewMatrix.isFinite() && that->fViewMatrix.hasPerspective())) {
1212 return CombineResult::kCannotCombine;
1213 }
1214 // This is how we record that we must CPU-transform the vertices.
1216 }
1217
1218 // NOTE: The source color space is part of the spec, and the destination gamut is determined by
1219 // the render target context. A mis-match should be impossible.
1220 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
1221
1222 fMeshes.move_back_n(that->fMeshes.size(), that->fMeshes.begin());
1223 fVertexCount += that->fVertexCount;
1224 fIndexCount += that->fIndexCount;
1225 return CombineResult::kMerged;
1226}
1227
1228} // anonymous namespace
1229
1231
1233 GrPaint&& paint,
1234 const SkMesh& mesh,
1235 TArray<std::unique_ptr<GrFragmentProcessor>> children,
1236 const SkMatrix& viewMatrix,
1237 GrAAType aaType,
1238 sk_sp<GrColorSpaceXform> colorSpaceXform) {
1239 return GrSimpleMeshDrawOpHelper::FactoryHelper<MeshOp>(context,
1240 std::move(paint),
1241 mesh,
1242 std::move(children),
1243 aaType,
1244 std::move(colorSpaceXform),
1245 viewMatrix);
1246}
1247
1249 GrPaint&& paint,
1250 sk_sp<SkVertices> vertices,
1251 const GrPrimitiveType* overridePrimitiveType,
1252 const SkMatrix& viewMatrix,
1253 GrAAType aaType,
1254 sk_sp<GrColorSpaceXform> colorSpaceXform) {
1255 return GrSimpleMeshDrawOpHelper::FactoryHelper<MeshOp>(context,
1256 std::move(paint),
1257 std::move(vertices),
1258 overridePrimitiveType,
1259 aaType,
1260 std::move(colorSpaceXform),
1261 viewMatrix);
1262}
1263
1264} // namespace skgpu::ganesh::DrawMeshOp
SkMatrix fViewMatrix
GrSimpleMesh * fMeshes
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define DEFINE_OP_CLASS_ID
Definition: GrOp.h:64
GrClampType
Definition: GrTypesPriv.h:228
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
Definition: GrTypesPriv.h:943
GrShaderFlags
Definition: GrTypesPriv.h:284
@ kVertex_GrShaderFlag
Definition: GrTypesPriv.h:286
@ kNone_GrShaderFlags
Definition: GrTypesPriv.h:285
@ kFragment_GrShaderFlag
Definition: GrTypesPriv.h:287
GrPrimitiveType
Definition: GrTypesPriv.h:43
@ kFragment_GrShaderType
Definition: GrTypesPriv.h:278
@ kVertex_GrShaderType
Definition: GrTypesPriv.h:277
GrAAType
Definition: GrTypesPriv.h:200
static constexpr bool GrIsPrimTypeLines(GrPrimitiveType type)
Definition: GrTypesPriv.h:52
GrLoadOp
Definition: GrTypesPriv.h:155
GrVertexAttribType
Definition: GrTypesPriv.h:312
@ kFloat2_GrVertexAttribType
Definition: GrTypesPriv.h:314
@ kUByte4_norm_GrVertexAttribType
Definition: GrTypesPriv.h:334
@ kFloat3_GrVertexAttribType
Definition: GrTypesPriv.h:315
@ kFloat_GrVertexAttribType
Definition: GrTypesPriv.h:313
@ kFloat4_GrVertexAttribType
Definition: GrTypesPriv.h:316
GrXferBarrierFlags
SkPoint pos
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkPMColor4f SK_PMColor4fILLEGAL
Definition: SkColorData.h:381
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
SkMeshSpecification::Attribute Attribute
Definition: SkMesh.cpp:54
SkMeshSpecification::Varying Varying
Definition: SkMesh.cpp:55
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
const Context & fContext
SkSLType
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr int SkToInt(S x)
Definition: SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
GLenum type
Definition: GrCaps.h:57
static bool Equals(const GrColorSpaceXform *a, const GrColorSpaceXform *b)
static uint32_t XformKey(const GrColorSpaceXform *xform)
virtual FixedFunctionFlags fixedFunctionFlags() const
Definition: GrDrawOp.h:112
virtual GrProcessorSet::Analysis finalize(const GrCaps &, const GrAppliedClip *, GrClampType)=0
friend class GrSimpleMeshDrawOpHelper
Definition: GrDrawOp.h:118
FixedFunctionFlags
Definition: GrDrawOp.h:104
void setData(const GrGLSLProgramDataManager &pdman, const GrFragmentProcessor &processor)
void setRuntimeEffectUniforms(SkSpan< const SkRuntimeEffect::Uniform >, SkSpan< const UniformHandle >, SkSpan< const Specialized >, const void *src) const
virtual void set4fv(UniformHandle, int arrayCount, const float v[]) const =0
void appendColorGamutXform(SkString *out, const char *srcColor, GrGLSLColorSpaceXformHelper *colorXformHelper)
SkString getMangledFunctionName(const char *baseName)
void codeAppendf(const char format[],...) SK_PRINTF_LIKE(2
UniformHandle addUniform(const GrProcessor *owner, uint32_t visibility, SkSLType type, const char *name, const char **outName=nullptr)
void emitAttributes(const GrGeometryProcessor &)
void addVarying(const char *name, GrGLSLVarying *varying, Interpolation=Interpolation::kInterpolated)
virtual std::unique_ptr< ProgramImpl > makeProgramImpl(const GrShaderCaps &) const =0
virtual void addToKey(const GrShaderCaps &, skgpu::KeyBuilder *) const =0
virtual GrProgramInfo * programInfo()=0
GrMeshDrawOp(uint32_t classID)
virtual void onCreateProgramInfo(const GrCaps *, SkArenaAlloc *, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrAppliedClip &&, const GrDstProxyView &, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp)=0
virtual void onPrepareDraws(GrMeshDrawTarget *)=0
void drawMesh(const GrSimpleMesh &mesh)
void bindPipelineAndScissorClip(const GrProgramInfo &programInfo, const SkRect &drawBounds)
void bindTextures(const GrGeometryProcessor &geomProc, const GrSurfaceProxy &singleGeomProcTexture, const GrPipeline &pipeline)
Definition: GrOp.h:70
CombineResult
Definition: GrOp.h:99
virtual void onExecute(GrOpFlushState *, const SkRect &chainBounds)=0
std::unique_ptr< GrOp > Owner
Definition: GrOp.h:72
virtual const char * name() const =0
const T & cast() const
Definition: GrOp.h:148
virtual void visitProxies(const GrVisitProxyFunc &) const
Definition: GrOp.h:95
virtual CombineResult onCombineIfPossible(GrOp *, SkArenaAlloc *, const GrCaps &)
Definition: GrOp.h:305
bool isConstant(SkPMColor4f *color=nullptr) const
const T & cast() const
Definition: GrProcessor.h:127
virtual const char * name() const =0
const GrPipeline & pipeline() const
Definition: GrProgramInfo.h:39
const GrGeometryProcessor & geomProc() const
Definition: GrProgramInfo.h:40
void visitFPProxies(const GrVisitProxyFunc &func) const
Definition: GrProgramInfo.h:64
const SkString & getName() const
Definition: GrShaderVar.h:91
void visitProxies(const GrVisitProxyFunc &func) const
skgpu::Swizzle swizzle() const
skgpu::Mipmapped mipmapped() const
GrSurfaceProxy * proxy() const
const GrBackendFormat & backendFormat() const
const GrSurfaceProxyView & view() const
GrSamplerState samplerState() const
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition: SkMatrix.cpp:770
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
bool hasPerspective() const
Definition: SkMatrix.h:312
bool isFinite() const
Definition: SkMatrix.h:1834
static const SkMatrix & InvalidMatrix()
Definition: SkMatrix.cpp:1550
static sk_sp< Base > Make(const void *data, size_t size)
Definition: SkMeshPriv.h:123
SkSpan< const Uniform > uniforms() const
Definition: SkMesh.h:170
size_t stride() const
Definition: SkMesh.h:187
static Result Make(SkSpan< const Attribute > attributes, size_t vertexStride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
Definition: SkMesh.cpp:389
SkColorSpace * colorSpace() const
Definition: SkMesh.h:189
Definition: SkMesh.h:263
VertexBuffer * vertexBuffer() const
Definition: SkMesh.h:353
size_t vertexCount() const
Definition: SkMesh.h:356
size_t vertexOffset() const
Definition: SkMesh.h:355
IndexBuffer * indexBuffer() const
Definition: SkMesh.h:359
size_t indexCount() const
Definition: SkMesh.h:362
sk_sp< const SkData > refUniforms() const
Definition: SkMesh.h:364
SkRect bounds() const
Definition: SkMesh.h:369
size_t indexOffset() const
Definition: SkMesh.h:361
SkMeshSpecification * spec() const
Definition: SkMesh.h:348
Mode
Definition: SkMesh.h:308
sk_sp< SkMeshSpecification > refSpec() const
Definition: SkMesh.h:347
static sk_sp< const SkData > TransformUniforms(SkSpan< const SkRuntimeEffect::Uniform > uniforms, sk_sp< const SkData > originalData, const SkColorSpaceXformSteps &)
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
constexpr T * data() const
Definition: SkSpan_impl.h:94
constexpr T * begin() const
Definition: SkSpan_impl.h:90
constexpr T * end() const
Definition: SkSpan_impl.h:91
constexpr size_t size() const
Definition: SkSpan_impl.h:95
const char * c_str() const
Definition: SkString.h:133
bool hasColors() const
SkVertices::VertexMode mode() const
bool hasTexCoords() const
const SkRect & bounds() const
Definition: SkVertices.h:98
@ kTriangleStrip_VertexMode
Definition: SkVertices.h:32
@ kTriangleFan_VertexMode
Definition: SkVertices.h:33
@ kTriangles_VertexMode
Definition: SkVertices.h:31
SkVerticesPriv priv()
T * get() const
Definition: SkRefCnt.h:303
const Paint & paint
Definition: color_source.cc:38
DlColor color
static bool b
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
uint32_t * target
SkMesh mesh
Definition: SkRecords.h:345
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
SK_API sk_sp< SkShader > Color(SkColor)
const uint32_t fp
void Helper(uword arg)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, sk_sp< SkVertices > vertices, const GrPrimitiveType *overridePrimitiveType, const SkMatrix &viewMatrix, GrAAType aaType, sk_sp< GrColorSpaceXform > colorSpaceXform)
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, const SkMesh &mesh, TArray< std::unique_ptr< GrFragmentProcessor > > children, const SkMatrix &viewMatrix, GrAAType aaType, sk_sp< GrColorSpaceXform > colorSpaceXform)
Definition: ref_ptr.h:256
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
void setIndexed(sk_sp< const GrBuffer > indexBuffer, int indexCount, int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue, GrPrimitiveRestart, sk_sp< const GrBuffer > vertexBuffer, int baseVertex)
Definition: GrSimpleMesh.h:56
void set(sk_sp< const GrBuffer > vertexBuffer, int vertexCount, int baseVertex)
Definition: GrSimpleMesh.h:47
static int PassthroughLocalCoordsVaryingIndex(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:65
static bool HasColors(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:30
static SkSpan< const Varying > Varyings(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:20
static const SkSL::Program * FS(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:25
static bool VaryingIsDead(const SkMeshSpecification &spec, int v)
Definition: SkMeshPriv.h:75
static int Hash(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:27
static const SkSL::Program * VS(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:24
static ColorType GetColorType(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:29
static SkSLType VaryingTypeAsSLType(Varying::Type type)
Definition: SkMeshPriv.h:40
static SkSLType AttrTypeAsSLType(Attribute::Type type)
Definition: SkMeshPriv.h:54
std::shared_ptr< Context > fContext
Definition: SkSLProgram.h:154
static ArrayDesc< T > Array(const T *array, int count)
Definition: BufferWriter.h:167
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63