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