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