• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/ops/DrawVerticesOp.h"
9 
10 #include "include/core/SkM44.h"
11 #include "src/core/SkArenaAlloc.h"
12 #include "src/core/SkDevice.h"
13 #include "src/core/SkMatrixPriv.h"
14 #include "src/core/SkVerticesPriv.h"
15 #include "src/gpu/BufferWriter.h"
16 #include "src/gpu/GrGeometryProcessor.h"
17 #include "src/gpu/GrOpFlushState.h"
18 #include "src/gpu/GrProgramInfo.h"
19 #include "src/gpu/SkGr.h"
20 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
21 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
22 #include "src/gpu/glsl/GrGLSLVarying.h"
23 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
24 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
25 
26 namespace skgpu::v1::DrawVerticesOp {
27 
28 namespace {
29 
30 enum class ColorArrayType {
31     kUnused,
32     kPremulGrColor,
33     kSkColor,
34 };
35 
36 enum class LocalCoordsType {
37     kUnused,
38     kUsePosition,
39     kExplicit,
40 };
41 
42 class VerticesGP : public GrGeometryProcessor {
43 public:
Make(SkArenaAlloc * arena,LocalCoordsType localCoordsType,ColorArrayType colorArrayType,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix)44     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
45                                      LocalCoordsType localCoordsType,
46                                      ColorArrayType colorArrayType,
47                                      const SkPMColor4f& color,
48                                      sk_sp<GrColorSpaceXform> colorSpaceXform,
49                                      const SkMatrix& viewMatrix) {
50         return arena->make([&](void* ptr) {
51             return new (ptr) VerticesGP(localCoordsType, colorArrayType, color,
52                                         std::move(colorSpaceXform), viewMatrix);
53         });
54     }
55 
name() const56     const char* name() const override { return "VerticesGP"; }
57 
positionAttr() const58     const Attribute& positionAttr() const { return fAttributes[kPositionIndex]; }
colorAttr() const59     const Attribute& colorAttr() const { return fAttributes[kColorIndex]; }
localCoordsAttr() const60     const Attribute& localCoordsAttr() const { return fAttributes[kLocalCoordsIndex]; }
61 
addToKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const62     void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
63         uint32_t key = 0;
64         key |= (fColorArrayType == ColorArrayType::kSkColor) ? 0x1 : 0;
65         key |= ProgramImpl::ComputeMatrixKey(caps, fViewMatrix) << 20;
66         b->add32(key);
67         b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
68     }
69 
makeProgramImpl(const GrShaderCaps &) const70     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
71         return std::make_unique<Impl>();
72     }
73 
74 private:
75     class Impl : public ProgramImpl {
76     public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)77         void setData(const GrGLSLProgramDataManager& pdman,
78                      const GrShaderCaps& shaderCaps,
79                      const GrGeometryProcessor& geomProc) override {
80             const VerticesGP& vgp = geomProc.cast<VerticesGP>();
81 
82             SetTransform(pdman, shaderCaps, fViewMatrixUniform, vgp.fViewMatrix, &fViewMatrix);
83 
84             if (!vgp.colorAttr().isInitialized() && vgp.fColor != fColor) {
85                 pdman.set4fv(fColorUniform, 1, vgp.fColor.vec());
86                 fColor = vgp.fColor;
87             }
88 
89             fColorSpaceHelper.setData(pdman, vgp.fColorSpaceXform.get());
90         }
91 
92     private:
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)93         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
94             const VerticesGP& gp = args.fGeomProc.cast<VerticesGP>();
95             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
96             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
97             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
98             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
99 
100             // emit attributes
101             varyingHandler->emitAttributes(gp);
102 
103             fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
104                                        kVertex_GrShaderFlag);
105 
106             // Setup pass through color
107             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
108             if (gp.colorAttr().isInitialized()) {
109                 GrGLSLVarying varying(kHalf4_GrSLType);
110                 varyingHandler->addVarying("color", &varying);
111                 vertBuilder->codeAppendf("half4 color = %s;", gp.colorAttr().name());
112 
113                 // For SkColor, do a red/blue swap, possible color space conversion, and premul
114                 if (gp.fColorArrayType == ColorArrayType::kSkColor) {
115                     vertBuilder->codeAppend("color = color.bgra;");
116 
117                     SkString xformedColor;
118                     vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper);
119                     vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
120 
121                     vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
122                 }
123 
124                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
125                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
126             } else {
127                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
128                                         &fColorUniform);
129             }
130 
131             // Setup position
132             WriteOutputPosition(vertBuilder,
133                                 uniformHandler,
134                                 *args.fShaderCaps,
135                                 gpArgs,
136                                 gp.positionAttr().name(),
137                                 gp.fViewMatrix,
138                                 &fViewMatrixUniform);
139 
140             // emit transforms using either explicit local coords or positions
141             const auto& coordsAttr = gp.localCoordsAttr().isInitialized() ? gp.localCoordsAttr()
142                                                                           : gp.positionAttr();
143             gpArgs->fLocalCoordVar = coordsAttr.asShaderVar();
144 
145             fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
146         }
147 
148     private:
149         SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
150         SkPMColor4f fColor   = SK_PMColor4fILLEGAL;
151 
152         UniformHandle fViewMatrixUniform;
153         UniformHandle fColorUniform;
154 
155         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
156     };
157 
VerticesGP(LocalCoordsType localCoordsType,ColorArrayType colorArrayType,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix)158     VerticesGP(LocalCoordsType localCoordsType,
159                ColorArrayType colorArrayType,
160                const SkPMColor4f& color,
161                sk_sp<GrColorSpaceXform> colorSpaceXform,
162                const SkMatrix& viewMatrix)
163             : INHERITED(kVerticesGP_ClassID)
164             , fColorArrayType(colorArrayType)
165             , fColor(color)
166             , fViewMatrix(viewMatrix)
167             , fColorSpaceXform(std::move(colorSpaceXform)) {
168         constexpr Attribute missingAttr;
169         fAttributes.push_back({"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType});
170         fAttributes.push_back(fColorArrayType != ColorArrayType::kUnused
171                                       ? MakeColorAttribute("inColor", false)
172                                       : missingAttr);
173         fAttributes.push_back(localCoordsType == LocalCoordsType::kExplicit
174                         ? Attribute{"inLocalCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType}
175                         : missingAttr);
176 
177         this->setVertexAttributes(fAttributes.data(), fAttributes.size());
178     }
179 
180     enum {
181         kPositionIndex    = 0,
182         kColorIndex       = 1,
183         kLocalCoordsIndex = 2,
184     };
185 
186     std::vector<Attribute> fAttributes;
187     ColorArrayType fColorArrayType;
188     SkPMColor4f fColor;
189     SkMatrix fViewMatrix;
190     sk_sp<GrColorSpaceXform> fColorSpaceXform;
191 
192     using INHERITED = GrGeometryProcessor;
193 };
194 
195 class DrawVerticesOpImpl final : public GrMeshDrawOp {
196 private:
197     using Helper = GrSimpleMeshDrawOpHelper;
198 
199 public:
200     DEFINE_OP_CLASS_ID
201 
202     DrawVerticesOpImpl(GrProcessorSet*,
203                        const SkPMColor4f&,
204                        sk_sp<SkVertices>,
205                        GrPrimitiveType,
206                        GrAAType,
207                        sk_sp<GrColorSpaceXform>,
208                        const SkMatrixProvider&);
209 
name() const210     const char* name() const override { return "DrawVerticesOp"; }
211 
visitProxies(const GrVisitProxyFunc & func) const212     void visitProxies(const GrVisitProxyFunc& func) const override {
213         if (fProgramInfo) {
214             fProgramInfo->visitFPProxies(func);
215         } else {
216             fHelper.visitProxies(func);
217         }
218     }
219 
220     FixedFunctionFlags fixedFunctionFlags() const override;
221 
222     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
223 
224 private:
programInfo()225     GrProgramInfo* programInfo() override { return fProgramInfo; }
226 
227     void onCreateProgramInfo(const GrCaps*,
228                              SkArenaAlloc*,
229                              const GrSurfaceProxyView& writeView,
230                              bool usesMSAASurface,
231                              GrAppliedClip&&,
232                              const GrDstProxyView&,
233                              GrXferBarrierFlags renderPassXferBarriers,
234                              GrLoadOp colorLoadOp) override;
235 
236     void onPrepareDraws(GrMeshDrawTarget*) override;
237     void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
238 #if GR_TEST_UTILS
239     SkString onDumpInfo() const override;
240 #endif
241 
242     GrGeometryProcessor* makeGP(SkArenaAlloc*);
243 
primitiveType() const244     GrPrimitiveType primitiveType() const { return fPrimitiveType; }
combinablePrimitive() const245     bool combinablePrimitive() const {
246         return GrPrimitiveType::kTriangles == fPrimitiveType ||
247                GrPrimitiveType::kLines == fPrimitiveType ||
248                GrPrimitiveType::kPoints == fPrimitiveType;
249     }
250 
251     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps&) override;
252 
253     struct Mesh {
254         SkPMColor4f fColor;  // Used if this->hasPerVertexColors() is false.
255         sk_sp<SkVertices> fVertices;
256         SkMatrix fViewMatrix;
257         bool fIgnoreColors;
258 
hasPerVertexColorsskgpu::v1::DrawVerticesOp::__anonc9a8554f0111::DrawVerticesOpImpl::Mesh259         bool hasPerVertexColors() const {
260             return fVertices->priv().hasColors() && !fIgnoreColors;
261         }
262     };
263 
isIndexed() const264     bool isIndexed() const {
265         // Consistency enforced in onCombineIfPossible.
266         return fMeshes[0].fVertices->priv().hasIndices();
267     }
268 
requiresPerVertexColors() const269     bool requiresPerVertexColors() const {
270         return fColorArrayType != ColorArrayType::kUnused;
271     }
272 
requiresPerVertexLocalCoords() const273     bool requiresPerVertexLocalCoords() const {
274         return fLocalCoordsType == LocalCoordsType::kExplicit;
275     }
276 
vertexStride() const277     size_t vertexStride() const {
278         return sizeof(SkPoint) +
279                (this->requiresPerVertexColors() ? sizeof(uint32_t) : 0) +
280                (this->requiresPerVertexLocalCoords() ? sizeof(SkPoint) : 0);
281     }
282 
283     Helper fHelper;
284     SkSTArray<1, Mesh, true> fMeshes;
285     // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore
286     // the SkVertices mode (though fPrimitiveType may have been inferred from it).
287     GrPrimitiveType fPrimitiveType;
288     int fVertexCount;
289     int fIndexCount;
290     bool fMultipleViewMatrices;
291     LocalCoordsType fLocalCoordsType;
292     ColorArrayType fColorArrayType;
293     sk_sp<GrColorSpaceXform> fColorSpaceXform;
294 
295     GrSimpleMesh*  fMesh = nullptr;
296     GrProgramInfo* fProgramInfo = nullptr;
297 
298     using INHERITED = GrMeshDrawOp;
299 };
300 
DrawVerticesOpImpl(GrProcessorSet * processorSet,const SkPMColor4f & color,sk_sp<SkVertices> vertices,GrPrimitiveType primitiveType,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrixProvider & matrixProvider)301 DrawVerticesOpImpl::DrawVerticesOpImpl(GrProcessorSet* processorSet,
302                                        const SkPMColor4f& color,
303                                        sk_sp<SkVertices> vertices,
304                                        GrPrimitiveType primitiveType,
305                                        GrAAType aaType,
306                                        sk_sp<GrColorSpaceXform> colorSpaceXform,
307                                        const SkMatrixProvider& matrixProvider)
308         : INHERITED(ClassID())
309         , fHelper(processorSet, aaType)
310         , fPrimitiveType(primitiveType)
311         , fMultipleViewMatrices(false)
312         , fColorSpaceXform(std::move(colorSpaceXform)) {
313     SkASSERT(vertices);
314 
315     SkVerticesPriv info(vertices->priv());
316 
317     fVertexCount = info.vertexCount();
318     fIndexCount = info.indexCount();
319     fColorArrayType = info.hasColors() ? ColorArrayType::kSkColor
320                                        : ColorArrayType::kUnused;
321     fLocalCoordsType = info.hasTexCoords() ? LocalCoordsType::kExplicit
322                                            : LocalCoordsType::kUsePosition;
323 
324     Mesh& mesh = fMeshes.push_back();
325     mesh.fColor = color;
326     mesh.fViewMatrix = matrixProvider.localToDevice();
327     mesh.fVertices = std::move(vertices);
328     mesh.fIgnoreColors = false;
329 
330     IsHairline zeroArea;
331     if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
332         zeroArea = IsHairline::kYes;
333     } else {
334         zeroArea = IsHairline::kNo;
335     }
336 
337     this->setTransformedBounds(mesh.fVertices->bounds(),
338                                 mesh.fViewMatrix,
339                                 HasAABloat::kNo,
340                                 zeroArea);
341 }
342 
343 #if GR_TEST_UTILS
onDumpInfo() const344 SkString DrawVerticesOpImpl::onDumpInfo() const {
345     return SkStringPrintf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n%s",
346                           (int)fPrimitiveType, fMeshes.count(), fVertexCount, fIndexCount,
347                           fHelper.dumpInfo().c_str());
348 }
349 #endif
350 
fixedFunctionFlags() const351 GrDrawOp::FixedFunctionFlags DrawVerticesOpImpl::fixedFunctionFlags() const {
352     return fHelper.fixedFunctionFlags();
353 }
354 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)355 GrProcessorSet::Analysis DrawVerticesOpImpl::finalize(const GrCaps& caps,
356                                                       const GrAppliedClip* clip,
357                                                       GrClampType clampType) {
358     GrProcessorAnalysisColor gpColor;
359     if (this->requiresPerVertexColors()) {
360         gpColor.setToUnknown();
361     } else {
362         gpColor.setToConstant(fMeshes.front().fColor);
363     }
364     auto result = fHelper.finalizeProcessors(caps, clip, clampType,
365                                              GrProcessorAnalysisCoverage::kNone, &gpColor);
366     if (gpColor.isConstant(&fMeshes.front().fColor)) {
367         fMeshes.front().fIgnoreColors = true;
368         fColorArrayType = ColorArrayType::kUnused;
369     }
370     if (!fHelper.usesLocalCoords()) {
371         fLocalCoordsType = LocalCoordsType::kUnused;
372     }
373     return result;
374 }
375 
makeGP(SkArenaAlloc * arena)376 GrGeometryProcessor* DrawVerticesOpImpl::makeGP(SkArenaAlloc* arena) {
377     const SkMatrix& vm = fMultipleViewMatrices ? SkMatrix::I() : fMeshes[0].fViewMatrix;
378 
379     sk_sp<GrColorSpaceXform> csxform =
380             (fColorArrayType == ColorArrayType::kSkColor) ? fColorSpaceXform : nullptr;
381 
382     auto gp = VerticesGP::Make(arena, fLocalCoordsType, fColorArrayType, fMeshes[0].fColor,
383                                std::move(csxform), vm);
384     SkASSERT(this->vertexStride() == gp->vertexStride());
385     return gp;
386 }
387 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)388 void DrawVerticesOpImpl::onCreateProgramInfo(const GrCaps* caps,
389                                              SkArenaAlloc* arena,
390                                              const GrSurfaceProxyView& writeView,
391                                              bool usesMSAASurface,
392                                              GrAppliedClip&& appliedClip,
393                                              const GrDstProxyView& dstProxyView,
394                                              GrXferBarrierFlags renderPassXferBarriers,
395                                              GrLoadOp colorLoadOp) {
396     GrGeometryProcessor* gp = this->makeGP(arena);
397     fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, usesMSAASurface,
398                                              std::move(appliedClip), dstProxyView, gp,
399                                              this->primitiveType(), renderPassXferBarriers,
400                                              colorLoadOp);
401 }
402 
onPrepareDraws(GrMeshDrawTarget * target)403 void DrawVerticesOpImpl::onPrepareDraws(GrMeshDrawTarget* target) {
404     // Allocate buffers.
405     size_t vertexStride = this->vertexStride();
406     sk_sp<const GrBuffer> vertexBuffer;
407     int firstVertex = 0;
408     VertexWriter verts{
409             target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex)};
410     if (!verts) {
411         SkDebugf("Could not allocate vertices\n");
412         return;
413     }
414 
415     sk_sp<const GrBuffer> indexBuffer;
416     int firstIndex = 0;
417     uint16_t* indices = nullptr;
418     if (this->isIndexed()) {
419         indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
420         if (!indices) {
421             SkDebugf("Could not allocate indices\n");
422             return;
423         }
424     }
425 
426     // Copy data into the buffers.
427     bool hasColorAttribute = this->requiresPerVertexColors();
428     bool hasLocalCoordsAttribute = this->requiresPerVertexLocalCoords();
429     int vertexOffset = 0;
430 
431     for (const auto& mesh : fMeshes) {
432         SkVerticesPriv info(mesh.fVertices->priv());
433 
434         // Copy data into the index buffer.
435         if (indices) {
436             int indexCount = info.indexCount();
437             for (int i = 0; i < indexCount; ++i) {
438                 *indices++ = info.indices()[i] + vertexOffset;
439             }
440         }
441 
442         // Copy data into the vertex buffer.
443         int vertexCount = info.vertexCount();
444         const SkPoint* positions = info.positions();
445         const SkColor* colors = info.colors();
446         const SkPoint* localCoords = info.texCoords() ? info.texCoords() : positions;
447 
448         // TODO4F: Preserve float colors
449         GrColor meshColor = mesh.fColor.toBytes_RGBA();
450 
451         SkPoint* posBase = (SkPoint*)verts.ptr();
452 
453         for (int i = 0; i < vertexCount; ++i) {
454             verts << positions[i];
455             if (hasColorAttribute) {
456                 verts << (mesh.hasPerVertexColors() ? colors[i] : meshColor);
457             }
458             if (hasLocalCoordsAttribute) {
459                 verts << localCoords[i];
460             }
461         }
462 
463         if (fMultipleViewMatrices) {
464             SkASSERT(!mesh.fViewMatrix.hasPerspective());
465             SkMatrixPriv::MapPointsWithStride(mesh.fViewMatrix, posBase, vertexStride,
466                                               positions, sizeof(SkPoint), vertexCount);
467         }
468 
469         vertexOffset += vertexCount;
470     }
471 
472     SkASSERT(!fMesh);
473     fMesh = target->allocMesh();
474     if (this->isIndexed()) {
475         fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
476                          GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
477     } else {
478         fMesh->set(std::move(vertexBuffer), fVertexCount, firstVertex);
479     }
480 }
481 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)482 void DrawVerticesOpImpl::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
483     if (!fProgramInfo) {
484         this->createProgramInfo(flushState);
485     }
486 
487     if (!fProgramInfo || !fMesh) {
488         return;
489     }
490 
491     flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
492     flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
493     flushState->drawMesh(*fMesh);
494 }
495 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)496 GrOp::CombineResult DrawVerticesOpImpl::onCombineIfPossible(GrOp* t,
497                                                             SkArenaAlloc*,
498                                                             const GrCaps& caps) {
499     auto that = t->cast<DrawVerticesOpImpl>();
500 
501     if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
502         return CombineResult::kCannotCombine;
503     }
504 
505     if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
506         return CombineResult::kCannotCombine;
507     }
508 
509     if (this->isIndexed() != that->isIndexed()) {
510         return CombineResult::kCannotCombine;
511     }
512 
513     if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
514         return CombineResult::kCannotCombine;
515     }
516 
517     // We can't mix draws that use SkColor vertex colors with those that don't. We can mix uniform
518     // color draws with GrColor draws (by expanding the uniform color into vertex color).
519     if ((fColorArrayType == ColorArrayType::kSkColor) !=
520         (that->fColorArrayType == ColorArrayType::kSkColor)) {
521         return CombineResult::kCannotCombine;
522     }
523 
524     // If we're acquiring a mesh with a different view matrix, or an op that needed multiple view
525     // matrices, we need multiple view matrices.
526     bool needMultipleViewMatrices =
527             fMultipleViewMatrices || that->fMultipleViewMatrices ||
528             !SkMatrixPriv::CheapEqual(this->fMeshes[0].fViewMatrix, that->fMeshes[0].fViewMatrix);
529 
530     // ... but we can't enable multiple view matrices if any of them have perspective, or our other
531     // varyings won't be interpolated correctly.
532     if (needMultipleViewMatrices && (this->fMeshes[0].fViewMatrix.hasPerspective() ||
533                                      that->fMeshes[0].fViewMatrix.hasPerspective())) {
534         return CombineResult::kCannotCombine;
535     } else {
536         fMultipleViewMatrices = needMultipleViewMatrices;
537     }
538 
539     // If the other op already required per-vertex colors, the combined mesh does.
540     if (that->fColorArrayType == ColorArrayType::kPremulGrColor) {
541         fColorArrayType = ColorArrayType::kPremulGrColor;
542     }
543 
544     // If we combine meshes with different (uniform) colors, switch to per-vertex colors.
545     if (fColorArrayType == ColorArrayType::kUnused) {
546         SkASSERT(that->fColorArrayType == ColorArrayType::kUnused);
547         if (this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
548             fColorArrayType = ColorArrayType::kPremulGrColor;
549         }
550     }
551 
552     // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
553     // gamut is determined by the render target context. A mis-match should be impossible.
554     SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
555 
556     // If the other op already required explicit local coords the combined mesh does.
557     if (that->fLocalCoordsType == LocalCoordsType::kExplicit) {
558         fLocalCoordsType = LocalCoordsType::kExplicit;
559     }
560 
561     // If we were planning to use positions for local coords but now have multiple view matrices,
562     // switch to explicit local coords.
563     if (fLocalCoordsType == LocalCoordsType::kUsePosition && fMultipleViewMatrices) {
564         fLocalCoordsType = LocalCoordsType::kExplicit;
565     }
566 
567     fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
568     fVertexCount += that->fVertexCount;
569     fIndexCount += that->fIndexCount;
570 
571     return CombineResult::kMerged;
572 }
573 
SkVertexModeToGrPrimitiveType(SkVertices::VertexMode mode)574 static GrPrimitiveType SkVertexModeToGrPrimitiveType(SkVertices::VertexMode mode) {
575     switch (mode) {
576         case SkVertices::kTriangles_VertexMode:
577             return GrPrimitiveType::kTriangles;
578         case SkVertices::kTriangleStrip_VertexMode:
579             return GrPrimitiveType::kTriangleStrip;
580         case SkVertices::kTriangleFan_VertexMode:
581             break;
582     }
583     SK_ABORT("Invalid mode");
584 }
585 
586 } // anonymous namespace
587 
Make(GrRecordingContext * context,GrPaint && paint,sk_sp<SkVertices> vertices,const SkMatrixProvider & matrixProvider,GrAAType aaType,sk_sp<GrColorSpaceXform> colorSpaceXform,GrPrimitiveType * overridePrimType)588 GrOp::Owner Make(GrRecordingContext* context,
589                  GrPaint&& paint,
590                  sk_sp<SkVertices> vertices,
591                  const SkMatrixProvider& matrixProvider,
592                  GrAAType aaType,
593                  sk_sp<GrColorSpaceXform> colorSpaceXform,
594                  GrPrimitiveType* overridePrimType) {
595     SkASSERT(vertices);
596     GrPrimitiveType primType = overridePrimType
597                                        ? *overridePrimType
598                                        : SkVertexModeToGrPrimitiveType(vertices->priv().mode());
599     return GrSimpleMeshDrawOpHelper::FactoryHelper<DrawVerticesOpImpl>(context,
600                                                                        std::move(paint),
601                                                                        std::move(vertices),
602                                                                        primType,
603                                                                        aaType,
604                                                                        std::move(colorSpaceXform),
605                                                                        matrixProvider);
606 }
607 
608 } // namespace skgpu::v1::DrawVerticesOp
609 
610 ///////////////////////////////////////////////////////////////////////////////////////////////////
611 
612 #if GR_TEST_UTILS
613 
614 #include "src/gpu/GrDrawOpTest.h"
615 
seed_vertices(GrPrimitiveType type)616 static uint32_t seed_vertices(GrPrimitiveType type) {
617     switch (type) {
618         case GrPrimitiveType::kTriangles:
619         case GrPrimitiveType::kTriangleStrip:
620             return 3;
621         case GrPrimitiveType::kPoints:
622             return 1;
623         case GrPrimitiveType::kLines:
624         case GrPrimitiveType::kLineStrip:
625             return 2;
626         case GrPrimitiveType::kPatches:
627         case GrPrimitiveType::kPath:
628             SkASSERT(0);
629             return 0;
630     }
631     SK_ABORT("Incomplete switch\n");
632 }
633 
primitive_vertices(GrPrimitiveType type)634 static uint32_t primitive_vertices(GrPrimitiveType type) {
635     switch (type) {
636         case GrPrimitiveType::kTriangles:
637             return 3;
638         case GrPrimitiveType::kLines:
639             return 2;
640         case GrPrimitiveType::kTriangleStrip:
641         case GrPrimitiveType::kPoints:
642         case GrPrimitiveType::kLineStrip:
643             return 1;
644         case GrPrimitiveType::kPatches:
645         case GrPrimitiveType::kPath:
646             SkASSERT(0);
647             return 0;
648     }
649     SK_ABORT("Incomplete switch\n");
650 }
651 
random_point(SkRandom * random,SkScalar min,SkScalar max)652 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
653     SkPoint p;
654     p.fX = random->nextRangeScalar(min, max);
655     p.fY = random->nextRangeScalar(min, max);
656     return p;
657 }
658 
randomize_params(size_t count,size_t maxVertex,SkScalar min,SkScalar max,SkRandom * random,SkTArray<SkPoint> * positions,SkTArray<SkPoint> * texCoords,bool hasTexCoords,SkTArray<uint32_t> * colors,bool hasColors,SkTArray<uint16_t> * indices,bool hasIndices)659 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
660                              SkRandom* random, SkTArray<SkPoint>* positions,
661                              SkTArray<SkPoint>* texCoords, bool hasTexCoords,
662                              SkTArray<uint32_t>* colors, bool hasColors,
663                              SkTArray<uint16_t>* indices, bool hasIndices) {
664     for (uint32_t v = 0; v < count; v++) {
665         positions->push_back(random_point(random, min, max));
666         if (hasTexCoords) {
667             texCoords->push_back(random_point(random, min, max));
668         }
669         if (hasColors) {
670             colors->push_back(GrTest::RandomColor(random));
671         }
672         if (hasIndices) {
673             SkASSERT(maxVertex <= UINT16_MAX);
674             indices->push_back(random->nextULessThan((uint16_t)maxVertex));
675         }
676     }
677 }
678 
GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp)679 GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp) {
680     GrPrimitiveType types[] = {
681         GrPrimitiveType::kTriangles,
682         GrPrimitiveType::kTriangleStrip,
683         GrPrimitiveType::kPoints,
684         GrPrimitiveType::kLines,
685         GrPrimitiveType::kLineStrip
686     };
687     auto type = types[random->nextULessThan(SK_ARRAY_COUNT(types))];
688 
689     uint32_t primitiveCount = random->nextRangeU(1, 100);
690 
691     // TODO make 'sensible' indexbuffers
692     SkTArray<SkPoint> positions;
693     SkTArray<SkPoint> texCoords;
694     SkTArray<uint32_t> colors;
695     SkTArray<uint16_t> indices;
696 
697     bool hasTexCoords = random->nextBool();
698     bool hasIndices = random->nextBool();
699     bool hasColors = random->nextBool();
700 
701     uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
702 
703     static const SkScalar kMinVertExtent = -100.f;
704     static const SkScalar kMaxVertExtent = 100.f;
705     randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
706                      &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
707                      hasIndices);
708 
709     for (uint32_t i = 1; i < primitiveCount; i++) {
710         randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
711                          random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
712                          hasIndices);
713     }
714 
715     SkSimpleMatrixProvider matrixProvider(GrTest::TestMatrix(random));
716 
717     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
718 
719     static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
720     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
721                                                       texCoords.begin(), colors.begin(),
722                                                       hasIndices ? indices.count() : 0,
723                                                       indices.begin());
724     GrAAType aaType = GrAAType::kNone;
725     if (numSamples > 1 && random->nextBool()) {
726         aaType = GrAAType::kMSAA;
727     }
728     return skgpu::v1::DrawVerticesOp::Make(context,
729                                            std::move(paint),
730                                            std::move(vertices),
731                                            matrixProvider,
732                                            aaType,
733                                            std::move(colorSpaceXform),
734                                            &type);
735 }
736 
737 #endif
738