blob: c6ae1c1efad80bef75ad55b0351aa4e412e58cf7 [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"
joshualitt2771b562015-08-07 12:46:26 -07009
joshualitt2771b562015-08-07 12:46:26 -070010#include "GrDefaultGeoProcFactory.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050011#include "GrInvariantOutput.h"
12#include "GrOpFlushState.h"
joshualitt2771b562015-08-07 12:46:26 -070013
bungeman06ca8ec2016-06-09 08:01:03 -070014static sk_sp<GrGeometryProcessor> set_vertex_attributes(bool hasLocalCoords,
joshualitt2771b562015-08-07 12:46:26 -070015 int* colorOffset,
16 int* texOffset,
joshualitt2771b562015-08-07 12:46:26 -070017 const SkMatrix& viewMatrix,
18 bool coverageIgnored) {
19 using namespace GrDefaultGeoProcFactory;
20 *texOffset = -1;
21 *colorOffset = -1;
joshualitt2771b562015-08-07 12:46:26 -070022
23 Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
Brian Salomonfc527d22016-12-14 21:07:01 -050024 LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type
25 : LocalCoords::kUsePosition_Type);
bsalomon14eaaa62015-09-24 07:01:26 -070026 *colorOffset = sizeof(SkPoint);
27 if (hasLocalCoords) {
joshualitt2771b562015-08-07 12:46:26 -070028 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
joshualitt2771b562015-08-07 12:46:26 -070029 }
Brian Salomonfc527d22016-12-14 21:07:01 -050030 return GrDefaultGeoProcFactory::Make(Color(Color::kAttribute_Type), coverage, localCoords,
31 viewMatrix);
joshualitt2771b562015-08-07 12:46:26 -070032}
33
Brian Salomonfc527d22016-12-14 21:07:01 -050034GrDrawVerticesOp::GrDrawVerticesOp(GrColor color, GrPrimitiveType primitiveType,
35 const SkMatrix& viewMatrix, const SkPoint* positions,
36 int vertexCount, const uint16_t* indices, int indexCount,
37 const GrColor* colors, const SkPoint* localCoords,
38 const SkRect& bounds)
39 : INHERITED(ClassID()) {
joshualitt2771b562015-08-07 12:46:26 -070040 SkASSERT(positions);
41
bsalomon14eaaa62015-09-24 07:01:26 -070042 fViewMatrix = viewMatrix;
bsalomond92b4192016-06-30 07:59:23 -070043 Mesh& mesh = fMeshes.push_back();
44 mesh.fColor = color;
joshualitt2771b562015-08-07 12:46:26 -070045
bsalomond92b4192016-06-30 07:59:23 -070046 mesh.fPositions.append(vertexCount, positions);
joshualitt2771b562015-08-07 12:46:26 -070047 if (indices) {
bsalomond92b4192016-06-30 07:59:23 -070048 mesh.fIndices.append(indexCount, indices);
joshualitt2771b562015-08-07 12:46:26 -070049 }
50
51 if (colors) {
bsalomon14eaaa62015-09-24 07:01:26 -070052 fVariableColor = true;
bsalomond92b4192016-06-30 07:59:23 -070053 mesh.fColors.append(vertexCount, colors);
joshualitt2771b562015-08-07 12:46:26 -070054 } else {
bsalomon14eaaa62015-09-24 07:01:26 -070055 fVariableColor = false;
joshualitt2771b562015-08-07 12:46:26 -070056 }
57
58 if (localCoords) {
bsalomond92b4192016-06-30 07:59:23 -070059 mesh.fLocalCoords.append(vertexCount, localCoords);
joshualitt2771b562015-08-07 12:46:26 -070060 }
bsalomon14eaaa62015-09-24 07:01:26 -070061 fVertexCount = vertexCount;
62 fIndexCount = indexCount;
63 fPrimitiveType = primitiveType;
joshualitt2771b562015-08-07 12:46:26 -070064
bsalomon88cf17d2016-07-08 06:40:56 -070065 IsZeroArea zeroArea;
66 if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) {
67 zeroArea = IsZeroArea::kYes;
68 } else {
69 zeroArea = IsZeroArea::kNo;
70 }
71 this->setBounds(bounds, HasAABloat::kNo, zeroArea);
joshualitt2771b562015-08-07 12:46:26 -070072}
73
Brian Salomonfc527d22016-12-14 21:07:01 -050074void GrDrawVerticesOp::computePipelineOptimizations(GrInitInvariantOutput* color,
75 GrInitInvariantOutput* coverage,
76 GrBatchToXPOverrides* overrides) const {
77 // When this is called there is only one mesh.
bsalomon14eaaa62015-09-24 07:01:26 -070078 if (fVariableColor) {
ethannicholasff210322015-11-24 12:10:10 -080079 color->setUnknownFourComponents();
joshualitt2771b562015-08-07 12:46:26 -070080 } else {
bsalomond92b4192016-06-30 07:59:23 -070081 color->setKnownFourComponents(fMeshes[0].fColor);
joshualitt2771b562015-08-07 12:46:26 -070082 }
ethannicholasff210322015-11-24 12:10:10 -080083 coverage->setKnownSingleComponent(0xff);
joshualitt2771b562015-08-07 12:46:26 -070084}
85
Brian Salomonfc527d22016-12-14 21:07:01 -050086void GrDrawVerticesOp::initBatchTracker(const GrXPOverridesForBatch& overrides) {
bsalomond92b4192016-06-30 07:59:23 -070087 SkASSERT(fMeshes.count() == 1);
bsalomon14eaaa62015-09-24 07:01:26 -070088 GrColor overrideColor;
ethannicholasff210322015-11-24 12:10:10 -080089 if (overrides.getOverrideColorIfSet(&overrideColor)) {
bsalomond92b4192016-06-30 07:59:23 -070090 fMeshes[0].fColor = overrideColor;
91 fMeshes[0].fColors.reset();
bsalomon14eaaa62015-09-24 07:01:26 -070092 fVariableColor = false;
joshualitt2771b562015-08-07 12:46:26 -070093 }
ethannicholasff210322015-11-24 12:10:10 -080094 fCoverageIgnored = !overrides.readsCoverage();
95 if (!overrides.readsLocalCoords()) {
bsalomond92b4192016-06-30 07:59:23 -070096 fMeshes[0].fLocalCoords.reset();
bsalomon14eaaa62015-09-24 07:01:26 -070097 }
joshualitt2771b562015-08-07 12:46:26 -070098}
99
Brian Salomonfc527d22016-12-14 21:07:01 -0500100void GrDrawVerticesOp::onPrepareDraws(Target* target) const {
bsalomond92b4192016-06-30 07:59:23 -0700101 bool hasLocalCoords = !fMeshes[0].fLocalCoords.isEmpty();
joshualitt2771b562015-08-07 12:46:26 -0700102 int colorOffset = -1, texOffset = -1;
bungeman06ca8ec2016-06-09 08:01:03 -0700103 sk_sp<GrGeometryProcessor> gp(set_vertex_attributes(hasLocalCoords, &colorOffset, &texOffset,
104 fViewMatrix, fCoverageIgnored));
joshualitt2771b562015-08-07 12:46:26 -0700105 size_t vertexStride = gp->getVertexStride();
106
Brian Salomonfc527d22016-12-14 21:07:01 -0500107 SkASSERT(vertexStride ==
108 sizeof(SkPoint) + (hasLocalCoords ? sizeof(SkPoint) : 0) + sizeof(GrColor));
joshualitt2771b562015-08-07 12:46:26 -0700109
bsalomond92b4192016-06-30 07:59:23 -0700110 int instanceCount = fMeshes.count();
joshualitt2771b562015-08-07 12:46:26 -0700111
cdalton397536c2016-03-25 12:15:03 -0700112 const GrBuffer* vertexBuffer;
joshualitt2771b562015-08-07 12:46:26 -0700113 int firstVertex;
114
bsalomon14eaaa62015-09-24 07:01:26 -0700115 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700116
117 if (!verts) {
118 SkDebugf("Could not allocate vertices\n");
119 return;
120 }
121
cdalton397536c2016-03-25 12:15:03 -0700122 const GrBuffer* indexBuffer = nullptr;
joshualitt2771b562015-08-07 12:46:26 -0700123 int firstIndex = 0;
124
halcanary96fcdcc2015-08-27 07:41:13 -0700125 uint16_t* indices = nullptr;
bsalomond92b4192016-06-30 07:59:23 -0700126 if (!fMeshes[0].fIndices.isEmpty()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700127 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700128
129 if (!indices) {
130 SkDebugf("Could not allocate indices\n");
131 return;
132 }
133 }
134
135 int indexOffset = 0;
136 int vertexOffset = 0;
137 for (int i = 0; i < instanceCount; i++) {
bsalomond92b4192016-06-30 07:59:23 -0700138 const Mesh& mesh = fMeshes[i];
joshualitt2771b562015-08-07 12:46:26 -0700139
140 // TODO we can actually cache this interleaved and then just memcopy
bsalomon14eaaa62015-09-24 07:01:26 -0700141 if (indices) {
bsalomond92b4192016-06-30 07:59:23 -0700142 for (int j = 0; j < mesh.fIndices.count(); ++j, ++indexOffset) {
143 *(indices + indexOffset) = mesh.fIndices[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700144 }
145 }
146
bsalomond92b4192016-06-30 07:59:23 -0700147 for (int j = 0; j < mesh.fPositions.count(); ++j) {
148 *((SkPoint*)verts) = mesh.fPositions[j];
149 if (mesh.fColors.isEmpty()) {
150 *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColor;
bsalomon14eaaa62015-09-24 07:01:26 -0700151 } else {
bsalomond92b4192016-06-30 07:59:23 -0700152 *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColors[j];
joshualitt2771b562015-08-07 12:46:26 -0700153 }
bsalomon14eaaa62015-09-24 07:01:26 -0700154 if (hasLocalCoords) {
bsalomond92b4192016-06-30 07:59:23 -0700155 *(SkPoint*)((intptr_t)verts + texOffset) = mesh.fLocalCoords[j];
joshualitt2771b562015-08-07 12:46:26 -0700156 }
157 verts = (void*)((intptr_t)verts + vertexStride);
158 vertexOffset++;
159 }
160 }
161
egdaniel0e1853c2016-03-17 11:35:45 -0700162 GrMesh mesh;
bsalomon14eaaa62015-09-24 07:01:26 -0700163 if (indices) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500164 mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, firstIndex,
165 fVertexCount, fIndexCount);
joshualitt2771b562015-08-07 12:46:26 -0700166
167 } else {
egdaniel0e1853c2016-03-17 11:35:45 -0700168 mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700169 }
bungeman06ca8ec2016-06-09 08:01:03 -0700170 target->draw(gp.get(), mesh);
joshualitt2771b562015-08-07 12:46:26 -0700171}
172
Brian Salomonfc527d22016-12-14 21:07:01 -0500173bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
174 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700175
176 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
177 that->bounds(), caps)) {
joshualitt2771b562015-08-07 12:46:26 -0700178 return false;
179 }
180
joshualitt2771b562015-08-07 12:46:26 -0700181 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
182 return false;
183 }
184
Brian Salomonfc527d22016-12-14 21:07:01 -0500185 // We currently use a uniform viewmatrix for this op.
bsalomon14eaaa62015-09-24 07:01:26 -0700186 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
joshualitt2771b562015-08-07 12:46:26 -0700187 return false;
188 }
189
bsalomond92b4192016-06-30 07:59:23 -0700190 if (fMeshes[0].fIndices.isEmpty() != that->fMeshes[0].fIndices.isEmpty()) {
joshualitt2771b562015-08-07 12:46:26 -0700191 return false;
192 }
193
bsalomond92b4192016-06-30 07:59:23 -0700194 if (fMeshes[0].fLocalCoords.isEmpty() != that->fMeshes[0].fLocalCoords.isEmpty()) {
joshualitt2771b562015-08-07 12:46:26 -0700195 return false;
196 }
197
bsalomon14eaaa62015-09-24 07:01:26 -0700198 if (!fVariableColor) {
bsalomond92b4192016-06-30 07:59:23 -0700199 if (that->fVariableColor || that->fMeshes[0].fColor != fMeshes[0].fColor) {
bsalomon14eaaa62015-09-24 07:01:26 -0700200 fVariableColor = true;
201 }
joshualitt2771b562015-08-07 12:46:26 -0700202 }
203
bsalomond92b4192016-06-30 07:59:23 -0700204 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700205 fVertexCount += that->fVertexCount;
206 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700207
bsalomon88cf17d2016-07-08 06:40:56 -0700208 this->joinBounds(*that);
joshualitt2771b562015-08-07 12:46:26 -0700209 return true;
210}
211
212///////////////////////////////////////////////////////////////////////////////////////////////////
213
214#ifdef GR_TEST_UTILS
215
Brian Salomon5ec9def2016-12-20 15:34:05 -0500216#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700217
218static uint32_t seed_vertices(GrPrimitiveType type) {
219 switch (type) {
220 case kTriangles_GrPrimitiveType:
221 case kTriangleStrip_GrPrimitiveType:
222 case kTriangleFan_GrPrimitiveType:
223 return 3;
224 case kPoints_GrPrimitiveType:
225 return 1;
226 case kLines_GrPrimitiveType:
227 case kLineStrip_GrPrimitiveType:
228 return 2;
229 }
230 SkFAIL("Incomplete switch\n");
231 return 0;
232}
233
234static uint32_t primitive_vertices(GrPrimitiveType type) {
235 switch (type) {
236 case kTriangles_GrPrimitiveType:
237 return 3;
238 case kLines_GrPrimitiveType:
239 return 2;
240 case kTriangleStrip_GrPrimitiveType:
241 case kTriangleFan_GrPrimitiveType:
242 case kPoints_GrPrimitiveType:
243 case kLineStrip_GrPrimitiveType:
244 return 1;
245 }
246 SkFAIL("Incomplete switch\n");
247 return 0;
248}
249
250static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
251 SkPoint p;
252 p.fX = random->nextRangeScalar(min, max);
253 p.fY = random->nextRangeScalar(min, max);
254 return p;
255}
256
257static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500258 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700259 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomonfc527d22016-12-14 21:07:01 -0500260 SkTArray<GrColor>* colors, bool hasColors, SkTArray<uint16_t>* indices,
261 bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700262 for (uint32_t v = 0; v < count; v++) {
263 positions->push_back(random_point(random, min, max));
264 if (hasTexCoords) {
265 texCoords->push_back(random_point(random, min, max));
266 }
267 if (hasColors) {
268 colors->push_back(GrRandomColor(random));
269 }
270 if (hasIndices) {
271 SkASSERT(maxVertex <= SK_MaxU16);
272 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
273 }
274 }
275}
276
Brian Salomon5ec9def2016-12-20 15:34:05 -0500277DRAW_OP_TEST_DEFINE(VerticesOp) {
joshualitt2771b562015-08-07 12:46:26 -0700278 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
279 uint32_t primitiveCount = random->nextRangeU(1, 100);
280
281 // TODO make 'sensible' indexbuffers
282 SkTArray<SkPoint> positions;
283 SkTArray<SkPoint> texCoords;
284 SkTArray<GrColor> colors;
285 SkTArray<uint16_t> indices;
286
287 bool hasTexCoords = random->nextBool();
288 bool hasIndices = random->nextBool();
289 bool hasColors = random->nextBool();
290
291 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
292
293 static const SkScalar kMinVertExtent = -100.f;
294 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500295 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
296 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
297 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700298
299 for (uint32_t i = 1; i < primitiveCount; i++) {
300 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500301 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
302 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700303 }
304
305 SkMatrix viewMatrix = GrTest::TestMatrix(random);
306 SkRect bounds;
Brian Salomonfc527d22016-12-14 21:07:01 -0500307 SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700308 SkASSERT(result);
309
310 viewMatrix.mapRect(&bounds);
311
bsalomond92b4192016-06-30 07:59:23 -0700312 GrColor color = GrRandomColor(random);
Brian Salomonfc527d22016-12-14 21:07:01 -0500313 return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount,
314 indices.begin(), hasIndices ? vertexCount : 0, colors.begin(),
Brian Salomon5ec9def2016-12-20 15:34:05 -0500315 texCoords.begin(), bounds);
joshualitt2771b562015-08-07 12:46:26 -0700316}
317
318#endif