blob: 7cfb3a2efa836f4537baf2c7e32f8165ceb22716 [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
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,
18 const SkMatrix& viewMatrix,
19 GrAAType aaType,
Brian Salomonc2f42542017-07-12 14:11:22 -040020 sk_sp<GrColorSpaceXform> colorSpaceXform,
21 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -050022 SkASSERT(vertices);
Brian Osmanae0c50c2017-05-25 16:56:34 -040023 GrPrimitiveType primType = overridePrimType ? *overridePrimType
24 : SkVertexModeToGrPrimitiveType(vertices->mode());
Robert Phillips7c525e62018-06-12 10:11:12 -040025 return Helper::FactoryHelper<GrDrawVerticesOp>(context, std::move(paint), std::move(vertices),
Joe Gregorio383c9bb2018-07-10 20:35:19 +000026 primType, aaType, std::move(colorSpaceXform),
27 viewMatrix);
Brian Salomon199fb872017-02-06 09:41:10 -050028}
29
Brian Salomonc2f42542017-07-12 14:11:22 -040030GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
Joe Gregorio383c9bb2018-07-10 20:35:19 +000031 sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType,
32 GrAAType aaType, sk_sp<GrColorSpaceXform> colorSpaceXform,
Brian Osmanfa6d8652017-05-31 09:37:27 -040033 const SkMatrix& viewMatrix)
34 : INHERITED(ClassID())
Brian Salomonc2f42542017-07-12 14:11:22 -040035 , fHelper(helperArgs, aaType)
Brian Osmanfa6d8652017-05-31 09:37:27 -040036 , fPrimitiveType(primitiveType)
37 , fColorSpaceXform(std::move(colorSpaceXform)) {
Brian Salomon199fb872017-02-06 09:41:10 -050038 SkASSERT(vertices);
39
40 fVertexCount = vertices->vertexCount();
41 fIndexCount = vertices->indexCount();
Brian Osmanae0c50c2017-05-25 16:56:34 -040042 fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor
43 : ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -070044
bsalomond92b4192016-06-30 07:59:23 -070045 Mesh& mesh = fMeshes.push_back();
46 mesh.fColor = color;
Brian Salomon3f363692017-02-02 21:05:19 -050047 mesh.fViewMatrix = viewMatrix;
Brian Salomon199fb872017-02-06 09:41:10 -050048 mesh.fVertices = std::move(vertices);
Brian Osman8a030552017-05-23 15:03:18 -040049 mesh.fIgnoreTexCoords = false;
50 mesh.fIgnoreColors = false;
joshualitt2771b562015-08-07 12:46:26 -070051
Brian Salomon199fb872017-02-06 09:41:10 -050052 fFlags = 0;
53 if (mesh.hasPerVertexColors()) {
54 fFlags |= kRequiresPerVertexColors_Flag;
joshualitt2771b562015-08-07 12:46:26 -070055 }
Brian Salomon199fb872017-02-06 09:41:10 -050056 if (mesh.hasExplicitLocalCoords()) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040057 fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
joshualitt2771b562015-08-07 12:46:26 -070058 }
59
bsalomon88cf17d2016-07-08 06:40:56 -070060 IsZeroArea zeroArea;
Chris Dalton3809bab2017-06-13 10:55:06 -060061 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
bsalomon88cf17d2016-07-08 06:40:56 -070062 zeroArea = IsZeroArea::kYes;
63 } else {
64 zeroArea = IsZeroArea::kNo;
65 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040066
Joe Gregorio383c9bb2018-07-10 20:35:19 +000067 this->setTransformedBounds(mesh.fVertices->bounds(),
68 mesh.fViewMatrix,
69 HasAABloat::kNo,
70 zeroArea);
joshualitt2771b562015-08-07 12:46:26 -070071}
72
Brian Salomonc2f42542017-07-12 14:11:22 -040073SkString GrDrawVerticesOp::dumpInfo() const {
74 SkString string;
75 string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
76 fMeshes.count(), fVertexCount, fIndexCount);
77 string += fHelper.dumpInfo();
78 string += INHERITED::dumpInfo();
79 return string;
joshualitt2771b562015-08-07 12:46:26 -070080}
81
Brian Salomonc2f42542017-07-12 14:11:22 -040082GrDrawOp::FixedFunctionFlags GrDrawVerticesOp::fixedFunctionFlags() const {
83 return fHelper.fixedFunctionFlags();
84}
85
86GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps,
Brian Osman9a725dd2017-09-20 09:53:22 -040087 const GrAppliedClip* clip,
88 GrPixelConfigIsClamped dstIsClamped) {
Brian Salomonc2f42542017-07-12 14:11:22 -040089 GrProcessorAnalysisColor gpColor;
90 if (this->requiresPerVertexColors()) {
91 gpColor.setToUnknown();
92 } else {
93 gpColor.setToConstant(fMeshes.front().fColor);
94 }
Brian Osman9a725dd2017-09-20 09:53:22 -040095 auto result = fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
96 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomonc2f42542017-07-12 14:11:22 -040097 if (gpColor.isConstant(&fMeshes.front().fColor)) {
98 fMeshes.front().fIgnoreColors = true;
Brian Salomon199fb872017-02-06 09:41:10 -050099 fFlags &= ~kRequiresPerVertexColors_Flag;
Brian Osmanae0c50c2017-05-25 16:56:34 -0400100 fColorArrayType = ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -0700101 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400102 if (!fHelper.usesLocalCoords()) {
Brian Osman8a030552017-05-23 15:03:18 -0400103 fMeshes[0].fIgnoreTexCoords = true;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400104 fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag;
bsalomon14eaaa62015-09-24 07:01:26 -0700105 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400106 return result;
joshualitt2771b562015-08-07 12:46:26 -0700107}
108
Brian Salomon199fb872017-02-06 09:41:10 -0500109sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000110 bool* hasLocalCoordAttribute) const {
Brian Salomon199fb872017-02-06 09:41:10 -0500111 using namespace GrDefaultGeoProcFactory;
112 LocalCoords::Type localCoordsType;
Brian Salomonc2f42542017-07-12 14:11:22 -0400113 if (fHelper.usesLocalCoords()) {
Brian Salomon199fb872017-02-06 09:41:10 -0500114 // If we have multiple view matrices we will transform the positions into device space. We
115 // must then also provide untransformed positions as local coords.
116 if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
117 *hasLocalCoordAttribute = true;
118 localCoordsType = LocalCoords::kHasExplicit_Type;
119 } else {
120 *hasLocalCoordAttribute = false;
121 localCoordsType = LocalCoords::kUsePosition_Type;
122 }
123 } else {
124 localCoordsType = LocalCoords::kUnused_Type;
125 *hasLocalCoordAttribute = false;
126 }
127
128 Color color(fMeshes[0].fColor);
129 if (this->requiresPerVertexColors()) {
Brian Osman08a50e02018-06-15 15:06:48 -0400130 if (fColorArrayType == ColorArrayType::kPremulGrColor) {
131 color.fType = Color::kPremulGrColorAttribute_Type;
132 } else {
133 color.fType = Color::kUnpremulSkColorAttribute_Type;
134 color.fColorSpaceXform = fColorSpaceXform;
135 }
Brian Salomon199fb872017-02-06 09:41:10 -0500136 *hasColorAttribute = true;
137 } else {
138 *hasColorAttribute = false;
139 };
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400140
Brian Salomon199fb872017-02-06 09:41:10 -0500141 const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400142
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000143 return GrDefaultGeoProcFactory::Make(color,
144 Coverage::kSolid_Type,
145 localCoordsType,
146 vm);
Brian Salomon199fb872017-02-06 09:41:10 -0500147}
148
Brian Salomon91326c32017-08-09 16:02:19 -0400149void GrDrawVerticesOp::onPrepareDraws(Target* target) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400150 if (fMeshes[0].fVertices->isVolatile()) {
151 this->drawVolatile(target);
152 } else {
153 this->drawNonVolatile(target);
154 }
155}
156
157void GrDrawVerticesOp::drawVolatile(Target* target) {
Brian Salomon199fb872017-02-06 09:41:10 -0500158 bool hasColorAttribute;
159 bool hasLocalCoordsAttribute;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400160 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000161 &hasLocalCoordsAttribute);
joshualitt2771b562015-08-07 12:46:26 -0700162
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400163 // Calculate the stride.
164 size_t vertexStride = sizeof(SkPoint) +
165 (hasColorAttribute ? sizeof(uint32_t) : 0) +
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000166 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0);
Brian Salomon92be2f72018-06-19 14:33:47 -0400167 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
joshualitt2771b562015-08-07 12:46:26 -0700168
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400169 // Allocate buffers.
170 const GrBuffer* vertexBuffer = nullptr;
171 int firstVertex = 0;
bsalomon14eaaa62015-09-24 07:01:26 -0700172 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700173 if (!verts) {
174 SkDebugf("Could not allocate vertices\n");
175 return;
176 }
177
cdalton397536c2016-03-25 12:15:03 -0700178 const GrBuffer* indexBuffer = nullptr;
joshualitt2771b562015-08-07 12:46:26 -0700179 int firstIndex = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700180 uint16_t* indices = nullptr;
Brian Salomon199fb872017-02-06 09:41:10 -0500181 if (this->isIndexed()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700182 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700183 if (!indices) {
184 SkDebugf("Could not allocate indices\n");
185 return;
186 }
187 }
188
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400189 // Fill the buffers.
190 this->fillBuffers(hasColorAttribute,
191 hasLocalCoordsAttribute,
192 vertexStride,
193 verts,
194 indices);
195
196 // Draw the vertices.
197 this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex);
198}
199
200void GrDrawVerticesOp::drawNonVolatile(Target* target) {
201 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
202
203 bool hasColorAttribute;
204 bool hasLocalCoordsAttribute;
205 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000206 &hasLocalCoordsAttribute);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400207
208 SkASSERT(fMeshes.count() == 1); // Non-volatile meshes should never combine.
209
210 // Get the resource provider.
211 GrResourceProvider* rp = target->resourceProvider();
212
213 // Generate keys for the buffers.
214 GrUniqueKey vertexKey, indexKey;
215 GrUniqueKey::Builder vertexKeyBuilder(&vertexKey, kDomain, 2);
216 GrUniqueKey::Builder indexKeyBuilder(&indexKey, kDomain, 2);
217 vertexKeyBuilder[0] = indexKeyBuilder[0] = fMeshes[0].fVertices->uniqueID();
218 vertexKeyBuilder[1] = 0;
219 indexKeyBuilder[1] = 1;
220 vertexKeyBuilder.finish();
221 indexKeyBuilder.finish();
222
223 // Try to grab data from the cache.
224 sk_sp<GrBuffer> vertexBuffer = rp->findByUniqueKey<GrBuffer>(vertexKey);
225 sk_sp<GrBuffer> indexBuffer = this->isIndexed() ?
226 rp->findByUniqueKey<GrBuffer>(indexKey) :
227 nullptr;
228
229 // Draw using the cached buffers if possible.
230 if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
231 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
232 return;
233 }
234
235 // Calculate the stride.
236 size_t vertexStride = sizeof(SkPoint) +
237 (hasColorAttribute ? sizeof(uint32_t) : 0) +
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000238 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400239 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
240
241 // Allocate vertex buffer.
242 vertexBuffer.reset(rp->createBuffer(fVertexCount * vertexStride,
243 kVertex_GrBufferType,
244 kStatic_GrAccessPattern,
245 0));
246 void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
247 if (!verts) {
248 SkDebugf("Could not allocate vertices\n");
249 return;
250 }
251
252 // Allocate index buffer.
253 uint16_t* indices = nullptr;
254 if (this->isIndexed()) {
255 indexBuffer.reset(rp->createBuffer(fIndexCount * sizeof(uint16_t),
256 kIndex_GrBufferType,
257 kStatic_GrAccessPattern,
258 0));
259 indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr;
260 if (!indices) {
261 SkDebugf("Could not allocate indices\n");
262 return;
263 }
264 }
265
266 // Fill the buffers.
267 this->fillBuffers(hasColorAttribute,
268 hasLocalCoordsAttribute,
269 vertexStride,
270 verts,
271 indices);
272
273 // Unmap the buffers.
274 vertexBuffer->unmap();
275 if (indexBuffer) {
276 indexBuffer->unmap();
277 }
278
279 // Cache the buffers.
280 rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get());
281 rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
282
283 // Draw the vertices.
284 this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
285}
286
287void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
288 bool hasLocalCoordsAttribute,
289 size_t vertexStride,
290 void* verts,
291 uint16_t* indices) const {
292 int instanceCount = fMeshes.count();
293
294 // Copy data into the buffers.
joshualitt2771b562015-08-07 12:46:26 -0700295 int vertexOffset = 0;
Brian Salomonfab30a32017-02-06 19:06:22 -0500296 // We have a fast case below for uploading the vertex data when the matrix is translate
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400297 // only and there are colors but not local coords. Fast case does not apply when there are bone
298 // transformations.
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000299 bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute;
joshualitt2771b562015-08-07 12:46:26 -0700300 for (int i = 0; i < instanceCount; i++) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400301 // Get each mesh.
bsalomond92b4192016-06-30 07:59:23 -0700302 const Mesh& mesh = fMeshes[i];
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400303
304 // Copy data into the index buffer.
bsalomon14eaaa62015-09-24 07:01:26 -0700305 if (indices) {
Brian Salomon199fb872017-02-06 09:41:10 -0500306 int indexCount = mesh.fVertices->indexCount();
Brian Salomonfab30a32017-02-06 19:06:22 -0500307 for (int j = 0; j < indexCount; ++j) {
308 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700309 }
310 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400311
312 // Copy data into the vertex buffer.
Brian Salomon199fb872017-02-06 09:41:10 -0500313 int vertexCount = mesh.fVertices->vertexCount();
314 const SkPoint* positions = mesh.fVertices->positions();
315 const SkColor* colors = mesh.fVertices->colors();
316 const SkPoint* localCoords = mesh.fVertices->texCoords();
Brian Salomonfab30a32017-02-06 19:06:22 -0500317 bool fastMesh = (!this->hasMultipleViewMatrices() ||
318 mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
319 mesh.hasPerVertexColors();
320 if (fastAttrs && fastMesh) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400321 // Fast case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500322 struct V {
323 SkPoint fPos;
324 uint32_t fColor;
325 };
326 SkASSERT(sizeof(V) == vertexStride);
327 V* v = (V*)verts;
328 Sk2f t(0, 0);
Brian Salomon199fb872017-02-06 09:41:10 -0500329 if (this->hasMultipleViewMatrices()) {
Brian Salomonfab30a32017-02-06 19:06:22 -0500330 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
joshualitt2771b562015-08-07 12:46:26 -0700331 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500332 for (int j = 0; j < vertexCount; ++j) {
333 Sk2f p = Sk2f::Load(positions++) + t;
334 p.store(&v[j].fPos);
335 v[j].fColor = colors[j];
336 }
337 verts = v + vertexCount;
338 } else {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400339 // Normal case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500340 static constexpr size_t kColorOffset = sizeof(SkPoint);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400341 size_t offset = kColorOffset;
342 if (hasColorAttribute) {
343 offset += sizeof(uint32_t);
344 }
345 size_t localCoordOffset = offset;
Brian Salomonfab30a32017-02-06 19:06:22 -0500346
347 for (int j = 0; j < vertexCount; ++j) {
348 if (this->hasMultipleViewMatrices()) {
349 mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
Brian Salomon3f363692017-02-02 21:05:19 -0500350 } else {
Brian Salomonfab30a32017-02-06 19:06:22 -0500351 *((SkPoint*)verts) = positions[j];
Brian Salomon199fb872017-02-06 09:41:10 -0500352 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500353 if (hasColorAttribute) {
354 if (mesh.hasPerVertexColors()) {
355 *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
356 } else {
357 *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
358 }
Brian Salomon3f363692017-02-02 21:05:19 -0500359 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500360 if (hasLocalCoordsAttribute) {
361 if (mesh.hasExplicitLocalCoords()) {
362 *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
363 } else {
364 *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
365 }
366 }
367 verts = (void*)((intptr_t)verts + vertexStride);
joshualitt2771b562015-08-07 12:46:26 -0700368 }
joshualitt2771b562015-08-07 12:46:26 -0700369 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500370 vertexOffset += vertexCount;
joshualitt2771b562015-08-07 12:46:26 -0700371 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400372}
joshualitt2771b562015-08-07 12:46:26 -0700373
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400374void GrDrawVerticesOp::drawVertices(Target* target,
375 GrGeometryProcessor* gp,
376 const GrBuffer* vertexBuffer,
377 int firstVertex,
378 const GrBuffer* indexBuffer,
379 int firstIndex) {
Chris Daltonbca46e22017-05-15 11:03:26 -0600380 GrMesh mesh(this->primitiveType());
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400381 if (this->isIndexed()) {
382 mesh.setIndexed(indexBuffer, fIndexCount,
383 firstIndex, 0, fVertexCount - 1,
Ruiqi Maoc05aa7d2018-07-03 21:18:07 +0000384 GrPrimitiveRestart::kNo);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400385 } else {
386 mesh.setNonIndexedNonInstanced(fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700387 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600388 mesh.setVertexData(vertexBuffer, firstVertex);
Brian Salomon49348902018-06-26 09:12:38 -0400389 auto pipe = fHelper.makePipeline(target);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400390 target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
joshualitt2771b562015-08-07 12:46:26 -0700391}
392
Brian Salomonfc527d22016-12-14 21:07:01 -0500393bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
394 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700395
Brian Salomonc2f42542017-07-12 14:11:22 -0400396 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
joshualitt2771b562015-08-07 12:46:26 -0700397 return false;
398 }
399
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400400 // Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
401 // then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
402 // that was saved in its vertex buffer, which is not necessarily there anymore.
403 if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
404 return false;
405 }
406
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500407 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
joshualitt2771b562015-08-07 12:46:26 -0700408 return false;
409 }
410
Mike Reedaa9e3322017-03-16 14:38:48 -0400411 if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
joshualitt2771b562015-08-07 12:46:26 -0700412 return false;
413 }
414
Brian Salomon3de0aee2017-01-29 09:34:17 -0500415 if (fColorArrayType != that->fColorArrayType) {
416 return false;
417 }
418
Ben Wagner9bc36fd2018-06-15 14:23:36 -0400419 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
Brian Salomon3f363692017-02-02 21:05:19 -0500420 return false;
421 }
422
Brian Osmanfa6d8652017-05-31 09:37:27 -0400423 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
424 // gamut is determined by the render target context. A mis-match should be impossible.
425 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
426
Brian Salomon199fb872017-02-06 09:41:10 -0500427 // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
428 // with multiple view matrices.
429 fFlags |= that->fFlags;
joshualitt2771b562015-08-07 12:46:26 -0700430
Brian Salomon199fb872017-02-06 09:41:10 -0500431 if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
432 fFlags |= kRequiresPerVertexColors_Flag;
433 }
Brian Salomon3f363692017-02-02 21:05:19 -0500434 // Check whether we are about to acquire a mesh with a different view matrix.
Brian Salomon199fb872017-02-06 09:41:10 -0500435 if (!this->hasMultipleViewMatrices() &&
436 !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
437 fFlags |= kHasMultipleViewMatrices_Flag;
Brian Salomon3f363692017-02-02 21:05:19 -0500438 }
439
bsalomond92b4192016-06-30 07:59:23 -0700440 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700441 fVertexCount += that->fVertexCount;
442 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700443
bsalomon88cf17d2016-07-08 06:40:56 -0700444 this->joinBounds(*that);
joshualitt2771b562015-08-07 12:46:26 -0700445 return true;
446}
447
448///////////////////////////////////////////////////////////////////////////////////////////////////
449
Hal Canary6f6961e2017-01-31 13:50:44 -0500450#if GR_TEST_UTILS
joshualitt2771b562015-08-07 12:46:26 -0700451
Brian Salomon5ec9def2016-12-20 15:34:05 -0500452#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700453
454static uint32_t seed_vertices(GrPrimitiveType type) {
455 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600456 case GrPrimitiveType::kTriangles:
457 case GrPrimitiveType::kTriangleStrip:
joshualitt2771b562015-08-07 12:46:26 -0700458 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600459 case GrPrimitiveType::kPoints:
joshualitt2771b562015-08-07 12:46:26 -0700460 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600461 case GrPrimitiveType::kLines:
462 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700463 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600464 case GrPrimitiveType::kLinesAdjacency:
465 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700466 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400467 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700468 return 0;
469}
470
471static uint32_t primitive_vertices(GrPrimitiveType type) {
472 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600473 case GrPrimitiveType::kTriangles:
joshualitt2771b562015-08-07 12:46:26 -0700474 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600475 case GrPrimitiveType::kLines:
joshualitt2771b562015-08-07 12:46:26 -0700476 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600477 case GrPrimitiveType::kTriangleStrip:
Chris Dalton3809bab2017-06-13 10:55:06 -0600478 case GrPrimitiveType::kPoints:
479 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700480 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600481 case GrPrimitiveType::kLinesAdjacency:
482 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700483 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400484 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700485 return 0;
486}
487
488static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
489 SkPoint p;
490 p.fX = random->nextRangeScalar(min, max);
491 p.fY = random->nextRangeScalar(min, max);
492 return p;
493}
494
495static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500496 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700497 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomon3de0aee2017-01-29 09:34:17 -0500498 SkTArray<uint32_t>* colors, bool hasColors,
499 SkTArray<uint16_t>* indices, bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700500 for (uint32_t v = 0; v < count; v++) {
501 positions->push_back(random_point(random, min, max));
502 if (hasTexCoords) {
503 texCoords->push_back(random_point(random, min, max));
504 }
505 if (hasColors) {
506 colors->push_back(GrRandomColor(random));
507 }
508 if (hasIndices) {
Ben Wagnerb0897652018-06-15 15:37:57 +0000509 SkASSERT(maxVertex <= UINT16_MAX);
joshualitt2771b562015-08-07 12:46:26 -0700510 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
511 }
512 }
513}
514
Brian Salomonc2f42542017-07-12 14:11:22 -0400515GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
Chris Daltonb894c2b2017-06-14 12:39:19 -0600516 GrPrimitiveType type;
517 do {
518 type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
519 } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400520 !context->contextPriv().caps()->shaderCaps()->geometryShaderSupport());
Chris Daltonb894c2b2017-06-14 12:39:19 -0600521
joshualitt2771b562015-08-07 12:46:26 -0700522 uint32_t primitiveCount = random->nextRangeU(1, 100);
523
524 // TODO make 'sensible' indexbuffers
525 SkTArray<SkPoint> positions;
526 SkTArray<SkPoint> texCoords;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500527 SkTArray<uint32_t> colors;
joshualitt2771b562015-08-07 12:46:26 -0700528 SkTArray<uint16_t> indices;
529
530 bool hasTexCoords = random->nextBool();
531 bool hasIndices = random->nextBool();
532 bool hasColors = random->nextBool();
533
534 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
535
536 static const SkScalar kMinVertExtent = -100.f;
537 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500538 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
539 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
540 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700541
542 for (uint32_t i = 1; i < primitiveCount; i++) {
543 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500544 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
545 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700546 }
547
548 SkMatrix viewMatrix = GrTest::TestMatrix(random);
joshualitt2771b562015-08-07 12:46:26 -0700549
Brian Osmanfa6d8652017-05-31 09:37:27 -0400550 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
Brian Osmanae0c50c2017-05-25 16:56:34 -0400551
552 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
553 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
554 texCoords.begin(), colors.begin(),
555 hasIndices ? indices.count() : 0,
556 indices.begin());
Brian Salomonc2f42542017-07-12 14:11:22 -0400557 GrAAType aaType = GrAAType::kNone;
558 if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
559 aaType = GrAAType::kMSAA;
560 }
Joe Gregorio383c9bb2018-07-10 20:35:19 +0000561 return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices),
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400562 viewMatrix, aaType, std::move(colorSpaceXform), &type);
joshualitt2771b562015-08-07 12:46:26 -0700563}
564
565#endif