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 | |
26 | namespace { |
27 | |
28 | enum class ColorArrayType { |
29 | kUnused, |
30 | kPremulGrColor, |
31 | kSkColor, |
32 | }; |
33 | |
34 | enum class LocalCoordsType { |
35 | kUnused, |
36 | kUsePosition, |
37 | kExplicit, |
38 | }; |
39 | |
40 | static 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 | |
51 | static 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 | |
62 | static 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. |
71 | class MarkedMatrices { |
72 | public: |
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 | |
103 | private: |
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 | |
110 | class VerticesGP : public GrGeometryProcessor { |
111 | public: |
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 | |
377 | private: |
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 | |
437 | class DrawVerticesOp final : public GrMeshDrawOp { |
438 | private: |
439 | using Helper = GrSimpleMeshDrawOpHelper; |
440 | |
441 | public: |
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 | |
463 | private: |
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 | |
539 | DrawVerticesOp::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 |
584 | SkString 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 | |
591 | GrDrawOp::FixedFunctionFlags DrawVerticesOp::fixedFunctionFlags() const { |
592 | return fHelper.fixedFunctionFlags(); |
593 | } |
594 | |
595 | GrProcessorSet::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 | |
616 | GrGeometryProcessor* 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 | |
633 | void 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 | |
643 | void 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 | |
727 | void 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 | |
741 | GrOp::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 | |
833 | static 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 | |
845 | std::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 | |
868 | static 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 | |
886 | static 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 | |
904 | static 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 | |
911 | static 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 | |
931 | GR_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 | |