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