blob: 6abca9d3e8badd8d9d9e0242af1a76eac47104d7 [file] [log] [blame]
joshualitt2771b562015-08-07 12:46:26 -07001/*
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
Brian Salomonfc527d22016-12-14 21:07:01 -05008#include "GrDrawVerticesOp.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -04009#include "GrCaps.h"
joshualitt2771b562015-08-07 12:46:26 -070010#include "GrDefaultGeoProcFactory.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050011#include "GrOpFlushState.h"
Brian Osman3b655982017-03-07 16:58:08 -050012#include "SkGr.h"
Ruiqi Maob6307342018-07-03 11:38:15 -040013#include "SkRectPriv.h"
joshualitt2771b562015-08-07 12:46:26 -070014
Robert Phillips7c525e62018-06-12 10:11:12 -040015std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
16 GrPaint&& paint,
Brian Salomonc2f42542017-07-12 14:11:22 -040017 sk_sp<SkVertices> vertices,
Ruiqi Maob6307342018-07-03 11:38:15 -040018 const SkMatrix bones[],
19 int boneCount,
Brian Salomonc2f42542017-07-12 14:11:22 -040020 const SkMatrix& viewMatrix,
21 GrAAType aaType,
Brian Salomonc2f42542017-07-12 14:11:22 -040022 sk_sp<GrColorSpaceXform> colorSpaceXform,
23 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -050024 SkASSERT(vertices);
Brian Osmanae0c50c2017-05-25 16:56:34 -040025 GrPrimitiveType primType = overridePrimType ? *overridePrimType
26 : SkVertexModeToGrPrimitiveType(vertices->mode());
Robert Phillips7c525e62018-06-12 10:11:12 -040027 return Helper::FactoryHelper<GrDrawVerticesOp>(context, std::move(paint), std::move(vertices),
Ruiqi Maob6307342018-07-03 11:38:15 -040028 bones, boneCount, primType, aaType,
29 std::move(colorSpaceXform), viewMatrix);
Brian Salomon199fb872017-02-06 09:41:10 -050030}
31
Brian Salomonc2f42542017-07-12 14:11:22 -040032GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
Ruiqi Maob6307342018-07-03 11:38:15 -040033 sk_sp<SkVertices> vertices, const SkMatrix bones[],
34 int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
35 sk_sp<GrColorSpaceXform> colorSpaceXform,
Brian Osmanfa6d8652017-05-31 09:37:27 -040036 const SkMatrix& viewMatrix)
37 : INHERITED(ClassID())
Brian Salomonc2f42542017-07-12 14:11:22 -040038 , fHelper(helperArgs, aaType)
Brian Osmanfa6d8652017-05-31 09:37:27 -040039 , fPrimitiveType(primitiveType)
40 , fColorSpaceXform(std::move(colorSpaceXform)) {
Brian Salomon199fb872017-02-06 09:41:10 -050041 SkASSERT(vertices);
42
43 fVertexCount = vertices->vertexCount();
44 fIndexCount = vertices->indexCount();
Brian Osmanae0c50c2017-05-25 16:56:34 -040045 fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor
46 : ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -070047
bsalomond92b4192016-06-30 07:59:23 -070048 Mesh& mesh = fMeshes.push_back();
49 mesh.fColor = color;
Brian Salomon3f363692017-02-02 21:05:19 -050050 mesh.fViewMatrix = viewMatrix;
Brian Salomon199fb872017-02-06 09:41:10 -050051 mesh.fVertices = std::move(vertices);
Ruiqi Maob6307342018-07-03 11:38:15 -040052 if (bones) {
53 mesh.fBones.assign(bones, bones + boneCount);
54 }
Brian Osman8a030552017-05-23 15:03:18 -040055 mesh.fIgnoreTexCoords = false;
56 mesh.fIgnoreColors = false;
Ruiqi Maob6307342018-07-03 11:38:15 -040057 mesh.fIgnoreBones = false;
joshualitt2771b562015-08-07 12:46:26 -070058
Brian Salomon199fb872017-02-06 09:41:10 -050059 fFlags = 0;
60 if (mesh.hasPerVertexColors()) {
61 fFlags |= kRequiresPerVertexColors_Flag;
joshualitt2771b562015-08-07 12:46:26 -070062 }
Brian Salomon199fb872017-02-06 09:41:10 -050063 if (mesh.hasExplicitLocalCoords()) {
Ruiqi Maob6307342018-07-03 11:38:15 -040064 fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
65 }
66 if (mesh.hasBones()) {
67 fFlags |= kHasBones_Flag;
68 }
69
70 // Special case for meshes with a world transform but no bone weights.
71 // These will be considered normal vertices draws without bones.
72 if (!mesh.fVertices->hasBones() && boneCount == 1) {
73 mesh.fViewMatrix.preConcat(bones[0]);
joshualitt2771b562015-08-07 12:46:26 -070074 }
75
bsalomon88cf17d2016-07-08 06:40:56 -070076 IsZeroArea zeroArea;
Chris Dalton3809bab2017-06-13 10:55:06 -060077 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
bsalomon88cf17d2016-07-08 06:40:56 -070078 zeroArea = IsZeroArea::kYes;
79 } else {
80 zeroArea = IsZeroArea::kNo;
81 }
Ruiqi Maob6307342018-07-03 11:38:15 -040082
83 if (this->hasBones()) {
84 // We don't know the bounds if there are deformations involved, so attempt to calculate
85 // the maximum possible.
86 SkRect bounds;
87 const SkRect& originalBounds = bones[0].mapRect(mesh.fVertices->bounds());
88 for (int i = 1; i < boneCount; i++) {
89 const SkMatrix& matrix = bones[i];
90 bounds.join(matrix.mapRect(originalBounds));
91 }
92
93 this->setTransformedBounds(bounds,
94 mesh.fViewMatrix,
95 HasAABloat::kNo,
96 zeroArea);
97 } else {
98 this->setTransformedBounds(mesh.fVertices->bounds(),
99 mesh.fViewMatrix,
100 HasAABloat::kNo,
101 zeroArea);
102 }
joshualitt2771b562015-08-07 12:46:26 -0700103}
104
Brian Salomonc2f42542017-07-12 14:11:22 -0400105SkString GrDrawVerticesOp::dumpInfo() const {
106 SkString string;
107 string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
108 fMeshes.count(), fVertexCount, fIndexCount);
109 string += fHelper.dumpInfo();
110 string += INHERITED::dumpInfo();
111 return string;
joshualitt2771b562015-08-07 12:46:26 -0700112}
113
Brian Salomonc2f42542017-07-12 14:11:22 -0400114GrDrawOp::FixedFunctionFlags GrDrawVerticesOp::fixedFunctionFlags() const {
115 return fHelper.fixedFunctionFlags();
116}
117
118GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps,
Brian Osman9a725dd2017-09-20 09:53:22 -0400119 const GrAppliedClip* clip,
120 GrPixelConfigIsClamped dstIsClamped) {
Brian Salomonc2f42542017-07-12 14:11:22 -0400121 GrProcessorAnalysisColor gpColor;
122 if (this->requiresPerVertexColors()) {
123 gpColor.setToUnknown();
124 } else {
125 gpColor.setToConstant(fMeshes.front().fColor);
126 }
Brian Osman9a725dd2017-09-20 09:53:22 -0400127 auto result = fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
128 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomonc2f42542017-07-12 14:11:22 -0400129 if (gpColor.isConstant(&fMeshes.front().fColor)) {
130 fMeshes.front().fIgnoreColors = true;
Brian Salomon199fb872017-02-06 09:41:10 -0500131 fFlags &= ~kRequiresPerVertexColors_Flag;
Brian Osmanae0c50c2017-05-25 16:56:34 -0400132 fColorArrayType = ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -0700133 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400134 if (!fHelper.usesLocalCoords()) {
Brian Osman8a030552017-05-23 15:03:18 -0400135 fMeshes[0].fIgnoreTexCoords = true;
Ruiqi Maob6307342018-07-03 11:38:15 -0400136 fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag;
bsalomon14eaaa62015-09-24 07:01:26 -0700137 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400138 return result;
joshualitt2771b562015-08-07 12:46:26 -0700139}
140
Brian Salomon199fb872017-02-06 09:41:10 -0500141sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
Ruiqi Maob6307342018-07-03 11:38:15 -0400142 bool* hasLocalCoordAttribute,
143 bool* hasBoneAttribute) const {
Brian Salomon199fb872017-02-06 09:41:10 -0500144 using namespace GrDefaultGeoProcFactory;
145 LocalCoords::Type localCoordsType;
Brian Salomonc2f42542017-07-12 14:11:22 -0400146 if (fHelper.usesLocalCoords()) {
Brian Salomon199fb872017-02-06 09:41:10 -0500147 // If we have multiple view matrices we will transform the positions into device space. We
148 // must then also provide untransformed positions as local coords.
149 if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
150 *hasLocalCoordAttribute = true;
151 localCoordsType = LocalCoords::kHasExplicit_Type;
152 } else {
153 *hasLocalCoordAttribute = false;
154 localCoordsType = LocalCoords::kUsePosition_Type;
155 }
156 } else {
157 localCoordsType = LocalCoords::kUnused_Type;
158 *hasLocalCoordAttribute = false;
159 }
160
161 Color color(fMeshes[0].fColor);
162 if (this->requiresPerVertexColors()) {
Brian Osman08a50e02018-06-15 15:06:48 -0400163 if (fColorArrayType == ColorArrayType::kPremulGrColor) {
164 color.fType = Color::kPremulGrColorAttribute_Type;
165 } else {
166 color.fType = Color::kUnpremulSkColorAttribute_Type;
167 color.fColorSpaceXform = fColorSpaceXform;
168 }
Brian Salomon199fb872017-02-06 09:41:10 -0500169 *hasColorAttribute = true;
170 } else {
171 *hasColorAttribute = false;
172 };
Ruiqi Maob6307342018-07-03 11:38:15 -0400173
Brian Salomon199fb872017-02-06 09:41:10 -0500174 const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
Ruiqi Maob6307342018-07-03 11:38:15 -0400175
176 Bones bones(fMeshes[0].fBones.data(), fMeshes[0].fBones.size());
177 *hasBoneAttribute = this->hasBones();
178
179 if (this->hasBones()) {
180 return GrDefaultGeoProcFactory::MakeWithBones(color,
181 Coverage::kSolid_Type,
182 localCoordsType,
183 bones,
184 vm);
185 } else {
186 return GrDefaultGeoProcFactory::Make(color,
187 Coverage::kSolid_Type,
188 localCoordsType,
189 vm);
190 }
Brian Salomon199fb872017-02-06 09:41:10 -0500191}
192
Brian Salomon91326c32017-08-09 16:02:19 -0400193void GrDrawVerticesOp::onPrepareDraws(Target* target) {
Ruiqi Maob6307342018-07-03 11:38:15 -0400194 if (fMeshes[0].fVertices->isVolatile()) {
195 this->drawVolatile(target);
196 } else {
197 this->drawNonVolatile(target);
198 }
199}
200
201void GrDrawVerticesOp::drawVolatile(Target* target) {
Brian Salomon199fb872017-02-06 09:41:10 -0500202 bool hasColorAttribute;
203 bool hasLocalCoordsAttribute;
Ruiqi Maob6307342018-07-03 11:38:15 -0400204 bool hasBoneAttribute;
205 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
206 &hasLocalCoordsAttribute,
207 &hasBoneAttribute);
joshualitt2771b562015-08-07 12:46:26 -0700208
Ruiqi Maob6307342018-07-03 11:38:15 -0400209 // Calculate the stride.
210 size_t vertexStride = sizeof(SkPoint) +
211 (hasColorAttribute ? sizeof(uint32_t) : 0) +
212 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
213 (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
Brian Salomon92be2f72018-06-19 14:33:47 -0400214 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
joshualitt2771b562015-08-07 12:46:26 -0700215
Ruiqi Maob6307342018-07-03 11:38:15 -0400216 // Allocate buffers.
217 const GrBuffer* vertexBuffer = nullptr;
218 int firstVertex = 0;
bsalomon14eaaa62015-09-24 07:01:26 -0700219 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700220 if (!verts) {
221 SkDebugf("Could not allocate vertices\n");
222 return;
223 }
224
cdalton397536c2016-03-25 12:15:03 -0700225 const GrBuffer* indexBuffer = nullptr;
joshualitt2771b562015-08-07 12:46:26 -0700226 int firstIndex = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700227 uint16_t* indices = nullptr;
Brian Salomon199fb872017-02-06 09:41:10 -0500228 if (this->isIndexed()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700229 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700230 if (!indices) {
231 SkDebugf("Could not allocate indices\n");
232 return;
233 }
234 }
235
Ruiqi Maob6307342018-07-03 11:38:15 -0400236 // Fill the buffers.
237 this->fillBuffers(hasColorAttribute,
238 hasLocalCoordsAttribute,
239 hasBoneAttribute,
240 vertexStride,
241 verts,
242 indices);
243
244 // Draw the vertices.
245 this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex);
246}
247
248void GrDrawVerticesOp::drawNonVolatile(Target* target) {
249 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
250
251 bool hasColorAttribute;
252 bool hasLocalCoordsAttribute;
253 bool hasBoneAttribute;
254 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
255 &hasLocalCoordsAttribute,
256 &hasBoneAttribute);
257
258 int instanceCount = fMeshes.count();
259 SkASSERT(instanceCount == 1); // Non-volatile meshes should never combine.
260
261 // Get the resource provider.
262 GrResourceProvider* rp = target->resourceProvider();
263
264 // Generate keys for the buffers.
265 GrUniqueKey vertexKey, indexKey;
266 GrUniqueKey::Builder vertexKeyBuilder(&vertexKey, kDomain, instanceCount + 1);
267 GrUniqueKey::Builder indexKeyBuilder(&indexKey, kDomain, instanceCount + 1);
268 for (int i = 0; i < instanceCount; i ++) {
269 vertexKeyBuilder[i] = indexKeyBuilder[i] = fMeshes[i].fVertices->uniqueID();
270 }
271 vertexKeyBuilder[instanceCount] = 0;
272 indexKeyBuilder[instanceCount] = 1;
273 vertexKeyBuilder.finish();
274 indexKeyBuilder.finish();
275
276 // Try to grab data from the cache.
277 sk_sp<GrBuffer> vertexBuffer = rp->findByUniqueKey<GrBuffer>(vertexKey);
278 sk_sp<GrBuffer> indexBuffer = rp->findByUniqueKey<GrBuffer>(indexKey);
279
280 // Draw using the cached buffers if possible.
281 if (vertexBuffer) {
282 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
283 return;
284 }
285
286 // Calculate the stride.
287 size_t vertexStride = sizeof(SkPoint) +
288 (hasColorAttribute ? sizeof(uint32_t) : 0) +
289 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
290 (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
291 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
292
293 // Allocate vertex buffer.
294 vertexBuffer.reset(rp->createBuffer(fVertexCount * vertexStride,
295 kVertex_GrBufferType,
296 kStatic_GrAccessPattern,
297 0));
298 void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
299 if (!verts) {
300 SkDebugf("Could not allocate vertices\n");
301 return;
302 }
303
304 // Allocate index buffer.
305 uint16_t* indices = nullptr;
306 if (this->isIndexed()) {
307 indexBuffer.reset(rp->createBuffer(fIndexCount * sizeof(uint16_t),
308 kIndex_GrBufferType,
309 kStatic_GrAccessPattern,
310 0));
311 indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr;
312 if (!indices) {
313 SkDebugf("Could not allocate indices\n");
314 return;
315 }
316 }
317
318 // Fill the buffers.
319 this->fillBuffers(hasColorAttribute,
320 hasLocalCoordsAttribute,
321 hasBoneAttribute,
322 vertexStride,
323 verts,
324 indices);
325
326 // Unmap the buffers.
327 vertexBuffer->unmap();
328 if (indexBuffer) {
329 indexBuffer->unmap();
330 }
331
332 // Cache the buffers.
333 rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get());
334 rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
335
336 // Draw the vertices.
337 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
338}
339
340void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
341 bool hasLocalCoordsAttribute,
342 bool hasBoneAttribute,
343 size_t vertexStride,
344 void* verts,
345 uint16_t* indices) const {
346 int instanceCount = fMeshes.count();
347
348 // Copy data into the buffers.
joshualitt2771b562015-08-07 12:46:26 -0700349 int vertexOffset = 0;
Brian Salomonfab30a32017-02-06 19:06:22 -0500350 // We have a fast case below for uploading the vertex data when the matrix is translate
Ruiqi Maob6307342018-07-03 11:38:15 -0400351 // only and there are colors but not local coords. Fast case does not apply when there are bone
352 // transformations.
353 bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute && !hasBoneAttribute;
joshualitt2771b562015-08-07 12:46:26 -0700354 for (int i = 0; i < instanceCount; i++) {
Ruiqi Maob6307342018-07-03 11:38:15 -0400355 // Get each mesh.
bsalomond92b4192016-06-30 07:59:23 -0700356 const Mesh& mesh = fMeshes[i];
Ruiqi Maob6307342018-07-03 11:38:15 -0400357
358 // Copy data into the index buffer.
bsalomon14eaaa62015-09-24 07:01:26 -0700359 if (indices) {
Brian Salomon199fb872017-02-06 09:41:10 -0500360 int indexCount = mesh.fVertices->indexCount();
Brian Salomonfab30a32017-02-06 19:06:22 -0500361 for (int j = 0; j < indexCount; ++j) {
362 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700363 }
364 }
Ruiqi Maob6307342018-07-03 11:38:15 -0400365
366 // Copy data into the vertex buffer.
Brian Salomon199fb872017-02-06 09:41:10 -0500367 int vertexCount = mesh.fVertices->vertexCount();
368 const SkPoint* positions = mesh.fVertices->positions();
369 const SkColor* colors = mesh.fVertices->colors();
370 const SkPoint* localCoords = mesh.fVertices->texCoords();
Ruiqi Maob6307342018-07-03 11:38:15 -0400371 const SkVertices::BoneIndices* boneIndices = mesh.fVertices->boneIndices();
372 const SkVertices::BoneWeights* boneWeights = mesh.fVertices->boneWeights();
Brian Salomonfab30a32017-02-06 19:06:22 -0500373 bool fastMesh = (!this->hasMultipleViewMatrices() ||
374 mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
375 mesh.hasPerVertexColors();
376 if (fastAttrs && fastMesh) {
Ruiqi Maob6307342018-07-03 11:38:15 -0400377 // Fast case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500378 struct V {
379 SkPoint fPos;
380 uint32_t fColor;
381 };
382 SkASSERT(sizeof(V) == vertexStride);
383 V* v = (V*)verts;
384 Sk2f t(0, 0);
Brian Salomon199fb872017-02-06 09:41:10 -0500385 if (this->hasMultipleViewMatrices()) {
Brian Salomonfab30a32017-02-06 19:06:22 -0500386 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
joshualitt2771b562015-08-07 12:46:26 -0700387 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500388 for (int j = 0; j < vertexCount; ++j) {
389 Sk2f p = Sk2f::Load(positions++) + t;
390 p.store(&v[j].fPos);
391 v[j].fColor = colors[j];
392 }
393 verts = v + vertexCount;
394 } else {
Ruiqi Maob6307342018-07-03 11:38:15 -0400395 // Normal case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500396 static constexpr size_t kColorOffset = sizeof(SkPoint);
Ruiqi Maob6307342018-07-03 11:38:15 -0400397 size_t offset = kColorOffset;
398 if (hasColorAttribute) {
399 offset += sizeof(uint32_t);
400 }
401 size_t localCoordOffset = offset;
402 if (hasLocalCoordsAttribute) {
403 offset += sizeof(SkPoint);
404 }
405 size_t boneIndexOffset = offset;
406 offset += 4 * sizeof(uint32_t);
407 size_t boneWeightOffset = offset;
Brian Salomonfab30a32017-02-06 19:06:22 -0500408
409 for (int j = 0; j < vertexCount; ++j) {
410 if (this->hasMultipleViewMatrices()) {
411 mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
Brian Salomon3f363692017-02-02 21:05:19 -0500412 } else {
Brian Salomonfab30a32017-02-06 19:06:22 -0500413 *((SkPoint*)verts) = positions[j];
Brian Salomon199fb872017-02-06 09:41:10 -0500414 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500415 if (hasColorAttribute) {
416 if (mesh.hasPerVertexColors()) {
417 *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
418 } else {
419 *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
420 }
Brian Salomon3f363692017-02-02 21:05:19 -0500421 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500422 if (hasLocalCoordsAttribute) {
423 if (mesh.hasExplicitLocalCoords()) {
424 *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
425 } else {
426 *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
427 }
428 }
Ruiqi Maob6307342018-07-03 11:38:15 -0400429 if (hasBoneAttribute) {
430 const SkVertices::BoneIndices& indices = boneIndices[j];
431 const SkVertices::BoneWeights& weights = boneWeights[j];
432 for (int k = 0; k < 4; k++) {
433 size_t indexOffset = boneIndexOffset + sizeof(uint32_t) * k;
434 size_t weightOffset = boneWeightOffset + sizeof(float) * k;
435 *(uint32_t*)((intptr_t)verts + indexOffset) = indices.indices[k];
436 *(float*)((intptr_t)verts + weightOffset) = weights.weights[k];
437 }
438 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500439 verts = (void*)((intptr_t)verts + vertexStride);
joshualitt2771b562015-08-07 12:46:26 -0700440 }
joshualitt2771b562015-08-07 12:46:26 -0700441 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500442 vertexOffset += vertexCount;
joshualitt2771b562015-08-07 12:46:26 -0700443 }
Ruiqi Maob6307342018-07-03 11:38:15 -0400444}
joshualitt2771b562015-08-07 12:46:26 -0700445
Ruiqi Maob6307342018-07-03 11:38:15 -0400446void GrDrawVerticesOp::drawVertices(Target* target,
447 GrGeometryProcessor* gp,
448 const GrBuffer* vertexBuffer,
449 int firstVertex,
450 const GrBuffer* indexBuffer,
451 int firstIndex) {
Chris Daltonbca46e22017-05-15 11:03:26 -0600452 GrMesh mesh(this->primitiveType());
Ruiqi Maob6307342018-07-03 11:38:15 -0400453 if (this->isIndexed()) {
454 mesh.setIndexed(indexBuffer, fIndexCount,
455 firstIndex, 0, fVertexCount - 1,
Brian Salomon802cb312018-06-08 18:05:20 -0400456 GrPrimitiveRestart::kNo);
Ruiqi Maob6307342018-07-03 11:38:15 -0400457 } else {
458 mesh.setNonIndexedNonInstanced(fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700459 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600460 mesh.setVertexData(vertexBuffer, firstVertex);
Brian Salomon49348902018-06-26 09:12:38 -0400461 auto pipe = fHelper.makePipeline(target);
Ruiqi Maob6307342018-07-03 11:38:15 -0400462 target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
joshualitt2771b562015-08-07 12:46:26 -0700463}
464
Brian Salomonfc527d22016-12-14 21:07:01 -0500465bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
466 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700467
Brian Salomonc2f42542017-07-12 14:11:22 -0400468 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
joshualitt2771b562015-08-07 12:46:26 -0700469 return false;
470 }
471
Ruiqi Maob6307342018-07-03 11:38:15 -0400472 // Meshes with bones cannot be combined because different meshes use different bones, so to
473 // combine them, the matrices would have to be combined, and the bone indices on each vertex
474 // would change, thus making the vertices uncacheable.
475 if (this->hasBones() || that->hasBones()) {
476 return false;
477 }
478
479 // Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
480 // then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
481 // that was saved in its vertex buffer, which is not necessarily there anymore.
482 if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
483 return false;
484 }
485
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500486 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
joshualitt2771b562015-08-07 12:46:26 -0700487 return false;
488 }
489
Mike Reedaa9e3322017-03-16 14:38:48 -0400490 if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
joshualitt2771b562015-08-07 12:46:26 -0700491 return false;
492 }
493
Brian Salomon3de0aee2017-01-29 09:34:17 -0500494 if (fColorArrayType != that->fColorArrayType) {
495 return false;
496 }
497
Ben Wagner9bc36fd2018-06-15 14:23:36 -0400498 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
Brian Salomon3f363692017-02-02 21:05:19 -0500499 return false;
500 }
501
Brian Osmanfa6d8652017-05-31 09:37:27 -0400502 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
503 // gamut is determined by the render target context. A mis-match should be impossible.
504 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
505
Brian Salomon199fb872017-02-06 09:41:10 -0500506 // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
507 // with multiple view matrices.
508 fFlags |= that->fFlags;
joshualitt2771b562015-08-07 12:46:26 -0700509
Brian Salomon199fb872017-02-06 09:41:10 -0500510 if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
511 fFlags |= kRequiresPerVertexColors_Flag;
512 }
Brian Salomon3f363692017-02-02 21:05:19 -0500513 // Check whether we are about to acquire a mesh with a different view matrix.
Brian Salomon199fb872017-02-06 09:41:10 -0500514 if (!this->hasMultipleViewMatrices() &&
515 !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
516 fFlags |= kHasMultipleViewMatrices_Flag;
Brian Salomon3f363692017-02-02 21:05:19 -0500517 }
518
bsalomond92b4192016-06-30 07:59:23 -0700519 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700520 fVertexCount += that->fVertexCount;
521 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700522
bsalomon88cf17d2016-07-08 06:40:56 -0700523 this->joinBounds(*that);
joshualitt2771b562015-08-07 12:46:26 -0700524 return true;
525}
526
527///////////////////////////////////////////////////////////////////////////////////////////////////
528
Hal Canary6f6961e2017-01-31 13:50:44 -0500529#if GR_TEST_UTILS
joshualitt2771b562015-08-07 12:46:26 -0700530
Brian Salomon5ec9def2016-12-20 15:34:05 -0500531#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700532
533static uint32_t seed_vertices(GrPrimitiveType type) {
534 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600535 case GrPrimitiveType::kTriangles:
536 case GrPrimitiveType::kTriangleStrip:
joshualitt2771b562015-08-07 12:46:26 -0700537 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600538 case GrPrimitiveType::kPoints:
joshualitt2771b562015-08-07 12:46:26 -0700539 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600540 case GrPrimitiveType::kLines:
541 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700542 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600543 case GrPrimitiveType::kLinesAdjacency:
544 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700545 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400546 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700547 return 0;
548}
549
550static uint32_t primitive_vertices(GrPrimitiveType type) {
551 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600552 case GrPrimitiveType::kTriangles:
joshualitt2771b562015-08-07 12:46:26 -0700553 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600554 case GrPrimitiveType::kLines:
joshualitt2771b562015-08-07 12:46:26 -0700555 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600556 case GrPrimitiveType::kTriangleStrip:
Chris Dalton3809bab2017-06-13 10:55:06 -0600557 case GrPrimitiveType::kPoints:
558 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700559 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600560 case GrPrimitiveType::kLinesAdjacency:
561 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700562 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400563 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700564 return 0;
565}
566
567static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
568 SkPoint p;
569 p.fX = random->nextRangeScalar(min, max);
570 p.fY = random->nextRangeScalar(min, max);
571 return p;
572}
573
574static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500575 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700576 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomon3de0aee2017-01-29 09:34:17 -0500577 SkTArray<uint32_t>* colors, bool hasColors,
578 SkTArray<uint16_t>* indices, bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700579 for (uint32_t v = 0; v < count; v++) {
580 positions->push_back(random_point(random, min, max));
581 if (hasTexCoords) {
582 texCoords->push_back(random_point(random, min, max));
583 }
584 if (hasColors) {
585 colors->push_back(GrRandomColor(random));
586 }
587 if (hasIndices) {
Ben Wagnerb0897652018-06-15 15:37:57 +0000588 SkASSERT(maxVertex <= UINT16_MAX);
joshualitt2771b562015-08-07 12:46:26 -0700589 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
590 }
591 }
592}
593
Brian Salomonc2f42542017-07-12 14:11:22 -0400594GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
Chris Daltonb894c2b2017-06-14 12:39:19 -0600595 GrPrimitiveType type;
596 do {
597 type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
598 } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400599 !context->contextPriv().caps()->shaderCaps()->geometryShaderSupport());
Chris Daltonb894c2b2017-06-14 12:39:19 -0600600
joshualitt2771b562015-08-07 12:46:26 -0700601 uint32_t primitiveCount = random->nextRangeU(1, 100);
602
603 // TODO make 'sensible' indexbuffers
604 SkTArray<SkPoint> positions;
605 SkTArray<SkPoint> texCoords;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500606 SkTArray<uint32_t> colors;
joshualitt2771b562015-08-07 12:46:26 -0700607 SkTArray<uint16_t> indices;
608
609 bool hasTexCoords = random->nextBool();
610 bool hasIndices = random->nextBool();
611 bool hasColors = random->nextBool();
612
613 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
614
615 static const SkScalar kMinVertExtent = -100.f;
616 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500617 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
618 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
619 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700620
621 for (uint32_t i = 1; i < primitiveCount; i++) {
622 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500623 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
624 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700625 }
626
627 SkMatrix viewMatrix = GrTest::TestMatrix(random);
joshualitt2771b562015-08-07 12:46:26 -0700628
Brian Osmanfa6d8652017-05-31 09:37:27 -0400629 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
Brian Osmanae0c50c2017-05-25 16:56:34 -0400630
631 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
632 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
633 texCoords.begin(), colors.begin(),
634 hasIndices ? indices.count() : 0,
635 indices.begin());
Brian Salomonc2f42542017-07-12 14:11:22 -0400636 GrAAType aaType = GrAAType::kNone;
637 if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
638 aaType = GrAAType::kMSAA;
639 }
Ruiqi Maob6307342018-07-03 11:38:15 -0400640 return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0,
641 viewMatrix, aaType, std::move(colorSpaceXform), &type);
joshualitt2771b562015-08-07 12:46:26 -0700642}
643
644#endif