blob: bb5b7a5ef22ae80d1092cb077fb4cc722aeb8a8a [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 Mao9a6e42f2018-07-09 14:16:56 -040013#include "SkRectPriv.h"
joshualitt2771b562015-08-07 12:46:26 -070014
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040015static constexpr int kNumFloatsPerSkMatrix = 9;
16
Robert Phillips7c525e62018-06-12 10:11:12 -040017std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
18 GrPaint&& paint,
Brian Salomonc2f42542017-07-12 14:11:22 -040019 sk_sp<SkVertices> vertices,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040020 const SkMatrix bones[],
21 int boneCount,
Brian Salomonc2f42542017-07-12 14:11:22 -040022 const SkMatrix& viewMatrix,
23 GrAAType aaType,
Brian Salomonc2f42542017-07-12 14:11:22 -040024 sk_sp<GrColorSpaceXform> colorSpaceXform,
25 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -050026 SkASSERT(vertices);
Brian Osmanae0c50c2017-05-25 16:56:34 -040027 GrPrimitiveType primType = overridePrimType ? *overridePrimType
28 : SkVertexModeToGrPrimitiveType(vertices->mode());
Robert Phillips7c525e62018-06-12 10:11:12 -040029 return Helper::FactoryHelper<GrDrawVerticesOp>(context, std::move(paint), std::move(vertices),
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040030 bones, boneCount, primType, aaType,
31 std::move(colorSpaceXform), viewMatrix);
Brian Salomon199fb872017-02-06 09:41:10 -050032}
33
Brian Salomonc2f42542017-07-12 14:11:22 -040034GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040035 sk_sp<SkVertices> vertices, const SkMatrix bones[],
36 int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
37 sk_sp<GrColorSpaceXform> colorSpaceXform,
Brian Osmanfa6d8652017-05-31 09:37:27 -040038 const SkMatrix& viewMatrix)
39 : INHERITED(ClassID())
Brian Salomonc2f42542017-07-12 14:11:22 -040040 , fHelper(helperArgs, aaType)
Brian Osmanfa6d8652017-05-31 09:37:27 -040041 , fPrimitiveType(primitiveType)
42 , fColorSpaceXform(std::move(colorSpaceXform)) {
Brian Salomon199fb872017-02-06 09:41:10 -050043 SkASSERT(vertices);
44
45 fVertexCount = vertices->vertexCount();
46 fIndexCount = vertices->indexCount();
Brian Osmanae0c50c2017-05-25 16:56:34 -040047 fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor
48 : ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -070049
bsalomond92b4192016-06-30 07:59:23 -070050 Mesh& mesh = fMeshes.push_back();
51 mesh.fColor = color;
Brian Salomon3f363692017-02-02 21:05:19 -050052 mesh.fViewMatrix = viewMatrix;
Brian Salomon199fb872017-02-06 09:41:10 -050053 mesh.fVertices = std::move(vertices);
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040054 if (bones) {
55 // Copy the bone data over in the format that the GPU would upload.
56 mesh.fBones.reserve(boneCount * kNumFloatsPerSkMatrix);
57 for (int i = 0; i < boneCount; i ++) {
58 const SkMatrix& matrix = bones[i];
59 mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleX));
60 mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewY));
61 mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp0));
62 mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewX));
63 mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleY));
64 mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp1));
65 mesh.fBones.push_back(matrix.get(SkMatrix::kMTransX));
66 mesh.fBones.push_back(matrix.get(SkMatrix::kMTransY));
67 mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp2));
68 }
69 }
Brian Osman8a030552017-05-23 15:03:18 -040070 mesh.fIgnoreTexCoords = false;
71 mesh.fIgnoreColors = false;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040072 mesh.fIgnoreBones = false;
joshualitt2771b562015-08-07 12:46:26 -070073
Brian Salomon199fb872017-02-06 09:41:10 -050074 fFlags = 0;
75 if (mesh.hasPerVertexColors()) {
76 fFlags |= kRequiresPerVertexColors_Flag;
joshualitt2771b562015-08-07 12:46:26 -070077 }
Brian Salomon199fb872017-02-06 09:41:10 -050078 if (mesh.hasExplicitLocalCoords()) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040079 fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
joshualitt2771b562015-08-07 12:46:26 -070080 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040081 if (mesh.hasBones()) {
82 fFlags |= kHasBones_Flag;
83 }
84
85 // Special case for meshes with a world transform but no bone weights.
86 // These will be considered normal vertices draws without bones.
87 if (!mesh.fVertices->hasBones() && boneCount == 1) {
88 mesh.fViewMatrix.preConcat(bones[0]);
89 }
joshualitt2771b562015-08-07 12:46:26 -070090
bsalomon88cf17d2016-07-08 06:40:56 -070091 IsZeroArea zeroArea;
Chris Dalton3809bab2017-06-13 10:55:06 -060092 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
bsalomon88cf17d2016-07-08 06:40:56 -070093 zeroArea = IsZeroArea::kYes;
94 } else {
95 zeroArea = IsZeroArea::kNo;
96 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040097
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040098 if (this->hasBones()) {
99 // We don't know the bounds if there are deformations involved, so attempt to calculate
100 // the maximum possible.
101 SkRect bounds;
102 const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds());
103 for (int i = 1; i < boneCount; i++) {
104 const SkMatrix& matrix = bones[i];
105 bounds.join(matrix.mapRect(originalBounds));
106 }
107
108 this->setTransformedBounds(bounds,
109 mesh.fViewMatrix,
110 HasAABloat::kNo,
111 zeroArea);
112 } else {
113 this->setTransformedBounds(mesh.fVertices->bounds(),
114 mesh.fViewMatrix,
115 HasAABloat::kNo,
116 zeroArea);
117 }
joshualitt2771b562015-08-07 12:46:26 -0700118}
119
Brian Salomonc2f42542017-07-12 14:11:22 -0400120SkString GrDrawVerticesOp::dumpInfo() const {
121 SkString string;
122 string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
123 fMeshes.count(), fVertexCount, fIndexCount);
124 string += fHelper.dumpInfo();
125 string += INHERITED::dumpInfo();
126 return string;
joshualitt2771b562015-08-07 12:46:26 -0700127}
128
Brian Salomonc2f42542017-07-12 14:11:22 -0400129GrDrawOp::FixedFunctionFlags GrDrawVerticesOp::fixedFunctionFlags() const {
130 return fHelper.fixedFunctionFlags();
131}
132
133GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps,
Brian Osman9a725dd2017-09-20 09:53:22 -0400134 const GrAppliedClip* clip,
135 GrPixelConfigIsClamped dstIsClamped) {
Brian Salomonc2f42542017-07-12 14:11:22 -0400136 GrProcessorAnalysisColor gpColor;
137 if (this->requiresPerVertexColors()) {
138 gpColor.setToUnknown();
139 } else {
140 gpColor.setToConstant(fMeshes.front().fColor);
141 }
Brian Osman9a725dd2017-09-20 09:53:22 -0400142 auto result = fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
143 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomonc2f42542017-07-12 14:11:22 -0400144 if (gpColor.isConstant(&fMeshes.front().fColor)) {
145 fMeshes.front().fIgnoreColors = true;
Brian Salomon199fb872017-02-06 09:41:10 -0500146 fFlags &= ~kRequiresPerVertexColors_Flag;
Brian Osmanae0c50c2017-05-25 16:56:34 -0400147 fColorArrayType = ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -0700148 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400149 if (!fHelper.usesLocalCoords()) {
Brian Osman8a030552017-05-23 15:03:18 -0400150 fMeshes[0].fIgnoreTexCoords = true;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400151 fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag;
bsalomon14eaaa62015-09-24 07:01:26 -0700152 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400153 return result;
joshualitt2771b562015-08-07 12:46:26 -0700154}
155
Brian Salomon199fb872017-02-06 09:41:10 -0500156sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400157 bool* hasLocalCoordAttribute,
158 bool* hasBoneAttribute) const {
Brian Salomon199fb872017-02-06 09:41:10 -0500159 using namespace GrDefaultGeoProcFactory;
160 LocalCoords::Type localCoordsType;
Brian Salomonc2f42542017-07-12 14:11:22 -0400161 if (fHelper.usesLocalCoords()) {
Brian Salomon199fb872017-02-06 09:41:10 -0500162 // If we have multiple view matrices we will transform the positions into device space. We
163 // must then also provide untransformed positions as local coords.
164 if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
165 *hasLocalCoordAttribute = true;
166 localCoordsType = LocalCoords::kHasExplicit_Type;
167 } else {
168 *hasLocalCoordAttribute = false;
169 localCoordsType = LocalCoords::kUsePosition_Type;
170 }
171 } else {
172 localCoordsType = LocalCoords::kUnused_Type;
173 *hasLocalCoordAttribute = false;
174 }
175
176 Color color(fMeshes[0].fColor);
177 if (this->requiresPerVertexColors()) {
Brian Osman08a50e02018-06-15 15:06:48 -0400178 if (fColorArrayType == ColorArrayType::kPremulGrColor) {
179 color.fType = Color::kPremulGrColorAttribute_Type;
180 } else {
181 color.fType = Color::kUnpremulSkColorAttribute_Type;
182 color.fColorSpaceXform = fColorSpaceXform;
183 }
Brian Salomon199fb872017-02-06 09:41:10 -0500184 *hasColorAttribute = true;
185 } else {
186 *hasColorAttribute = false;
187 };
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400188
Brian Salomon199fb872017-02-06 09:41:10 -0500189 const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400190
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400191 Bones bones(fMeshes[0].fBones.data(), fMeshes[0].fBones.size() / kNumFloatsPerSkMatrix);
192 *hasBoneAttribute = this->hasBones();
193
194 if (this->hasBones()) {
195 return GrDefaultGeoProcFactory::MakeWithBones(color,
196 Coverage::kSolid_Type,
197 localCoordsType,
198 bones,
199 vm);
200 } else {
201 return GrDefaultGeoProcFactory::Make(color,
202 Coverage::kSolid_Type,
203 localCoordsType,
204 vm);
205 }
Brian Salomon199fb872017-02-06 09:41:10 -0500206}
207
Brian Salomon91326c32017-08-09 16:02:19 -0400208void GrDrawVerticesOp::onPrepareDraws(Target* target) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400209 if (fMeshes[0].fVertices->isVolatile()) {
210 this->drawVolatile(target);
211 } else {
212 this->drawNonVolatile(target);
213 }
214}
215
216void GrDrawVerticesOp::drawVolatile(Target* target) {
Brian Salomon199fb872017-02-06 09:41:10 -0500217 bool hasColorAttribute;
218 bool hasLocalCoordsAttribute;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400219 bool hasBoneAttribute;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400220 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400221 &hasLocalCoordsAttribute,
222 &hasBoneAttribute);
joshualitt2771b562015-08-07 12:46:26 -0700223
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400224 // Calculate the stride.
225 size_t vertexStride = sizeof(SkPoint) +
226 (hasColorAttribute ? sizeof(uint32_t) : 0) +
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400227 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
228 (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
Brian Salomon92be2f72018-06-19 14:33:47 -0400229 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
joshualitt2771b562015-08-07 12:46:26 -0700230
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400231 // Allocate buffers.
232 const GrBuffer* vertexBuffer = nullptr;
233 int firstVertex = 0;
bsalomon14eaaa62015-09-24 07:01:26 -0700234 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700235 if (!verts) {
236 SkDebugf("Could not allocate vertices\n");
237 return;
238 }
239
cdalton397536c2016-03-25 12:15:03 -0700240 const GrBuffer* indexBuffer = nullptr;
joshualitt2771b562015-08-07 12:46:26 -0700241 int firstIndex = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700242 uint16_t* indices = nullptr;
Brian Salomon199fb872017-02-06 09:41:10 -0500243 if (this->isIndexed()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700244 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700245 if (!indices) {
246 SkDebugf("Could not allocate indices\n");
247 return;
248 }
249 }
250
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400251 // Fill the buffers.
252 this->fillBuffers(hasColorAttribute,
253 hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400254 hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400255 vertexStride,
256 verts,
257 indices);
258
259 // Draw the vertices.
260 this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex);
261}
262
263void GrDrawVerticesOp::drawNonVolatile(Target* target) {
264 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
265
266 bool hasColorAttribute;
267 bool hasLocalCoordsAttribute;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400268 bool hasBoneAttribute;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400269 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400270 &hasLocalCoordsAttribute,
271 &hasBoneAttribute);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400272
273 SkASSERT(fMeshes.count() == 1); // Non-volatile meshes should never combine.
274
275 // Get the resource provider.
276 GrResourceProvider* rp = target->resourceProvider();
277
278 // Generate keys for the buffers.
279 GrUniqueKey vertexKey, indexKey;
280 GrUniqueKey::Builder vertexKeyBuilder(&vertexKey, kDomain, 2);
281 GrUniqueKey::Builder indexKeyBuilder(&indexKey, kDomain, 2);
282 vertexKeyBuilder[0] = indexKeyBuilder[0] = fMeshes[0].fVertices->uniqueID();
283 vertexKeyBuilder[1] = 0;
284 indexKeyBuilder[1] = 1;
285 vertexKeyBuilder.finish();
286 indexKeyBuilder.finish();
287
288 // Try to grab data from the cache.
289 sk_sp<GrBuffer> vertexBuffer = rp->findByUniqueKey<GrBuffer>(vertexKey);
290 sk_sp<GrBuffer> indexBuffer = this->isIndexed() ?
291 rp->findByUniqueKey<GrBuffer>(indexKey) :
292 nullptr;
293
294 // Draw using the cached buffers if possible.
295 if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
296 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
297 return;
298 }
299
300 // Calculate the stride.
301 size_t vertexStride = sizeof(SkPoint) +
302 (hasColorAttribute ? sizeof(uint32_t) : 0) +
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400303 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
304 (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400305 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
306
307 // Allocate vertex buffer.
308 vertexBuffer.reset(rp->createBuffer(fVertexCount * vertexStride,
309 kVertex_GrBufferType,
310 kStatic_GrAccessPattern,
311 0));
312 void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
313 if (!verts) {
314 SkDebugf("Could not allocate vertices\n");
315 return;
316 }
317
318 // Allocate index buffer.
319 uint16_t* indices = nullptr;
320 if (this->isIndexed()) {
321 indexBuffer.reset(rp->createBuffer(fIndexCount * sizeof(uint16_t),
322 kIndex_GrBufferType,
323 kStatic_GrAccessPattern,
324 0));
325 indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr;
326 if (!indices) {
327 SkDebugf("Could not allocate indices\n");
328 return;
329 }
330 }
331
332 // Fill the buffers.
333 this->fillBuffers(hasColorAttribute,
334 hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400335 hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400336 vertexStride,
337 verts,
338 indices);
339
340 // Unmap the buffers.
341 vertexBuffer->unmap();
342 if (indexBuffer) {
343 indexBuffer->unmap();
344 }
345
346 // Cache the buffers.
347 rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get());
348 rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
349
350 // Draw the vertices.
351 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
352}
353
354void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
355 bool hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400356 bool hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400357 size_t vertexStride,
358 void* verts,
359 uint16_t* indices) const {
360 int instanceCount = fMeshes.count();
361
362 // Copy data into the buffers.
joshualitt2771b562015-08-07 12:46:26 -0700363 int vertexOffset = 0;
Brian Salomonfab30a32017-02-06 19:06:22 -0500364 // We have a fast case below for uploading the vertex data when the matrix is translate
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400365 // only and there are colors but not local coords. Fast case does not apply when there are bone
366 // transformations.
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400367 bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute && !hasBoneAttribute;
joshualitt2771b562015-08-07 12:46:26 -0700368 for (int i = 0; i < instanceCount; i++) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400369 // Get each mesh.
bsalomond92b4192016-06-30 07:59:23 -0700370 const Mesh& mesh = fMeshes[i];
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400371
372 // Copy data into the index buffer.
bsalomon14eaaa62015-09-24 07:01:26 -0700373 if (indices) {
Brian Salomon199fb872017-02-06 09:41:10 -0500374 int indexCount = mesh.fVertices->indexCount();
Brian Salomonfab30a32017-02-06 19:06:22 -0500375 for (int j = 0; j < indexCount; ++j) {
376 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700377 }
378 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400379
380 // Copy data into the vertex buffer.
Brian Salomon199fb872017-02-06 09:41:10 -0500381 int vertexCount = mesh.fVertices->vertexCount();
382 const SkPoint* positions = mesh.fVertices->positions();
383 const SkColor* colors = mesh.fVertices->colors();
384 const SkPoint* localCoords = mesh.fVertices->texCoords();
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400385 const SkVertices::BoneIndices* boneIndices = mesh.fVertices->boneIndices();
386 const SkVertices::BoneWeights* boneWeights = mesh.fVertices->boneWeights();
Brian Salomonfab30a32017-02-06 19:06:22 -0500387 bool fastMesh = (!this->hasMultipleViewMatrices() ||
388 mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
389 mesh.hasPerVertexColors();
390 if (fastAttrs && fastMesh) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400391 // Fast case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500392 struct V {
393 SkPoint fPos;
394 uint32_t fColor;
395 };
396 SkASSERT(sizeof(V) == vertexStride);
397 V* v = (V*)verts;
398 Sk2f t(0, 0);
Brian Salomon199fb872017-02-06 09:41:10 -0500399 if (this->hasMultipleViewMatrices()) {
Brian Salomonfab30a32017-02-06 19:06:22 -0500400 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
joshualitt2771b562015-08-07 12:46:26 -0700401 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500402 for (int j = 0; j < vertexCount; ++j) {
403 Sk2f p = Sk2f::Load(positions++) + t;
404 p.store(&v[j].fPos);
405 v[j].fColor = colors[j];
406 }
407 verts = v + vertexCount;
408 } else {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400409 // Normal case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500410 static constexpr size_t kColorOffset = sizeof(SkPoint);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400411 size_t offset = kColorOffset;
412 if (hasColorAttribute) {
413 offset += sizeof(uint32_t);
414 }
415 size_t localCoordOffset = offset;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400416 if (hasLocalCoordsAttribute) {
417 offset += sizeof(SkPoint);
418 }
419 size_t boneIndexOffset = offset;
420 if (hasBoneAttribute) {
421 offset += 4 * sizeof(uint32_t);
422 }
423 size_t boneWeightOffset = offset;
Brian Salomonfab30a32017-02-06 19:06:22 -0500424
425 for (int j = 0; j < vertexCount; ++j) {
426 if (this->hasMultipleViewMatrices()) {
427 mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
Brian Salomon3f363692017-02-02 21:05:19 -0500428 } else {
Brian Salomonfab30a32017-02-06 19:06:22 -0500429 *((SkPoint*)verts) = positions[j];
Brian Salomon199fb872017-02-06 09:41:10 -0500430 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500431 if (hasColorAttribute) {
432 if (mesh.hasPerVertexColors()) {
433 *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
434 } else {
435 *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
436 }
Brian Salomon3f363692017-02-02 21:05:19 -0500437 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500438 if (hasLocalCoordsAttribute) {
439 if (mesh.hasExplicitLocalCoords()) {
440 *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
441 } else {
442 *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
443 }
444 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400445 if (hasBoneAttribute) {
446 const SkVertices::BoneIndices& indices = boneIndices[j];
447 const SkVertices::BoneWeights& weights = boneWeights[j];
448 for (int k = 0; k < 4; k++) {
449 size_t indexOffset = boneIndexOffset + sizeof(uint32_t) * k;
450 size_t weightOffset = boneWeightOffset + sizeof(float) * k;
451 *(uint32_t*)((intptr_t)verts + indexOffset) = indices.indices[k];
452 *(float*)((intptr_t)verts + weightOffset) = weights.weights[k];
453 }
454 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500455 verts = (void*)((intptr_t)verts + vertexStride);
joshualitt2771b562015-08-07 12:46:26 -0700456 }
joshualitt2771b562015-08-07 12:46:26 -0700457 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500458 vertexOffset += vertexCount;
joshualitt2771b562015-08-07 12:46:26 -0700459 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400460}
joshualitt2771b562015-08-07 12:46:26 -0700461
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400462void GrDrawVerticesOp::drawVertices(Target* target,
463 GrGeometryProcessor* gp,
464 const GrBuffer* vertexBuffer,
465 int firstVertex,
466 const GrBuffer* indexBuffer,
467 int firstIndex) {
Chris Daltonbca46e22017-05-15 11:03:26 -0600468 GrMesh mesh(this->primitiveType());
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400469 if (this->isIndexed()) {
470 mesh.setIndexed(indexBuffer, fIndexCount,
471 firstIndex, 0, fVertexCount - 1,
Ruiqi Maoc05aa7d2018-07-03 21:18:07 +0000472 GrPrimitiveRestart::kNo);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400473 } else {
474 mesh.setNonIndexedNonInstanced(fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700475 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600476 mesh.setVertexData(vertexBuffer, firstVertex);
Brian Salomon49348902018-06-26 09:12:38 -0400477 auto pipe = fHelper.makePipeline(target);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400478 target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
joshualitt2771b562015-08-07 12:46:26 -0700479}
480
Brian Salomonfc527d22016-12-14 21:07:01 -0500481bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
482 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700483
Brian Salomonc2f42542017-07-12 14:11:22 -0400484 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
joshualitt2771b562015-08-07 12:46:26 -0700485 return false;
486 }
487
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400488 // Meshes with bones cannot be combined because different meshes use different bones, so to
489 // combine them, the matrices would have to be combined, and the bone indices on each vertex
490 // would change, thus making the vertices uncacheable.
491 if (this->hasBones() || that->hasBones()) {
492 return false;
493 }
494
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400495 // Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
496 // then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
497 // that was saved in its vertex buffer, which is not necessarily there anymore.
498 if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
499 return false;
500 }
501
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500502 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
joshualitt2771b562015-08-07 12:46:26 -0700503 return false;
504 }
505
Mike Reedaa9e3322017-03-16 14:38:48 -0400506 if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
joshualitt2771b562015-08-07 12:46:26 -0700507 return false;
508 }
509
Brian Salomon3de0aee2017-01-29 09:34:17 -0500510 if (fColorArrayType != that->fColorArrayType) {
511 return false;
512 }
513
Ben Wagner9bc36fd2018-06-15 14:23:36 -0400514 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
Brian Salomon3f363692017-02-02 21:05:19 -0500515 return false;
516 }
517
Brian Osmanfa6d8652017-05-31 09:37:27 -0400518 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
519 // gamut is determined by the render target context. A mis-match should be impossible.
520 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
521
Brian Salomon199fb872017-02-06 09:41:10 -0500522 // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
523 // with multiple view matrices.
524 fFlags |= that->fFlags;
joshualitt2771b562015-08-07 12:46:26 -0700525
Brian Salomon199fb872017-02-06 09:41:10 -0500526 if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
527 fFlags |= kRequiresPerVertexColors_Flag;
528 }
Brian Salomon3f363692017-02-02 21:05:19 -0500529 // Check whether we are about to acquire a mesh with a different view matrix.
Brian Salomon199fb872017-02-06 09:41:10 -0500530 if (!this->hasMultipleViewMatrices() &&
531 !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
532 fFlags |= kHasMultipleViewMatrices_Flag;
Brian Salomon3f363692017-02-02 21:05:19 -0500533 }
534
bsalomond92b4192016-06-30 07:59:23 -0700535 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700536 fVertexCount += that->fVertexCount;
537 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700538
bsalomon88cf17d2016-07-08 06:40:56 -0700539 this->joinBounds(*that);
joshualitt2771b562015-08-07 12:46:26 -0700540 return true;
541}
542
543///////////////////////////////////////////////////////////////////////////////////////////////////
544
Hal Canary6f6961e2017-01-31 13:50:44 -0500545#if GR_TEST_UTILS
joshualitt2771b562015-08-07 12:46:26 -0700546
Brian Salomon5ec9def2016-12-20 15:34:05 -0500547#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700548
549static uint32_t seed_vertices(GrPrimitiveType type) {
550 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600551 case GrPrimitiveType::kTriangles:
552 case GrPrimitiveType::kTriangleStrip:
joshualitt2771b562015-08-07 12:46:26 -0700553 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600554 case GrPrimitiveType::kPoints:
joshualitt2771b562015-08-07 12:46:26 -0700555 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600556 case GrPrimitiveType::kLines:
557 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700558 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600559 case GrPrimitiveType::kLinesAdjacency:
560 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700561 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400562 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700563 return 0;
564}
565
566static uint32_t primitive_vertices(GrPrimitiveType type) {
567 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600568 case GrPrimitiveType::kTriangles:
joshualitt2771b562015-08-07 12:46:26 -0700569 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600570 case GrPrimitiveType::kLines:
joshualitt2771b562015-08-07 12:46:26 -0700571 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600572 case GrPrimitiveType::kTriangleStrip:
Chris Dalton3809bab2017-06-13 10:55:06 -0600573 case GrPrimitiveType::kPoints:
574 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700575 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600576 case GrPrimitiveType::kLinesAdjacency:
577 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700578 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400579 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700580 return 0;
581}
582
583static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
584 SkPoint p;
585 p.fX = random->nextRangeScalar(min, max);
586 p.fY = random->nextRangeScalar(min, max);
587 return p;
588}
589
590static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500591 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700592 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomon3de0aee2017-01-29 09:34:17 -0500593 SkTArray<uint32_t>* colors, bool hasColors,
594 SkTArray<uint16_t>* indices, bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700595 for (uint32_t v = 0; v < count; v++) {
596 positions->push_back(random_point(random, min, max));
597 if (hasTexCoords) {
598 texCoords->push_back(random_point(random, min, max));
599 }
600 if (hasColors) {
601 colors->push_back(GrRandomColor(random));
602 }
603 if (hasIndices) {
Ben Wagnerb0897652018-06-15 15:37:57 +0000604 SkASSERT(maxVertex <= UINT16_MAX);
joshualitt2771b562015-08-07 12:46:26 -0700605 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
606 }
607 }
608}
609
Brian Salomonc2f42542017-07-12 14:11:22 -0400610GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
Chris Daltonb894c2b2017-06-14 12:39:19 -0600611 GrPrimitiveType type;
612 do {
613 type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
614 } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400615 !context->contextPriv().caps()->shaderCaps()->geometryShaderSupport());
Chris Daltonb894c2b2017-06-14 12:39:19 -0600616
joshualitt2771b562015-08-07 12:46:26 -0700617 uint32_t primitiveCount = random->nextRangeU(1, 100);
618
619 // TODO make 'sensible' indexbuffers
620 SkTArray<SkPoint> positions;
621 SkTArray<SkPoint> texCoords;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500622 SkTArray<uint32_t> colors;
joshualitt2771b562015-08-07 12:46:26 -0700623 SkTArray<uint16_t> indices;
624
625 bool hasTexCoords = random->nextBool();
626 bool hasIndices = random->nextBool();
627 bool hasColors = random->nextBool();
628
629 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
630
631 static const SkScalar kMinVertExtent = -100.f;
632 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500633 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
634 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
635 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700636
637 for (uint32_t i = 1; i < primitiveCount; i++) {
638 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500639 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
640 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700641 }
642
643 SkMatrix viewMatrix = GrTest::TestMatrix(random);
joshualitt2771b562015-08-07 12:46:26 -0700644
Brian Osmanfa6d8652017-05-31 09:37:27 -0400645 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
Brian Osmanae0c50c2017-05-25 16:56:34 -0400646
647 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
648 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
649 texCoords.begin(), colors.begin(),
650 hasIndices ? indices.count() : 0,
651 indices.begin());
Brian Salomonc2f42542017-07-12 14:11:22 -0400652 GrAAType aaType = GrAAType::kNone;
653 if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
654 aaType = GrAAType::kMSAA;
655 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400656 return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400657 viewMatrix, aaType, std::move(colorSpaceXform), &type);
joshualitt2771b562015-08-07 12:46:26 -0700658}
659
660#endif