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