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