• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/gpu/ganesh/ops/DrawMeshOp.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkMesh.h"
12 #include "src/base/SkArenaAlloc.h"
13 #include "src/core/SkMeshPriv.h"
14 #include "src/core/SkRuntimeEffectPriv.h"
15 #include "src/core/SkVerticesPriv.h"
16 #include "src/gpu/BufferWriter.h"
17 #include "src/gpu/KeyBuilder.h"
18 #include "src/gpu/ganesh/GrGeometryProcessor.h"
19 #include "src/gpu/ganesh/GrMeshBuffers.h"
20 #include "src/gpu/ganesh/GrOpFlushState.h"
21 #include "src/gpu/ganesh/GrProgramInfo.h"
22 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
23 #include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
24 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
25 #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
26 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
27 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
28 #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
29 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
30 #include "src/sksl/ir/SkSLProgram.h"
31 #include "src/sksl/ir/SkSLVarDeclarations.h"
32 
33 using namespace skia_private;
34 
35 namespace {
36 
primitive_type(SkMesh::Mode mode)37 GrPrimitiveType primitive_type(SkMesh::Mode mode) {
38     switch (mode) {
39         case SkMesh::Mode::kTriangles:     return GrPrimitiveType::kTriangles;
40         case SkMesh::Mode::kTriangleStrip: return GrPrimitiveType::kTriangleStrip;
41     }
42     SkUNREACHABLE;
43 }
44 
45 using MeshAttributeType = SkMeshSpecification::Attribute::Type;
46 
attrib_type(MeshAttributeType type)47 GrVertexAttribType attrib_type(MeshAttributeType type) {
48     switch (type) {
49         case MeshAttributeType::kFloat:        return kFloat_GrVertexAttribType;
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     }
55     SkUNREACHABLE;
56 }
57 
58 class MeshGP : public GrGeometryProcessor {
59 private:
60     using ChildPtr = SkRuntimeEffect::ChildPtr;
61 
62 public:
Make(SkArenaAlloc * arena,sk_sp<SkMeshSpecification> spec,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const std::optional<SkPMColor4f> & color,bool needsLocalCoords,sk_sp<const SkData> uniforms,SkSpan<std::unique_ptr<GrFragmentProcessor>> children)63     static GrGeometryProcessor* Make(
64             SkArenaAlloc* arena,
65             sk_sp<SkMeshSpecification> spec,
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 
name() const83     const char* name() const override { return "MeshGP"; }
84 
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const85     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");
88         if (SkMeshSpecificationPriv::GetColorType(*fSpec) !=
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 
makeProgramImpl(const GrShaderCaps &) const101     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
102         return std::make_unique<Impl>();
103     }
104 
105 private:
106     class Impl : public ProgramImpl {
107     public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)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,
132                                            GrFragmentProcessor::ProgramImpl& impl) {
133                                            impl.setData(pdman, fp);
134                                        },
135                                        *impl);
136                 }
137             }
138         }
139 
140     private:
141         class MeshCallbacks : public SkSL::PipelineStage::Callbacks {
142         public:
MeshCallbacks(Impl * self,const MeshGP & gp,GrGLSLShaderBuilder * builder,GrGLSLUniformHandler * uniformHandler,const char * mainName,const SkSL::Context & context)143             MeshCallbacks(Impl* self,
144                           const MeshGP& gp,
145                           GrGLSLShaderBuilder* builder,
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 
declareUniform(const SkSL::VarDeclaration * decl)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;
173                 SkAssertResult(SkSL::type_to_sksltype(fContext, *type, &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(),
179                                        [&name](SkMeshSpecification::Uniform uniform) {
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;
192                 GrShaderFlags shaderFlags = kNone_GrShaderFlags;
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 
getMangledName(const char * name)211             std::string getMangledName(const char* name) override {
212                 return std::string(fBuilder->getMangledFunctionName(name).c_str());
213             }
214 
getMainName()215             std::string getMainName() override { return fMainName; }
216 
defineFunction(const char * decl,const char * body,bool isMain)217             void defineFunction(const char* decl, const char* body, bool isMain) override {
218                 fBuilder->emitFunction(decl, body);
219             }
220 
declareFunction(const char * decl)221             void declareFunction(const char* decl) override {
222                 fBuilder->emitFunctionPrototype(decl);
223             }
224 
defineStruct(const char * definition)225             void defineStruct(const char* definition) override {
226                 fBuilder->definitionAppend(definition);
227             }
228 
declareGlobal(const char * declaration)229             void declareGlobal(const char* declaration) override {
230                 fBuilder->definitionAppend(declaration);
231             }
232 
sampleShader(int index,std::string coords)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 
sampleColorFilter(int index,std::string color)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 
sampleBlender(int index,std::string src,std::string dst)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 
toLinearSrgb(std::string color)278             std::string toLinearSrgb(std::string color) override {
279                 SK_ABORT("Color transform intrinsics not allowed.");
280             }
281 
fromLinearSrgb(std::string Color)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 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)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 =
313                     SkMeshSpecificationPriv::GetColorType(*mgp.fSpec);
314             int passthroughLCVaryingIndex =
315                     SkMeshSpecificationPriv::PassthroughLocalCoordsVaryingIndex(*mgp.fSpec);
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 
329             SkSpan<const SkMeshSpecification::Varying> specVaryings =
330                     SkMeshSpecificationPriv::Varyings(*mgp.fSpec);
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);
346             SkSL::PipelineStage::ConvertProgram(*customVS,
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             };
384             STArray<SkMeshSpecification::kMaxVaryings, RealVarying> realVaryings;
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                     }
391                     RealVarying rv {i, SkMeshSpecificationPriv::VaryingTypeAsSLType(v.type)};
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,
426                                            GrFragmentProcessor::ProgramImpl& impl) {
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);
452             SkSL::PipelineStage::ConvertProgram(*customFS,
453                                                 /*sampleCoords=*/"",
454                                                 /*inputColor=*/"",
455                                                 /*destColor=*/"",
456                                                 &fsCallbacks);
457             const char* uniformColorName = nullptr;
458             if (mgp.fColor != SK_PMColor4fILLEGAL) {
459                 fColorUniform = uniformHandler->addUniform(nullptr,
460                                                            kFragment_GrShaderFlag,
461                                                            SkSLType::kHalf4,
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.
482                 SkString local;
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(),
495                                                kFragment_GrShaderFlag);
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:
520         SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
521 
522         STArray<2, std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fChildImpls;
523         UniformHandle                                                 fViewMatrixUniform;
524         UniformHandle                                                 fColorUniform;
525         STArray<8, UniformHandle>                                     fSpecUniformHandles;
526 
527         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
528     };
529 
MeshGP(sk_sp<SkMeshSpecification> spec,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const std::optional<SkPMColor4f> & color,bool needsLocalCoords,sk_sp<const SkData> uniforms,SkSpan<std::unique_ptr<GrFragmentProcessor>> children)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),
548                                      SkMeshSpecificationPriv::AttrTypeAsSLType(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 
onTextureSampler(int index) const567     const TextureSampler& onTextureSampler(int index) const override {
568         return fTextureSamplers[index];
569     }
570 
571     sk_sp<SkMeshSpecification> fSpec;
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;
576     SkMatrix fViewMatrix;
577     SkPMColor4f fColor;
578     sk_sp<GrColorSpaceXform> fColorSpaceXform;
579     bool fNeedsLocalCoords;
580 
581     using INHERITED = GrGeometryProcessor;
582 };
583 
584 class MeshOp final : public GrMeshDrawOp {
585 private:
586     using Helper = GrSimpleMeshDrawOpHelper;
587     using ChildPtr = SkRuntimeEffect::ChildPtr;
588 
589 public:
590     DEFINE_OP_CLASS_ID
591 
592     MeshOp(GrProcessorSet*,
593            const SkPMColor4f&,
594            const SkMesh&,
595            TArray<std::unique_ptr<GrFragmentProcessor>> children,
596            GrAAType,
597            sk_sp<GrColorSpaceXform>,
598            const SkMatrix&);
599 
600     MeshOp(GrProcessorSet*,
601            const SkPMColor4f&,
602            sk_sp<SkVertices>,
603            const GrPrimitiveType*,
604            GrAAType,
605            sk_sp<GrColorSpaceXform>,
606            const SkMatrix&);
607 
name() const608     const char* name() const override { return "MeshOp"; }
609 
visitProxies(const GrVisitProxyFunc & func) const610     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 
627     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
628 
629 private:
programInfo()630     GrProgramInfo* programInfo() override { return fProgramInfo; }
631 
632     void onCreateProgramInfo(const GrCaps*,
633                              SkArenaAlloc*,
634                              const GrSurfaceProxyView& writeView,
635                              bool usesMSAASurface,
636                              GrAppliedClip&&,
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 
647     GrGeometryProcessor* makeGP(SkArenaAlloc*);
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 
isFromVertices() const669         bool isFromVertices() const { return SkToBool(fVertices); }
670 
vertices() const671         const SkVertices* vertices() const {
672             SkASSERT(this->isFromVertices());
673             return fVertices.get();
674         }
675 
gpuVB() const676         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 
gpuIB() const692         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 
vertexCount() const711         int vertexCount() const {
712             return this->isFromVertices() ? fVertices->priv().vertexCount() : fMeshData.vcount;
713         }
714 
indices() const715         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 
indexCount() const729         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 {
737             sk_sp<const SkMeshPriv::VB> vb;
738             sk_sp<const SkMeshPriv::IB> ib;
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 {
755             SkMatrix fViewMatrix;
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;
767     STArray<1, Mesh>           fMeshes;
768     sk_sp<GrColorSpaceXform>   fColorSpaceXform;
769     SkPMColor4f                fColor; // Used if no color from spec or analysis overrides.
770     SkMatrix                   fViewMatrix;
771     sk_sp<const SkData>        fUniforms;
772     int                        fVertexCount;
773     int                        fIndexCount;
774     GrSimpleMesh*              fMesh = nullptr;
775     GrProgramInfo*             fProgramInfo = nullptr;
776     TArray<std::unique_ptr<GrFragmentProcessor>> fChildren;
777 
778     using INHERITED = GrMeshDrawOp;
779 };
780 
Mesh(const SkMesh & mesh)781 MeshOp::Mesh::Mesh(const SkMesh& mesh) {
782     new (&fMeshData) MeshData();
783     SkASSERT(mesh.vertexBuffer());
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();
797         fMeshData.vb = SkMeshPriv::CpuVertexBuffer::Make(data, size);
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);
804         fMeshData.ib = SkMeshPriv::CpuIndexBuffer::Make(data, size);
805         fMeshData.ioffset = 0;
806     }
807 }
808 
Mesh(sk_sp<SkVertices> vertices,const SkMatrix & viewMatrix)809 MeshOp::Mesh::Mesh(sk_sp<SkVertices> vertices, const SkMatrix& viewMatrix)
810         : fVertices(std::move(vertices)), fViewMatrix(viewMatrix) {
811     SkASSERT(fVertices);
812 }
813 
Mesh(Mesh && that)814 MeshOp::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 
~Mesh()825 MeshOp::Mesh::~Mesh() {
826     if (!this->isFromVertices()) {
827         fMeshData.~MeshData();
828     }
829 }
830 
writeVertices(skgpu::VertexWriter & writer,const SkMeshSpecification & spec,bool transform) const831 void 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) {
840                 SkASSERT(!fViewMatrix.hasPerspective());
841                 fViewMatrix.mapPoints(&pos, 1);
842             }
843             writer << pos;
844             if (SkMeshSpecificationPriv::HasColors(spec)) {
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 
MeshOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const SkMesh & mesh,TArray<std::unique_ptr<GrFragmentProcessor>> children,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix)861 MeshOp::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();
877     fUniforms = SkRuntimeEffectPriv::TransformUniforms(
878             mesh.spec()->uniforms(), mesh.refUniforms(), mesh.spec()->colorSpace());
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 
make_vertices_spec(bool hasColors,bool hasTex)888 static SkMeshSpecification* make_vertices_spec(bool hasColors, bool hasTex) {
889     using Attribute = SkMeshSpecification::Attribute;
890     using Varying   = SkMeshSpecification::Varying;
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 
MeshOp(GrProcessorSet * processorSet,const SkPMColor4f & color,sk_sp<SkVertices> vertices,const GrPrimitiveType * overridePrimitiveType,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix)934 MeshOp::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()) {
976             case SkVertices::kTriangles_VertexMode:
977                 fPrimitiveType = GrPrimitiveType::kTriangles;
978                 break;
979             case SkVertices::kTriangleStrip_VertexMode:
980                 fPrimitiveType = GrPrimitiveType::kTriangleStrip;
981                 break;
982             case SkVertices::kTriangleFan_VertexMode:
983                 SkUNREACHABLE;
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)
onDumpInfo() const1000 SkString MeshOp::onDumpInfo() const { return {}; }
1001 #endif
1002 
fixedFunctionFlags() const1003 GrDrawOp::FixedFunctionFlags MeshOp::fixedFunctionFlags() const {
1004     return fHelper.fixedFunctionFlags();
1005 }
1006 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)1007 GrProcessorSet::Analysis MeshOp::finalize(const GrCaps& caps,
1008                                           const GrAppliedClip* clip,
1009                                           GrClampType clampType) {
1010     GrProcessorAnalysisColor gpColor;
1011     gpColor.setToUnknown();
1012     auto result = fHelper.finalizeProcessors(caps,
1013                                              clip,
1014                                              clampType,
1015                                              GrProcessorAnalysisCoverage::kNone,
1016                                              &gpColor);
1017     if (gpColor.isConstant(&fColor)) {
1018         fIgnoreSpecColor = true;
1019     }
1020     return result;
1021 }
1022 
makeGP(SkArenaAlloc * arena)1023 GrGeometryProcessor* 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.
1029     const SkMatrix& vm = fViewMatrix == SkMatrix::InvalidMatrix() ? SkMatrix::I() : fViewMatrix;
1030     return MeshGP::Make(arena,
1031                         fSpecification,
1032                         fColorSpaceXform,
1033                         vm,
1034                         color,
1035                         fHelper.usesLocalCoords(),
1036                         fUniforms,
1037                         SkSpan(fChildren));
1038 }
1039 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)1040 void 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 
onPrepareDraws(GrMeshDrawTarget * target)1060 void 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 
1076         bool transform = fViewMatrix == SkMatrix::InvalidMatrix();
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,
1124                           GrPrimitiveRestart::kNo,
1125                           std::move(vertexBuffer),
1126                           firstVertex);
1127     } else {
1128         fMesh->set(std::move(vertexBuffer), fVertexCount, firstVertex);
1129     }
1130 }
1131 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)1132 void 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 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)1157 GrOp::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.
1162         return GrOp::CombineResult::kCannotCombine;
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.
1215         fViewMatrix = SkMatrix::InvalidMatrix();
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 
1230 namespace skgpu::ganesh::DrawMeshOp {
1231 
Make(GrRecordingContext * context,GrPaint && paint,const SkMesh & mesh,TArray<std::unique_ptr<GrFragmentProcessor>> children,const SkMatrix & viewMatrix,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform)1232 GrOp::Owner Make(GrRecordingContext* context,
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 
Make(GrRecordingContext * context,GrPaint && paint,sk_sp<SkVertices> vertices,const GrPrimitiveType * overridePrimitiveType,const SkMatrix & viewMatrix,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform)1248 GrOp::Owner Make(GrRecordingContext* context,
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
1265