blob: 660d640cc8cdde3f76d35960440ba2777bea83d9 [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,
Ruiqi Maoc97a3392018-08-15 10:44:19 -040018 const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040019 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 Mao4ec72f72018-07-10 17:21:07 -040028 bones, boneCount, primType, aaType,
29 std::move(colorSpaceXform), viewMatrix);
Brian Salomon199fb872017-02-06 09:41:10 -050030}
31
Brian Osmancf860852018-10-31 14:04:39 -040032GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
Ruiqi Maoc97a3392018-08-15 10:44:19 -040033 sk_sp<SkVertices> vertices, const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040034 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);
Brian Osman8a030552017-05-23 15:03:18 -040052 mesh.fIgnoreTexCoords = false;
53 mesh.fIgnoreColors = false;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040054 mesh.fIgnoreBones = false;
joshualitt2771b562015-08-07 12:46:26 -070055
Ruiqi Maoc97a3392018-08-15 10:44:19 -040056 if (mesh.fVertices->hasBones() && bones) {
57 // Perform the transformations on the CPU instead of the GPU.
58 mesh.fVertices = mesh.fVertices->applyBones(bones, boneCount);
59 } else {
60 if (bones && boneCount > 1) {
61 // NOTE: This should never be used. All bone transforms are being done on the CPU
62 // instead of the GPU.
63
64 // Copy the bone data.
65 fBones.assign(bones, bones + boneCount);
66 }
67 }
68
Brian Salomon199fb872017-02-06 09:41:10 -050069 fFlags = 0;
70 if (mesh.hasPerVertexColors()) {
71 fFlags |= kRequiresPerVertexColors_Flag;
joshualitt2771b562015-08-07 12:46:26 -070072 }
Brian Salomon199fb872017-02-06 09:41:10 -050073 if (mesh.hasExplicitLocalCoords()) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040074 fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
joshualitt2771b562015-08-07 12:46:26 -070075 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040076 if (mesh.hasBones()) {
77 fFlags |= kHasBones_Flag;
78 }
79
80 // Special case for meshes with a world transform but no bone weights.
81 // These will be considered normal vertices draws without bones.
82 if (!mesh.fVertices->hasBones() && boneCount == 1) {
Ruiqi Maoc97a3392018-08-15 10:44:19 -040083 SkMatrix worldTransform;
84 worldTransform.setAffine(bones[0].values);
85 mesh.fViewMatrix.preConcat(worldTransform);
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040086 }
joshualitt2771b562015-08-07 12:46:26 -070087
bsalomon88cf17d2016-07-08 06:40:56 -070088 IsZeroArea zeroArea;
Chris Dalton3809bab2017-06-13 10:55:06 -060089 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
bsalomon88cf17d2016-07-08 06:40:56 -070090 zeroArea = IsZeroArea::kYes;
91 } else {
92 zeroArea = IsZeroArea::kNo;
93 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -040094
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040095 if (this->hasBones()) {
96 // We don't know the bounds if there are deformations involved, so attempt to calculate
97 // the maximum possible.
Robert Phillipsdc97fdc2018-07-18 08:27:19 -040098 SkRect bounds = SkRect::MakeEmpty();
Ruiqi Mao4ec72f72018-07-10 17:21:07 -040099 const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds());
100 for (int i = 1; i < boneCount; i++) {
Ruiqi Maoc97a3392018-08-15 10:44:19 -0400101 const SkVertices::Bone& matrix = bones[i];
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400102 bounds.join(matrix.mapRect(originalBounds));
103 }
104
105 this->setTransformedBounds(bounds,
106 mesh.fViewMatrix,
107 HasAABloat::kNo,
108 zeroArea);
109 } else {
110 this->setTransformedBounds(mesh.fVertices->bounds(),
111 mesh.fViewMatrix,
112 HasAABloat::kNo,
113 zeroArea);
114 }
joshualitt2771b562015-08-07 12:46:26 -0700115}
116
Brian Osman9a390ac2018-11-12 09:47:48 -0500117#ifdef SK_DEBUG
Brian Salomonc2f42542017-07-12 14:11:22 -0400118SkString GrDrawVerticesOp::dumpInfo() const {
119 SkString string;
120 string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
121 fMeshes.count(), fVertexCount, fIndexCount);
122 string += fHelper.dumpInfo();
123 string += INHERITED::dumpInfo();
124 return string;
joshualitt2771b562015-08-07 12:46:26 -0700125}
Brian Osman9a390ac2018-11-12 09:47:48 -0500126#endif
joshualitt2771b562015-08-07 12:46:26 -0700127
Brian Salomonc2f42542017-07-12 14:11:22 -0400128GrDrawOp::FixedFunctionFlags GrDrawVerticesOp::fixedFunctionFlags() const {
129 return fHelper.fixedFunctionFlags();
130}
131
Chris Dalton4b62aed2019-01-15 11:53:00 -0700132GrProcessorSet::Analysis GrDrawVerticesOp::finalize(const GrCaps& caps, const GrAppliedClip* clip) {
Brian Salomonc2f42542017-07-12 14:11:22 -0400133 GrProcessorAnalysisColor gpColor;
134 if (this->requiresPerVertexColors()) {
135 gpColor.setToUnknown();
136 } else {
137 gpColor.setToConstant(fMeshes.front().fColor);
138 }
Chris Dalton4b62aed2019-01-15 11:53:00 -0700139 auto result = fHelper.finalizeProcessors(caps, clip, GrProcessorAnalysisCoverage::kNone,
140 &gpColor);
Brian Salomonc2f42542017-07-12 14:11:22 -0400141 if (gpColor.isConstant(&fMeshes.front().fColor)) {
142 fMeshes.front().fIgnoreColors = true;
Brian Salomon199fb872017-02-06 09:41:10 -0500143 fFlags &= ~kRequiresPerVertexColors_Flag;
Brian Osmanae0c50c2017-05-25 16:56:34 -0400144 fColorArrayType = ColorArrayType::kPremulGrColor;
joshualitt2771b562015-08-07 12:46:26 -0700145 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400146 if (!fHelper.usesLocalCoords()) {
Brian Osman8a030552017-05-23 15:03:18 -0400147 fMeshes[0].fIgnoreTexCoords = true;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400148 fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag;
bsalomon14eaaa62015-09-24 07:01:26 -0700149 }
Brian Salomonc2f42542017-07-12 14:11:22 -0400150 return result;
joshualitt2771b562015-08-07 12:46:26 -0700151}
152
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400153sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(const GrShaderCaps* shaderCaps,
154 bool* hasColorAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400155 bool* hasLocalCoordAttribute,
156 bool* hasBoneAttribute) const {
Brian Salomon199fb872017-02-06 09:41:10 -0500157 using namespace GrDefaultGeoProcFactory;
158 LocalCoords::Type localCoordsType;
Brian Salomonc2f42542017-07-12 14:11:22 -0400159 if (fHelper.usesLocalCoords()) {
Brian Salomon199fb872017-02-06 09:41:10 -0500160 // If we have multiple view matrices we will transform the positions into device space. We
161 // must then also provide untransformed positions as local coords.
162 if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
163 *hasLocalCoordAttribute = true;
164 localCoordsType = LocalCoords::kHasExplicit_Type;
165 } else {
166 *hasLocalCoordAttribute = false;
167 localCoordsType = LocalCoords::kUsePosition_Type;
168 }
169 } else {
170 localCoordsType = LocalCoords::kUnused_Type;
171 *hasLocalCoordAttribute = false;
172 }
173
174 Color color(fMeshes[0].fColor);
175 if (this->requiresPerVertexColors()) {
Brian Osman08a50e02018-06-15 15:06:48 -0400176 if (fColorArrayType == ColorArrayType::kPremulGrColor) {
177 color.fType = Color::kPremulGrColorAttribute_Type;
178 } else {
179 color.fType = Color::kUnpremulSkColorAttribute_Type;
180 color.fColorSpaceXform = fColorSpaceXform;
181 }
Brian Salomon199fb872017-02-06 09:41:10 -0500182 *hasColorAttribute = true;
183 } else {
184 *hasColorAttribute = false;
Brian Salomon23356442018-11-30 15:33:19 -0500185 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400186
Brian Salomon199fb872017-02-06 09:41:10 -0500187 const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400188
Ruiqi Maoc97a3392018-08-15 10:44:19 -0400189 // The bones are packed as 6 floats in column major order, so we can directly upload them to
190 // the GPU as groups of 3 vec2s.
191 Bones bones(reinterpret_cast<const float*>(fBones.data()), fBones.size());
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400192 *hasBoneAttribute = this->hasBones();
193
194 if (this->hasBones()) {
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400195 return GrDefaultGeoProcFactory::MakeWithBones(shaderCaps,
196 color,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400197 Coverage::kSolid_Type,
198 localCoordsType,
199 bones,
200 vm);
201 } else {
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400202 return GrDefaultGeoProcFactory::Make(shaderCaps,
203 color,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400204 Coverage::kSolid_Type,
205 localCoordsType,
206 vm);
207 }
Brian Salomon199fb872017-02-06 09:41:10 -0500208}
209
Brian Salomon91326c32017-08-09 16:02:19 -0400210void GrDrawVerticesOp::onPrepareDraws(Target* target) {
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400211 bool hasMapBufferSupport = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
212 if (fMeshes[0].fVertices->isVolatile() || !hasMapBufferSupport) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400213 this->drawVolatile(target);
214 } else {
215 this->drawNonVolatile(target);
216 }
217}
218
219void GrDrawVerticesOp::drawVolatile(Target* target) {
Brian Salomon199fb872017-02-06 09:41:10 -0500220 bool hasColorAttribute;
221 bool hasLocalCoordsAttribute;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400222 bool hasBoneAttribute;
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400223 sk_sp<GrGeometryProcessor> gp = this->makeGP(target->caps().shaderCaps(),
224 &hasColorAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400225 &hasLocalCoordsAttribute,
226 &hasBoneAttribute);
joshualitt2771b562015-08-07 12:46:26 -0700227
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400228 // Allocate buffers.
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500229 size_t vertexStride = gp->vertexStride();
Brian Salomondbf70722019-02-07 11:31:24 -0500230 sk_sp<const GrBuffer> vertexBuffer;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400231 int firstVertex = 0;
bsalomon14eaaa62015-09-24 07:01:26 -0700232 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700233 if (!verts) {
234 SkDebugf("Could not allocate vertices\n");
235 return;
236 }
237
Brian Salomondbf70722019-02-07 11:31:24 -0500238 sk_sp<const GrBuffer> indexBuffer;
joshualitt2771b562015-08-07 12:46:26 -0700239 int firstIndex = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700240 uint16_t* indices = nullptr;
Brian Salomon199fb872017-02-06 09:41:10 -0500241 if (this->isIndexed()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700242 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700243 if (!indices) {
244 SkDebugf("Could not allocate indices\n");
245 return;
246 }
247 }
248
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400249 // Fill the buffers.
250 this->fillBuffers(hasColorAttribute,
251 hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400252 hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400253 vertexStride,
254 verts,
255 indices);
256
257 // Draw the vertices.
Brian Salomon12d22642019-01-29 14:38:50 -0500258 this->drawVertices(target, std::move(gp), std::move(vertexBuffer), firstVertex, indexBuffer,
259 firstIndex);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400260}
261
262void GrDrawVerticesOp::drawNonVolatile(Target* target) {
263 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
264
265 bool hasColorAttribute;
266 bool hasLocalCoordsAttribute;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400267 bool hasBoneAttribute;
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400268 sk_sp<GrGeometryProcessor> gp = this->makeGP(target->caps().shaderCaps(),
269 &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.
Brian Salomondbf70722019-02-07 11:31:24 -0500289 sk_sp<GrGpuBuffer> vertexBuffer = rp->findByUniqueKey<GrGpuBuffer>(vertexKey);
290 sk_sp<GrGpuBuffer> indexBuffer =
291 this->isIndexed() ? rp->findByUniqueKey<GrGpuBuffer>(indexKey) : nullptr;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400292
293 // Draw using the cached buffers if possible.
294 if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
Brian Salomon12d22642019-01-29 14:38:50 -0500295 this->drawVertices(target, std::move(gp), std::move(vertexBuffer), 0,
296 std::move(indexBuffer), 0);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400297 return;
298 }
299
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400300 // Allocate vertex buffer.
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500301 size_t vertexStride = gp->vertexStride();
Brian Salomondbf70722019-02-07 11:31:24 -0500302 vertexBuffer = rp->createBuffer(
303 fVertexCount * vertexStride, GrGpuBufferType::kVertex, kStatic_GrAccessPattern);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400304 void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
305 if (!verts) {
306 SkDebugf("Could not allocate vertices\n");
307 return;
308 }
309
310 // Allocate index buffer.
311 uint16_t* indices = nullptr;
312 if (this->isIndexed()) {
Brian Salomondbf70722019-02-07 11:31:24 -0500313 indexBuffer = rp->createBuffer(
314 fIndexCount * sizeof(uint16_t), GrGpuBufferType::kIndex, kStatic_GrAccessPattern);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400315 indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr;
316 if (!indices) {
317 SkDebugf("Could not allocate indices\n");
318 return;
319 }
320 }
321
322 // Fill the buffers.
323 this->fillBuffers(hasColorAttribute,
324 hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400325 hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400326 vertexStride,
327 verts,
328 indices);
329
330 // Unmap the buffers.
331 vertexBuffer->unmap();
332 if (indexBuffer) {
333 indexBuffer->unmap();
334 }
335
336 // Cache the buffers.
337 rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get());
338 rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
339
340 // Draw the vertices.
Brian Salomon12d22642019-01-29 14:38:50 -0500341 this->drawVertices(target, std::move(gp), std::move(vertexBuffer), 0, std::move(indexBuffer),
342 0);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400343}
344
345void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
346 bool hasLocalCoordsAttribute,
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400347 bool hasBoneAttribute,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400348 size_t vertexStride,
349 void* verts,
350 uint16_t* indices) const {
351 int instanceCount = fMeshes.count();
352
353 // Copy data into the buffers.
joshualitt2771b562015-08-07 12:46:26 -0700354 int vertexOffset = 0;
Brian Salomonfab30a32017-02-06 19:06:22 -0500355 // We have a fast case below for uploading the vertex data when the matrix is translate
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400356 // only and there are colors but not local coords. Fast case does not apply when there are bone
357 // transformations.
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400358 bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute && !hasBoneAttribute;
joshualitt2771b562015-08-07 12:46:26 -0700359 for (int i = 0; i < instanceCount; i++) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400360 // Get each mesh.
bsalomond92b4192016-06-30 07:59:23 -0700361 const Mesh& mesh = fMeshes[i];
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400362
363 // Copy data into the index buffer.
bsalomon14eaaa62015-09-24 07:01:26 -0700364 if (indices) {
Brian Salomon199fb872017-02-06 09:41:10 -0500365 int indexCount = mesh.fVertices->indexCount();
Brian Salomonfab30a32017-02-06 19:06:22 -0500366 for (int j = 0; j < indexCount; ++j) {
367 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700368 }
369 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400370
371 // Copy data into the vertex buffer.
Brian Salomon199fb872017-02-06 09:41:10 -0500372 int vertexCount = mesh.fVertices->vertexCount();
373 const SkPoint* positions = mesh.fVertices->positions();
374 const SkColor* colors = mesh.fVertices->colors();
375 const SkPoint* localCoords = mesh.fVertices->texCoords();
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400376 const SkVertices::BoneIndices* boneIndices = mesh.fVertices->boneIndices();
377 const SkVertices::BoneWeights* boneWeights = mesh.fVertices->boneWeights();
Brian Salomonfab30a32017-02-06 19:06:22 -0500378 bool fastMesh = (!this->hasMultipleViewMatrices() ||
379 mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
380 mesh.hasPerVertexColors();
381 if (fastAttrs && fastMesh) {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400382 // Fast case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500383 struct V {
384 SkPoint fPos;
385 uint32_t fColor;
386 };
387 SkASSERT(sizeof(V) == vertexStride);
388 V* v = (V*)verts;
389 Sk2f t(0, 0);
Brian Salomon199fb872017-02-06 09:41:10 -0500390 if (this->hasMultipleViewMatrices()) {
Brian Salomonfab30a32017-02-06 19:06:22 -0500391 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
joshualitt2771b562015-08-07 12:46:26 -0700392 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500393 for (int j = 0; j < vertexCount; ++j) {
394 Sk2f p = Sk2f::Load(positions++) + t;
395 p.store(&v[j].fPos);
396 v[j].fColor = colors[j];
397 }
398 verts = v + vertexCount;
399 } else {
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400400 // Normal case.
Brian Salomonfab30a32017-02-06 19:06:22 -0500401 static constexpr size_t kColorOffset = sizeof(SkPoint);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400402 size_t offset = kColorOffset;
403 if (hasColorAttribute) {
404 offset += sizeof(uint32_t);
405 }
406 size_t localCoordOffset = offset;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400407 if (hasLocalCoordsAttribute) {
408 offset += sizeof(SkPoint);
409 }
410 size_t boneIndexOffset = offset;
411 if (hasBoneAttribute) {
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400412 offset += 4 * sizeof(int8_t);
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400413 }
414 size_t boneWeightOffset = offset;
Brian Salomonfab30a32017-02-06 19:06:22 -0500415
Brian Osman1be2b7c2018-10-29 16:07:15 -0400416 // TODO4F: Preserve float colors
Brian Osmancf860852018-10-31 14:04:39 -0400417 GrColor color = mesh.fColor.toBytes_RGBA();
Brian Osman1be2b7c2018-10-29 16:07:15 -0400418
Brian Salomonfab30a32017-02-06 19:06:22 -0500419 for (int j = 0; j < vertexCount; ++j) {
420 if (this->hasMultipleViewMatrices()) {
421 mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
Brian Salomon3f363692017-02-02 21:05:19 -0500422 } else {
Brian Salomonfab30a32017-02-06 19:06:22 -0500423 *((SkPoint*)verts) = positions[j];
Brian Salomon199fb872017-02-06 09:41:10 -0500424 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500425 if (hasColorAttribute) {
426 if (mesh.hasPerVertexColors()) {
427 *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
428 } else {
Brian Osman1be2b7c2018-10-29 16:07:15 -0400429 *(uint32_t*)((intptr_t)verts + kColorOffset) = color;
Brian Salomonfab30a32017-02-06 19:06:22 -0500430 }
Brian Salomon3f363692017-02-02 21:05:19 -0500431 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500432 if (hasLocalCoordsAttribute) {
433 if (mesh.hasExplicitLocalCoords()) {
434 *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
435 } else {
436 *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
437 }
438 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400439 if (hasBoneAttribute) {
440 const SkVertices::BoneIndices& indices = boneIndices[j];
441 const SkVertices::BoneWeights& weights = boneWeights[j];
442 for (int k = 0; k < 4; k++) {
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400443 size_t indexOffset = boneIndexOffset + sizeof(int8_t) * k;
444 size_t weightOffset = boneWeightOffset + sizeof(uint8_t) * k;
445 *(int8_t*)((intptr_t)verts + indexOffset) = indices.indices[k];
446 *(uint8_t*)((intptr_t)verts + weightOffset) = weights.weights[k] * 255.0f;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400447 }
448 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500449 verts = (void*)((intptr_t)verts + vertexStride);
joshualitt2771b562015-08-07 12:46:26 -0700450 }
joshualitt2771b562015-08-07 12:46:26 -0700451 }
Brian Salomonfab30a32017-02-06 19:06:22 -0500452 vertexOffset += vertexCount;
joshualitt2771b562015-08-07 12:46:26 -0700453 }
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400454}
joshualitt2771b562015-08-07 12:46:26 -0700455
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400456void GrDrawVerticesOp::drawVertices(Target* target,
Brian Salomon7eae3e02018-08-07 14:02:38 +0000457 sk_sp<const GrGeometryProcessor> gp,
Brian Salomon12d22642019-01-29 14:38:50 -0500458 sk_sp<const GrBuffer> vertexBuffer,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400459 int firstVertex,
Brian Salomon12d22642019-01-29 14:38:50 -0500460 sk_sp<const GrBuffer> indexBuffer,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400461 int firstIndex) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000462 GrMesh* mesh = target->allocMesh(this->primitiveType());
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400463 if (this->isIndexed()) {
Brian Salomon12d22642019-01-29 14:38:50 -0500464 mesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
Brian Salomon7eae3e02018-08-07 14:02:38 +0000465 GrPrimitiveRestart::kNo);
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400466 } else {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000467 mesh->setNonIndexedNonInstanced(fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700468 }
Brian Salomon12d22642019-01-29 14:38:50 -0500469 mesh->setVertexData(std::move(vertexBuffer), firstVertex);
Brian Salomon49348902018-06-26 09:12:38 -0400470 auto pipe = fHelper.makePipeline(target);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000471 target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
joshualitt2771b562015-08-07 12:46:26 -0700472}
473
Brian Salomon7eae3e02018-08-07 14:02:38 +0000474GrOp::CombineResult GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500475 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700476
Brian Salomonc2f42542017-07-12 14:11:22 -0400477 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000478 return CombineResult::kCannotCombine;
joshualitt2771b562015-08-07 12:46:26 -0700479 }
480
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400481 // Meshes with bones cannot be combined because different meshes use different bones, so to
482 // combine them, the matrices would have to be combined, and the bone indices on each vertex
483 // would change, thus making the vertices uncacheable.
484 if (this->hasBones() || that->hasBones()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000485 return CombineResult::kCannotCombine;
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400486 }
487
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400488 // Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
489 // then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
490 // that was saved in its vertex buffer, which is not necessarily there anymore.
491 if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000492 return CombineResult::kCannotCombine;
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400493 }
494
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500495 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000496 return CombineResult::kCannotCombine;
joshualitt2771b562015-08-07 12:46:26 -0700497 }
498
Mike Reedaa9e3322017-03-16 14:38:48 -0400499 if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000500 return CombineResult::kCannotCombine;
joshualitt2771b562015-08-07 12:46:26 -0700501 }
502
Brian Salomon3de0aee2017-01-29 09:34:17 -0500503 if (fColorArrayType != that->fColorArrayType) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000504 return CombineResult::kCannotCombine;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500505 }
506
Ben Wagner9bc36fd2018-06-15 14:23:36 -0400507 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000508 return CombineResult::kCannotCombine;
Brian Salomon3f363692017-02-02 21:05:19 -0500509 }
510
Brian Osmanfa6d8652017-05-31 09:37:27 -0400511 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
512 // gamut is determined by the render target context. A mis-match should be impossible.
513 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
514
Brian Salomon199fb872017-02-06 09:41:10 -0500515 // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
516 // with multiple view matrices.
517 fFlags |= that->fFlags;
joshualitt2771b562015-08-07 12:46:26 -0700518
Brian Salomon199fb872017-02-06 09:41:10 -0500519 if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
520 fFlags |= kRequiresPerVertexColors_Flag;
521 }
Brian Salomon3f363692017-02-02 21:05:19 -0500522 // Check whether we are about to acquire a mesh with a different view matrix.
Brian Salomon199fb872017-02-06 09:41:10 -0500523 if (!this->hasMultipleViewMatrices() &&
524 !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
525 fFlags |= kHasMultipleViewMatrices_Flag;
Brian Salomon3f363692017-02-02 21:05:19 -0500526 }
527
bsalomond92b4192016-06-30 07:59:23 -0700528 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700529 fVertexCount += that->fVertexCount;
530 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700531
Brian Salomon7eae3e02018-08-07 14:02:38 +0000532 return CombineResult::kMerged;
joshualitt2771b562015-08-07 12:46:26 -0700533}
534
535///////////////////////////////////////////////////////////////////////////////////////////////////
536
Hal Canary6f6961e2017-01-31 13:50:44 -0500537#if GR_TEST_UTILS
joshualitt2771b562015-08-07 12:46:26 -0700538
Brian Salomon5ec9def2016-12-20 15:34:05 -0500539#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700540
541static uint32_t seed_vertices(GrPrimitiveType type) {
542 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600543 case GrPrimitiveType::kTriangles:
544 case GrPrimitiveType::kTriangleStrip:
joshualitt2771b562015-08-07 12:46:26 -0700545 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600546 case GrPrimitiveType::kPoints:
joshualitt2771b562015-08-07 12:46:26 -0700547 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600548 case GrPrimitiveType::kLines:
549 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700550 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600551 case GrPrimitiveType::kLinesAdjacency:
552 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700553 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400554 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700555 return 0;
556}
557
558static uint32_t primitive_vertices(GrPrimitiveType type) {
559 switch (type) {
Chris Dalton3809bab2017-06-13 10:55:06 -0600560 case GrPrimitiveType::kTriangles:
joshualitt2771b562015-08-07 12:46:26 -0700561 return 3;
Chris Dalton3809bab2017-06-13 10:55:06 -0600562 case GrPrimitiveType::kLines:
joshualitt2771b562015-08-07 12:46:26 -0700563 return 2;
Chris Dalton3809bab2017-06-13 10:55:06 -0600564 case GrPrimitiveType::kTriangleStrip:
Chris Dalton3809bab2017-06-13 10:55:06 -0600565 case GrPrimitiveType::kPoints:
566 case GrPrimitiveType::kLineStrip:
joshualitt2771b562015-08-07 12:46:26 -0700567 return 1;
Chris Dalton3809bab2017-06-13 10:55:06 -0600568 case GrPrimitiveType::kLinesAdjacency:
569 return 4;
joshualitt2771b562015-08-07 12:46:26 -0700570 }
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400571 SK_ABORT("Incomplete switch\n");
joshualitt2771b562015-08-07 12:46:26 -0700572 return 0;
573}
574
575static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
576 SkPoint p;
577 p.fX = random->nextRangeScalar(min, max);
578 p.fY = random->nextRangeScalar(min, max);
579 return p;
580}
581
582static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500583 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700584 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomon3de0aee2017-01-29 09:34:17 -0500585 SkTArray<uint32_t>* colors, bool hasColors,
586 SkTArray<uint16_t>* indices, bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700587 for (uint32_t v = 0; v < count; v++) {
588 positions->push_back(random_point(random, min, max));
589 if (hasTexCoords) {
590 texCoords->push_back(random_point(random, min, max));
591 }
592 if (hasColors) {
593 colors->push_back(GrRandomColor(random));
594 }
595 if (hasIndices) {
Ben Wagnerb0897652018-06-15 15:37:57 +0000596 SkASSERT(maxVertex <= UINT16_MAX);
joshualitt2771b562015-08-07 12:46:26 -0700597 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
598 }
599 }
600}
601
Brian Salomonc2f42542017-07-12 14:11:22 -0400602GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
Chris Daltonb894c2b2017-06-14 12:39:19 -0600603 GrPrimitiveType type;
604 do {
605 type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
606 } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
Robert Phillips9da87e02019-02-04 13:26:26 -0500607 !context->priv().caps()->shaderCaps()->geometryShaderSupport());
Chris Daltonb894c2b2017-06-14 12:39:19 -0600608
joshualitt2771b562015-08-07 12:46:26 -0700609 uint32_t primitiveCount = random->nextRangeU(1, 100);
610
611 // TODO make 'sensible' indexbuffers
612 SkTArray<SkPoint> positions;
613 SkTArray<SkPoint> texCoords;
Brian Salomon3de0aee2017-01-29 09:34:17 -0500614 SkTArray<uint32_t> colors;
joshualitt2771b562015-08-07 12:46:26 -0700615 SkTArray<uint16_t> indices;
616
617 bool hasTexCoords = random->nextBool();
618 bool hasIndices = random->nextBool();
619 bool hasColors = random->nextBool();
620
621 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
622
623 static const SkScalar kMinVertExtent = -100.f;
624 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500625 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
626 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
627 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700628
629 for (uint32_t i = 1; i < primitiveCount; i++) {
630 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500631 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
632 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700633 }
634
635 SkMatrix viewMatrix = GrTest::TestMatrix(random);
joshualitt2771b562015-08-07 12:46:26 -0700636
Brian Osmanfa6d8652017-05-31 09:37:27 -0400637 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
Brian Osmanae0c50c2017-05-25 16:56:34 -0400638
639 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
640 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
641 texCoords.begin(), colors.begin(),
642 hasIndices ? indices.count() : 0,
643 indices.begin());
Brian Salomonc2f42542017-07-12 14:11:22 -0400644 GrAAType aaType = GrAAType::kNone;
645 if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
646 aaType = GrAAType::kMSAA;
647 }
Ruiqi Mao4ec72f72018-07-10 17:21:07 -0400648 return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0,
Ruiqi Mao9a6e42f2018-07-09 14:16:56 -0400649 viewMatrix, aaType, std::move(colorSpaceXform), &type);
joshualitt2771b562015-08-07 12:46:26 -0700650}
651
652#endif