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 "include/core/SkM44.h"
9#include "include/effects/SkRuntimeEffect.h"
10#include "src/core/SkArenaAlloc.h"
11#include "src/core/SkVerticesPriv.h"
12#include "src/gpu/GrOpFlushState.h"
13#include "src/gpu/GrProgramInfo.h"
14#include "src/gpu/GrVertexWriter.h"
15#include "src/gpu/SkGr.h"
16#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
17#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
19#include "src/gpu/glsl/GrGLSLVarying.h"
20#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
21#include "src/gpu/ops/GrDrawVerticesOp.h"
22#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
23
24namespace {
25
26enum class ColorArrayType {
27 kUnused,
28 kPremulGrColor,
29 kSkColor,
30};
31
32enum class LocalCoordsType {
33 kUnused,
34 kUsePosition,
35 kExplicit,
36};
37
38static GrVertexAttribType SkVerticesAttributeToGrVertexAttribType(const SkVertices::Attribute& a) {
39 switch (a.fType) {
40 case SkVertices::Attribute::Type::kFloat: return kFloat_GrVertexAttribType;
41 case SkVertices::Attribute::Type::kFloat2: return kFloat2_GrVertexAttribType;
42 case SkVertices::Attribute::Type::kFloat3: return kFloat3_GrVertexAttribType;
43 case SkVertices::Attribute::Type::kFloat4: return kFloat4_GrVertexAttribType;
44 case SkVertices::Attribute::Type::kByte4_unorm: return kUByte4_norm_GrVertexAttribType;
45 }
46 SkUNREACHABLE;
47}
48
49static GrSLType SkVerticesAttributeToGrSLType(const SkVertices::Attribute& a) {
50 switch (a.fType) {
51 case SkVertices::Attribute::Type::kFloat: return kFloat_GrSLType;
52 case SkVertices::Attribute::Type::kFloat2: return kFloat2_GrSLType;
53 case SkVertices::Attribute::Type::kFloat3: return kFloat3_GrSLType;
54 case SkVertices::Attribute::Type::kFloat4: return kFloat4_GrSLType;
55 case SkVertices::Attribute::Type::kByte4_unorm: return kHalf4_GrSLType;
56 }
57 SkUNREACHABLE;
58}
59
60class VerticesGP : public GrGeometryProcessor {
61public:
62 static GrGeometryProcessor* Make(SkArenaAlloc* arena,
63 LocalCoordsType localCoordsType,
64 ColorArrayType colorArrayType,
65 const SkPMColor4f& color,
66 sk_sp<GrColorSpaceXform> colorSpaceXform,
67 const SkMatrix& viewMatrix,
68 const SkVertices::Attribute* attrs,
69 int attrCount,
70 const SkM44& localToWorld) {
71 return arena->make<VerticesGP>(localCoordsType, colorArrayType, color,
72 std::move(colorSpaceXform), viewMatrix, attrs, attrCount,
73 localToWorld);
74 }
75
76 const char* name() const override { return "VerticesGP"; }
77
78 const SkPMColor4f& color() const { return fColor; }
79 const SkMatrix& viewMatrix() const { return fViewMatrix; }
80
81 const Attribute& positionAttr() const { return fAttributes[kPositionIndex]; }
82 const Attribute& colorAttr() const { return fAttributes[kColorIndex]; }
83 const Attribute& localCoordsAttr() const { return fAttributes[kLocalCoordsIndex]; }
84
85 class GLSLProcessor : public GrGLSLGeometryProcessor {
86 public:
87 GLSLProcessor()
88 : fViewMatrix(SkMatrix::InvalidMatrix())
89 , fColor(SK_PMColor4fILLEGAL) {}
90
91 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
92 const VerticesGP& gp = args.fGP.cast<VerticesGP>();
93 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
94 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
95 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
96 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
97
98 // emit attributes
99 varyingHandler->emitAttributes(gp);
100
101 fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
102 kVertex_GrShaderFlag);
103
104 // Setup pass through color
105 if (gp.colorAttr().isInitialized()) {
106 GrGLSLVarying varying(kHalf4_GrSLType);
107 varyingHandler->addVarying("color", &varying);
108 vertBuilder->codeAppendf("half4 color = %s;", gp.colorAttr().name());
109
110 // For SkColor, do a red/blue swap, possible color space conversion, and premul
111 if (gp.fColorArrayType == ColorArrayType::kSkColor) {
112 vertBuilder->codeAppend("color = color.bgra;");
113
114 SkString xformedColor;
115 vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper);
116 vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
117
118 vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
119 }
120
121 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
122 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
123 } else {
124 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
125 &fColorUniform);
126 }
127
128 // Setup position
129 this->writeOutputPosition(vertBuilder,
130 uniformHandler,
131 gpArgs,
132 gp.positionAttr().name(),
133 gp.viewMatrix(),
134 &fViewMatrixUniform);
135
136 // emit transforms using either explicit local coords or positions
137 const auto& coordsAttr = gp.localCoordsAttr().isInitialized() ? gp.localCoordsAttr()
138 : gp.positionAttr();
139 this->emitTransforms(vertBuilder,
140 varyingHandler,
141 uniformHandler,
142 coordsAttr.asShaderVar(),
143 SkMatrix::I(),
144 args.fFPCoordTransformHandler);
145
146 // Add varyings and globals for all custom attributes
147 for (size_t i = kFirstCustomIndex; i < gp.fAttributes.size(); ++i) {
148 const auto& attr(gp.fAttributes[i]);
149 const int customIdx = i - kFirstCustomIndex;
150 auto usage = gp.fUsages[customIdx];
151
152 GrSLType varyingType = attr.gpuType();
153 SkString varyingIn(attr.name());
154
155 switch (usage) {
156 case SkVertices::Attribute::Usage::kRaw:
157 break;
158 case SkVertices::Attribute::Usage::kColor: {
159 // For RGB colors, expand to RGBA with A = 1
160 if (attr.gpuType() == kFloat3_GrSLType) {
161 varyingIn = SkStringPrintf("float4(%s, 1)", attr.name());
162 }
163 // Convert to half (as expected by the color space transform functions)
164 varyingIn = SkStringPrintf("half4(%s)", varyingIn.c_str());
165 // Transform to destination color space (possible no-op)
166 SkString xformedColor;
167 vertBuilder->appendColorGamutXform(&xformedColor, varyingIn.c_str(),
168 &fColorSpaceHelper);
169 // Store the result of the transform in a temporary
170 vertBuilder->codeAppendf(
171 "half4 _tmp_clr_%d = %s;", customIdx, xformedColor.c_str());
172 // Finally, premultiply
173 varyingIn = SkStringPrintf(
174 "half4(_tmp_clr_%d.rgb * _tmp_clr_%d.a, _tmp_clr_%d.a)",
175 customIdx, customIdx, customIdx);
176 varyingType = kHalf4_GrSLType;
177 break;
178 }
179 case SkVertices::Attribute::Usage::kVector: {
180 if (!fLocalToWorldMatrixUniform.isValid()) {
181 fLocalToWorldMatrixUniform =
182 uniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
183 kFloat4x4_GrSLType, "localToWorld");
184 }
185 if (attr.gpuType() == kFloat2_GrSLType) {
186 varyingIn = SkStringPrintf("float3(%s, 0)", attr.name());
187 }
188 varyingIn = SkStringPrintf(
189 "normalize((%s * float4(%s, 0)).xyz)",
190 uniformHandler->getUniformCStr(fLocalToWorldMatrixUniform),
191 varyingIn.c_str());
192 varyingType = kFloat3_GrSLType;
193 break;
194 }
195 case SkVertices::Attribute::Usage::kNormalVector: {
196 if (!fNormalMatrixUniform.isValid()) {
197 fNormalMatrixUniform = uniformHandler->addUniform(
198 nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType,
199 "localToWorld_IT");
200 }
201 if (attr.gpuType() == kFloat2_GrSLType) {
202 varyingIn = SkStringPrintf("float3(%s, 0)", attr.name());
203 }
204 varyingIn = SkStringPrintf(
205 "normalize(%s * %s)",
206 uniformHandler->getUniformCStr(fNormalMatrixUniform),
207 varyingIn.c_str());
208 varyingType = kFloat3_GrSLType;
209 break;
210 }
211 case SkVertices::Attribute::Usage::kPosition: {
212 if (!fLocalToWorldMatrixUniform.isValid()) {
213 fLocalToWorldMatrixUniform =
214 uniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
215 kFloat4x4_GrSLType, "localToWorld");
216 }
217 if (attr.gpuType() == kFloat2_GrSLType) {
218 varyingIn = SkStringPrintf("float3(%s, 0)", attr.name());
219 }
220 vertBuilder->codeAppendf(
221 "float4 _tmp_pos_%d = %s * float4(%s, 1);",
222 customIdx,
223 uniformHandler->getUniformCStr(fLocalToWorldMatrixUniform),
224 varyingIn.c_str());
225 varyingIn = SkStringPrintf("_tmp_pos_%d.xyz / _tmp_pos_%d.w",
226 customIdx, customIdx);
227 varyingType = kFloat3_GrSLType;
228 }
229 }
230
231 GrGLSLVarying varying(varyingType);
232 varyingHandler->addVarying(attr.name(), &varying);
233 vertBuilder->codeAppendf("%s = %s;", varying.vsOut(), varyingIn.c_str());
234
235 GrShaderVar var(SkStringPrintf("_vtx_attr_%d", customIdx), varyingType);
236 fragBuilder->declareGlobal(var);
237 fragBuilder->codeAppendf("%s = %s;", var.c_str(), varying.fsIn());
238 }
239
240 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
241 }
242
243 static inline void GenKey(const GrGeometryProcessor& gp,
244 const GrShaderCaps&,
245 GrProcessorKeyBuilder* b) {
246 const VerticesGP& vgp = gp.cast<VerticesGP>();
247 uint32_t key = 0;
248 key |= (vgp.fColorArrayType == ColorArrayType::kSkColor) ? 0x1 : 0;
249 key |= ComputePosKey(vgp.viewMatrix()) << 20;
250 b->add32(key);
251 b->add32(GrColorSpaceXform::XformKey(vgp.fColorSpaceXform.get()));
252
253 uint32_t usageKey = 0;
254 SkASSERT(vgp.fUsages.size() <= 8);
255 for (size_t i = 0; i < vgp.fUsages.size(); ++i) {
256 SkASSERT((uint32_t)vgp.fUsages[i] < (1 << 4));
257 usageKey = (usageKey << 4) | (uint32_t)vgp.fUsages[i];
258 }
259 b->add32(usageKey);
260 }
261
262 void setData(const GrGLSLProgramDataManager& pdman,
263 const GrPrimitiveProcessor& gp,
264 const CoordTransformRange& transformRange) override {
265 const VerticesGP& vgp = gp.cast<VerticesGP>();
266
267 if (!vgp.viewMatrix().isIdentity() &&
268 !SkMatrixPriv::CheapEqual(fViewMatrix, vgp.viewMatrix())) {
269 fViewMatrix = vgp.viewMatrix();
270 pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix);
271 }
272
273 if (!vgp.colorAttr().isInitialized() && vgp.color() != fColor) {
274 pdman.set4fv(fColorUniform, 1, vgp.color().vec());
275 fColor = vgp.color();
276 }
277
278 this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
279
280 fColorSpaceHelper.setData(pdman, vgp.fColorSpaceXform.get());
281
282 if (fLocalToWorldMatrixUniform.isValid()) {
283 pdman.setSkM44(fLocalToWorldMatrixUniform, vgp.fLocalToWorldMatrix);
284 }
285
286 if (fNormalMatrixUniform.isValid()) {
287 // Get the upper-left 3x3 (rotation + scale) of local to world:
288 SkM44 mtx(vgp.fLocalToWorldMatrix);
289 mtx.setCol(3, {0, 0, 0, 1});
290 mtx.setRow(3, {0, 0, 0, 1});
291 // Invert it...
292 SkAssertResult(mtx.invert(&mtx));
293 // We want the inverse transpose, but we're going to feed it as a 3x3 column major
294 // matrix to the uniform. So copy the (not-yet-transposed) values out in row order.
295 float l2wIT[9] = { mtx.rc(0, 0), mtx.rc(0, 1), mtx.rc(0, 2),
296 mtx.rc(1, 0), mtx.rc(1, 1), mtx.rc(1, 2),
297 mtx.rc(2, 0), mtx.rc(2, 1), mtx.rc(2, 2) };
298 pdman.setMatrix3f(fNormalMatrixUniform, l2wIT);
299 }
300 }
301
302 private:
303 SkMatrix fViewMatrix;
304 SkPMColor4f fColor;
305 UniformHandle fViewMatrixUniform;
306 UniformHandle fColorUniform;
307 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
308
309 UniformHandle fLocalToWorldMatrixUniform;
310 UniformHandle fNormalMatrixUniform;
311
312 typedef GrGLSLGeometryProcessor INHERITED;
313 };
314
315 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
316 GLSLProcessor::GenKey(*this, caps, b);
317 }
318
319 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
320 return new GLSLProcessor();
321 }
322
323private:
324 friend class ::SkArenaAlloc; // for access to ctor
325
326 VerticesGP(LocalCoordsType localCoordsType,
327 ColorArrayType colorArrayType,
328 const SkPMColor4f& color,
329 sk_sp<GrColorSpaceXform> colorSpaceXform,
330 const SkMatrix& viewMatrix,
331 const SkVertices::Attribute* attrs,
332 int attrCount,
333 const SkM44& localToWorld)
334 : INHERITED(kVerticesGP_ClassID)
335 , fColorArrayType(colorArrayType)
336 , fColor(color)
337 , fViewMatrix(viewMatrix)
338 , fColorSpaceXform(std::move(colorSpaceXform))
339 , fLocalToWorldMatrix(localToWorld) {
340 constexpr Attribute missingAttr;
341 fAttributes.push_back({"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType});
342 fAttributes.push_back(fColorArrayType != ColorArrayType::kUnused
343 ? MakeColorAttribute("inColor", false)
344 : missingAttr);
345 fAttributes.push_back(localCoordsType == LocalCoordsType::kExplicit
346 ? Attribute{"inLocalCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType}
347 : missingAttr);
348
349 for (int i = 0; i < attrCount; ++i) {
350 // Attributes store char*, so allocate long-lived storage for the (dynamic) names
351 fAttrNames.push_back(SkStringPrintf("_vtx_attr%d", i));
352 fAttributes.push_back({fAttrNames.back().c_str(),
353 SkVerticesAttributeToGrVertexAttribType(attrs[i]),
354 SkVerticesAttributeToGrSLType(attrs[i])});
355 fUsages.push_back(attrs[i].fUsage);
356 }
357
358 this->setVertexAttributes(fAttributes.data(), fAttributes.size());
359 }
360
361 enum {
362 kPositionIndex = 0,
363 kColorIndex = 1,
364 kLocalCoordsIndex = 2,
365 kFirstCustomIndex = 3,
366 };
367
368 std::vector<SkString> fAttrNames;
369 std::vector<Attribute> fAttributes;
370 std::vector<SkVertices::Attribute::Usage> fUsages;
371 ColorArrayType fColorArrayType;
372 SkPMColor4f fColor;
373 SkMatrix fViewMatrix;
374 sk_sp<GrColorSpaceXform> fColorSpaceXform;
375 SkM44 fLocalToWorldMatrix;
376
377 typedef GrGeometryProcessor INHERITED;
378};
379
380class DrawVerticesOp final : public GrMeshDrawOp {
381private:
382 using Helper = GrSimpleMeshDrawOpHelper;
383
384public:
385 DEFINE_OP_CLASS_ID
386
387 DrawVerticesOp(const Helper::MakeArgs&, const SkPMColor4f&, sk_sp<SkVertices>,
388 GrPrimitiveType, GrAAType, sk_sp<GrColorSpaceXform>, const SkMatrix& viewMatrix,
389 const SkRuntimeEffect*, const SkM44* localToWorld);
390
391 const char* name() const override { return "DrawVerticesOp"; }
392
393 void visitProxies(const VisitProxyFunc& func) const override {
394 if (fProgramInfo) {
395 fProgramInfo->visitFPProxies(func);
396 } else {
397 fHelper.visitProxies(func);
398 }
399 }
400
401#ifdef SK_DEBUG
402 SkString dumpInfo() const override;
403#endif
404
405 FixedFunctionFlags fixedFunctionFlags() const override;
406
407 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
408 bool hasMixedSampledCoverage, GrClampType) override;
409
410private:
411 GrProgramInfo* programInfo() override { return fProgramInfo; }
412
413 void onCreateProgramInfo(const GrCaps*,
414 SkArenaAlloc*,
415 const GrSurfaceProxyView* writeView,
416 GrAppliedClip&&,
417 const GrXferProcessor::DstProxyView&) override;
418
419 void onPrepareDraws(Target*) override;
420 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
421
422 GrGeometryProcessor* makeGP(SkArenaAlloc*);
423
424 GrPrimitiveType primitiveType() const { return fPrimitiveType; }
425 bool combinablePrimitive() const {
426 return GrPrimitiveType::kTriangles == fPrimitiveType ||
427 GrPrimitiveType::kLines == fPrimitiveType ||
428 GrPrimitiveType::kPoints == fPrimitiveType;
429 }
430
431 CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*, const GrCaps&) override;
432
433 struct Mesh {
434 SkPMColor4f fColor; // Used if this->hasPerVertexColors() is false.
435 sk_sp<SkVertices> fVertices;
436 SkMatrix fViewMatrix;
437 bool fIgnoreColors;
438
439 bool hasPerVertexColors() const {
440 return fVertices->priv().hasColors() && !fIgnoreColors;
441 }
442 };
443
444 bool isIndexed() const {
445 // Consistency enforced in onCombineIfPossible.
446 return fMeshes[0].fVertices->priv().hasIndices();
447 }
448
449 bool requiresPerVertexColors() const {
450 return fColorArrayType != ColorArrayType::kUnused;
451 }
452
453 bool requiresPerVertexLocalCoords() const {
454 return fLocalCoordsType == LocalCoordsType::kExplicit;
455 }
456
457 size_t vertexStride() const {
458 return sizeof(SkPoint) +
459 (this->requiresPerVertexColors() ? sizeof(uint32_t) : 0) +
460 (this->requiresPerVertexLocalCoords() ? sizeof(SkPoint) : 0) +
461 fMeshes[0].fVertices->priv().customDataSize();
462 }
463
464 Helper fHelper;
465 SkSTArray<1, Mesh, true> fMeshes;
466 // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore
467 // the SkVertices mode (though fPrimitiveType may have been inferred from it).
468 GrPrimitiveType fPrimitiveType;
469 int fVertexCount;
470 int fIndexCount;
471 bool fMultipleViewMatrices;
472 LocalCoordsType fLocalCoordsType;
473 ColorArrayType fColorArrayType;
474 sk_sp<GrColorSpaceXform> fColorSpaceXform;
475 SkM44 fLocalToWorld;
476
477 GrSimpleMesh* fMesh = nullptr;
478 GrProgramInfo* fProgramInfo = nullptr;
479
480 typedef GrMeshDrawOp INHERITED;
481};
482
483DrawVerticesOp::DrawVerticesOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
484 sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType,
485 GrAAType aaType, sk_sp<GrColorSpaceXform> colorSpaceXform,
486 const SkMatrix& viewMatrix, const SkRuntimeEffect* effect,
487 const SkM44* localToWorld)
488 : INHERITED(ClassID())
489 , fHelper(helperArgs, aaType)
490 , fPrimitiveType(primitiveType)
491 , fMultipleViewMatrices(false)
492 , fColorSpaceXform(std::move(colorSpaceXform)) {
493 SkASSERT(vertices);
494
495 SkVerticesPriv info(vertices->priv());
496
497 fVertexCount = info.vertexCount();
498 fIndexCount = info.indexCount();
499 fColorArrayType = info.hasColors() ? ColorArrayType::kSkColor
500 : ColorArrayType::kUnused;
501 fLocalCoordsType = info.hasTexCoords() ? LocalCoordsType::kExplicit
502 : LocalCoordsType::kUsePosition;
503 if (localToWorld) {
504 fLocalToWorld = *localToWorld;
505 } else {
506 fLocalToWorld.setIdentity();
507 }
508
509 Mesh& mesh = fMeshes.push_back();
510 mesh.fColor = color;
511 mesh.fViewMatrix = viewMatrix;
512 mesh.fVertices = std::move(vertices);
513 mesh.fIgnoreColors = false;
514
515 IsHairline zeroArea;
516 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
517 zeroArea = IsHairline::kYes;
518 } else {
519 zeroArea = IsHairline::kNo;
520 }
521
522 this->setTransformedBounds(mesh.fVertices->bounds(),
523 mesh.fViewMatrix,
524 HasAABloat::kNo,
525 zeroArea);
526}
527
528#ifdef SK_DEBUG
529SkString DrawVerticesOp::dumpInfo() const {
530 SkString string;
531 string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
532 fMeshes.count(), fVertexCount, fIndexCount);
533 string += fHelper.dumpInfo();
534 string += INHERITED::dumpInfo();
535 return string;
536}
537#endif
538
539GrDrawOp::FixedFunctionFlags DrawVerticesOp::fixedFunctionFlags() const {
540 return fHelper.fixedFunctionFlags();
541}
542
543GrProcessorSet::Analysis DrawVerticesOp::finalize(
544 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
545 GrClampType clampType) {
546 GrProcessorAnalysisColor gpColor;
547 if (this->requiresPerVertexColors()) {
548 gpColor.setToUnknown();
549 } else {
550 gpColor.setToConstant(fMeshes.front().fColor);
551 }
552 auto result = fHelper.finalizeProcessors(caps, clip, hasMixedSampledCoverage, clampType,
553 GrProcessorAnalysisCoverage::kNone, &gpColor);
554 if (gpColor.isConstant(&fMeshes.front().fColor)) {
555 fMeshes.front().fIgnoreColors = true;
556 fColorArrayType = ColorArrayType::kUnused;
557 }
558 if (!fHelper.usesLocalCoords()) {
559 fLocalCoordsType = LocalCoordsType::kUnused;
560 }
561 return result;
562}
563
564GrGeometryProcessor* DrawVerticesOp::makeGP(SkArenaAlloc* arena) {
565 const SkMatrix& vm = fMultipleViewMatrices ? SkMatrix::I() : fMeshes[0].fViewMatrix;
566
567 SkVerticesPriv info(fMeshes[0].fVertices->priv());
568
569 sk_sp<GrColorSpaceXform> csxform = (fColorArrayType == ColorArrayType::kSkColor ||
570 info.hasUsage(SkVertices::Attribute::Usage::kColor))
571 ? fColorSpaceXform
572 : nullptr;
573
574 auto gp = VerticesGP::Make(arena, fLocalCoordsType, fColorArrayType, fMeshes[0].fColor,
575 std::move(csxform), vm, info.attributes(), info.attributeCount(),
576 fLocalToWorld);
577 SkASSERT(this->vertexStride() == gp->vertexStride());
578 return gp;
579}
580
581void DrawVerticesOp::onCreateProgramInfo(const GrCaps* caps,
582 SkArenaAlloc* arena,
583 const GrSurfaceProxyView* writeView,
584 GrAppliedClip&& appliedClip,
585 const GrXferProcessor::DstProxyView& dstProxyView) {
586 GrGeometryProcessor* gp = this->makeGP(arena);
587 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, std::move(appliedClip),
588 dstProxyView, gp, this->primitiveType());
589}
590
591void DrawVerticesOp::onPrepareDraws(Target* target) {
592 // Allocate buffers.
593 size_t vertexStride = this->vertexStride();
594 sk_sp<const GrBuffer> vertexBuffer;
595 int firstVertex = 0;
596 GrVertexWriter verts{
597 target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex)};
598 if (!verts.fPtr) {
599 SkDebugf("Could not allocate vertices\n");
600 return;
601 }
602
603 sk_sp<const GrBuffer> indexBuffer;
604 int firstIndex = 0;
605 uint16_t* indices = nullptr;
606 if (this->isIndexed()) {
607 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
608 if (!indices) {
609 SkDebugf("Could not allocate indices\n");
610 return;
611 }
612 }
613
614 // Copy data into the buffers.
615 bool hasColorAttribute = this->requiresPerVertexColors();
616 bool hasLocalCoordsAttribute = this->requiresPerVertexLocalCoords();
617 int vertexOffset = 0;
618
619 for (const auto& mesh : fMeshes) {
620 SkVerticesPriv info(mesh.fVertices->priv());
621
622 // Copy data into the index buffer.
623 if (indices) {
624 int indexCount = info.indexCount();
625 for (int i = 0; i < indexCount; ++i) {
626 *indices++ = info.indices()[i] + vertexOffset;
627 }
628 }
629
630 // Copy data into the vertex buffer.
631 int vertexCount = info.vertexCount();
632 const SkPoint* positions = info.positions();
633 const SkColor* colors = info.colors();
634 const SkPoint* localCoords = info.texCoords() ? info.texCoords() : positions;
635 const void* custom = info.customData();
636 size_t customDataSize = info.customDataSize();
637
638 // TODO4F: Preserve float colors
639 GrColor meshColor = mesh.fColor.toBytes_RGBA();
640
641 SkPoint* posBase = (SkPoint*)verts.fPtr;
642
643 for (int i = 0; i < vertexCount; ++i) {
644 verts.write(positions[i]);
645 if (hasColorAttribute) {
646 verts.write(mesh.hasPerVertexColors() ? colors[i] : meshColor);
647 }
648 if (hasLocalCoordsAttribute) {
649 verts.write(localCoords[i]);
650 }
651 if (customDataSize) {
652 verts.writeRaw(custom, customDataSize);
653 custom = SkTAddOffset<const void>(custom, customDataSize);
654 }
655 }
656
657 if (fMultipleViewMatrices) {
658 SkASSERT(!mesh.fViewMatrix.hasPerspective());
659 SkMatrixPriv::MapPointsWithStride(mesh.fViewMatrix, posBase, vertexStride, vertexCount);
660 }
661
662 vertexOffset += vertexCount;
663 }
664
665 SkASSERT(!fMesh);
666 fMesh = target->allocMesh();
667 if (this->isIndexed()) {
668 fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
669 GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
670 } else {
671 fMesh->set(std::move(vertexBuffer), fVertexCount, firstVertex);
672 }
673}
674
675void DrawVerticesOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
676 if (!fProgramInfo) {
677 this->createProgramInfo(flushState);
678 }
679
680 if (!fProgramInfo || !fMesh) {
681 return;
682 }
683
684 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
685 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
686 flushState->drawMesh(*fMesh);
687}
688
689GrOp::CombineResult DrawVerticesOp::onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
690 const GrCaps& caps) {
691 DrawVerticesOp* that = t->cast<DrawVerticesOp>();
692
693 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
694 return CombineResult::kCannotCombine;
695 }
696
697 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
698 return CombineResult::kCannotCombine;
699 }
700
701 if (this->isIndexed() != that->isIndexed()) {
702 return CombineResult::kCannotCombine;
703 }
704
705 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
706 return CombineResult::kCannotCombine;
707 }
708
709 SkVerticesPriv vThis(this->fMeshes[0].fVertices->priv()),
710 vThat(that->fMeshes[0].fVertices->priv());
711 if (vThis.attributeCount() != vThat.attributeCount() ||
712 !std::equal(vThis.attributes(), vThis.attributes() + vThis.attributeCount(),
713 vThat.attributes())) {
714 return CombineResult::kCannotCombine;
715 }
716
717 if (vThis.usesLocalToWorldMatrix() && this->fLocalToWorld != that->fLocalToWorld) {
718 return CombineResult::kCannotCombine;
719 }
720
721 // We can't mix draws that use SkColor vertex colors with those that don't. We can mix uniform
722 // color draws with GrColor draws (by expanding the uniform color into vertex color).
723 if ((fColorArrayType == ColorArrayType::kSkColor) !=
724 (that->fColorArrayType == ColorArrayType::kSkColor)) {
725 return CombineResult::kCannotCombine;
726 }
727
728 // If we're acquiring a mesh with a different view matrix, or an op that needed multiple view
729 // matrices, we need multiple view matrices.
730 bool needMultipleViewMatrices =
731 fMultipleViewMatrices || that->fMultipleViewMatrices ||
732 !SkMatrixPriv::CheapEqual(this->fMeshes[0].fViewMatrix, that->fMeshes[0].fViewMatrix);
733
734 // ... but we can't enable multiple view matrices if any of them have perspective, or our other
735 // varyings won't be interpolated correctly.
736 if (needMultipleViewMatrices && (this->fMeshes[0].fViewMatrix.hasPerspective() ||
737 that->fMeshes[0].fViewMatrix.hasPerspective())) {
738 return CombineResult::kCannotCombine;
739 } else {
740 fMultipleViewMatrices = needMultipleViewMatrices;
741 }
742
743 // If the other op already required per-vertex colors, the combined mesh does.
744 if (that->fColorArrayType == ColorArrayType::kPremulGrColor) {
745 fColorArrayType = ColorArrayType::kPremulGrColor;
746 }
747
748 // If we combine meshes with different (uniform) colors, switch to per-vertex colors.
749 if (fColorArrayType == ColorArrayType::kUnused) {
750 SkASSERT(that->fColorArrayType == ColorArrayType::kUnused);
751 if (this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
752 fColorArrayType = ColorArrayType::kPremulGrColor;
753 }
754 }
755
756 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
757 // gamut is determined by the render target context. A mis-match should be impossible.
758 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
759
760 // If the other op already required explicit local coords the combined mesh does.
761 if (that->fLocalCoordsType == LocalCoordsType::kExplicit) {
762 fLocalCoordsType = LocalCoordsType::kExplicit;
763 }
764
765 // If we were planning to use positions for local coords but now have multiple view matrices,
766 // switch to explicit local coords.
767 if (fLocalCoordsType == LocalCoordsType::kUsePosition && fMultipleViewMatrices) {
768 fLocalCoordsType = LocalCoordsType::kExplicit;
769 }
770
771 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
772 fVertexCount += that->fVertexCount;
773 fIndexCount += that->fIndexCount;
774
775 return CombineResult::kMerged;
776}
777
778} // anonymous namespace
779
780static GrPrimitiveType SkVertexModeToGrPrimitiveType(SkVertices::VertexMode mode) {
781 switch (mode) {
782 case SkVertices::kTriangles_VertexMode:
783 return GrPrimitiveType::kTriangles;
784 case SkVertices::kTriangleStrip_VertexMode:
785 return GrPrimitiveType::kTriangleStrip;
786 case SkVertices::kTriangleFan_VertexMode:
787 break;
788 }
789 SK_ABORT("Invalid mode");
790}
791
792std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrRecordingContext* context,
793 GrPaint&& paint,
794 sk_sp<SkVertices> vertices,
795 const SkMatrix& viewMatrix,
796 GrAAType aaType,
797 sk_sp<GrColorSpaceXform> colorSpaceXform,
798 GrPrimitiveType* overridePrimType,
799 const SkRuntimeEffect* effect,
800 const SkM44* localToWorld) {
801 SkASSERT(vertices);
802 GrPrimitiveType primType = overridePrimType
803 ? *overridePrimType
804 : SkVertexModeToGrPrimitiveType(vertices->priv().mode());
805 return GrSimpleMeshDrawOpHelper::FactoryHelper<DrawVerticesOp>(
806 context, std::move(paint), std::move(vertices), primType, aaType,
807 std::move(colorSpaceXform), viewMatrix, effect, localToWorld);
808}
809
810///////////////////////////////////////////////////////////////////////////////////////////////////
811
812#if GR_TEST_UTILS
813
814#include "src/gpu/GrDrawOpTest.h"
815
816static uint32_t seed_vertices(GrPrimitiveType type) {
817 switch (type) {
818 case GrPrimitiveType::kTriangles:
819 case GrPrimitiveType::kTriangleStrip:
820 return 3;
821 case GrPrimitiveType::kPoints:
822 return 1;
823 case GrPrimitiveType::kLines:
824 case GrPrimitiveType::kLineStrip:
825 return 2;
826 case GrPrimitiveType::kPatches:
827 case GrPrimitiveType::kPath:
828 SkASSERT(0);
829 return 0;
830 }
831 SK_ABORT("Incomplete switch\n");
832}
833
834static uint32_t primitive_vertices(GrPrimitiveType type) {
835 switch (type) {
836 case GrPrimitiveType::kTriangles:
837 return 3;
838 case GrPrimitiveType::kLines:
839 return 2;
840 case GrPrimitiveType::kTriangleStrip:
841 case GrPrimitiveType::kPoints:
842 case GrPrimitiveType::kLineStrip:
843 return 1;
844 case GrPrimitiveType::kPatches:
845 case GrPrimitiveType::kPath:
846 SkASSERT(0);
847 return 0;
848 }
849 SK_ABORT("Incomplete switch\n");
850}
851
852static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
853 SkPoint p;
854 p.fX = random->nextRangeScalar(min, max);
855 p.fY = random->nextRangeScalar(min, max);
856 return p;
857}
858
859static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
860 SkRandom* random, SkTArray<SkPoint>* positions,
861 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
862 SkTArray<uint32_t>* colors, bool hasColors,
863 SkTArray<uint16_t>* indices, bool hasIndices) {
864 for (uint32_t v = 0; v < count; v++) {
865 positions->push_back(random_point(random, min, max));
866 if (hasTexCoords) {
867 texCoords->push_back(random_point(random, min, max));
868 }
869 if (hasColors) {
870 colors->push_back(GrRandomColor(random));
871 }
872 if (hasIndices) {
873 SkASSERT(maxVertex <= UINT16_MAX);
874 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
875 }
876 }
877}
878
879GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp) {
880 GrPrimitiveType types[] = {
881 GrPrimitiveType::kTriangles,
882 GrPrimitiveType::kTriangleStrip,
883 GrPrimitiveType::kPoints,
884 GrPrimitiveType::kLines,
885 GrPrimitiveType::kLineStrip
886 };
887 auto type = types[random->nextULessThan(SK_ARRAY_COUNT(types))];
888
889 uint32_t primitiveCount = random->nextRangeU(1, 100);
890
891 // TODO make 'sensible' indexbuffers
892 SkTArray<SkPoint> positions;
893 SkTArray<SkPoint> texCoords;
894 SkTArray<uint32_t> colors;
895 SkTArray<uint16_t> indices;
896
897 bool hasTexCoords = random->nextBool();
898 bool hasIndices = random->nextBool();
899 bool hasColors = random->nextBool();
900
901 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
902
903 static const SkScalar kMinVertExtent = -100.f;
904 static const SkScalar kMaxVertExtent = 100.f;
905 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
906 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
907 hasIndices);
908
909 for (uint32_t i = 1; i < primitiveCount; i++) {
910 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
911 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
912 hasIndices);
913 }
914
915 SkMatrix viewMatrix = GrTest::TestMatrix(random);
916
917 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
918
919 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
920 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
921 texCoords.begin(), colors.begin(),
922 hasIndices ? indices.count() : 0,
923 indices.begin());
924 GrAAType aaType = GrAAType::kNone;
925 if (numSamples > 1 && random->nextBool()) {
926 aaType = GrAAType::kMSAA;
927 }
928 return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), viewMatrix,
929 aaType, std::move(colorSpaceXform), &type, nullptr, nullptr);
930}
931
932#endif
933