blob: bca7d230bcda7e5f2ed14a9a2f802f54a11ab5ee [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
8#include "GrDrawVerticesBatch.h"
9
bsalomon75398562015-08-17 12:55:38 -070010#include "GrBatchFlushState.h"
joshualitt2771b562015-08-07 12:46:26 -070011#include "GrInvariantOutput.h"
12#include "GrDefaultGeoProcFactory.h"
13
14static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
15 bool hasColors,
16 int* colorOffset,
17 int* texOffset,
18 GrColor color,
19 const SkMatrix& viewMatrix,
20 bool coverageIgnored) {
21 using namespace GrDefaultGeoProcFactory;
22 *texOffset = -1;
23 *colorOffset = -1;
24 Color gpColor(color);
25 if (hasColors) {
26 gpColor.fType = Color::kAttribute_Type;
27 }
28
29 Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
30 LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type :
31 LocalCoords::kUsePosition_Type);
32 if (hasLocalCoords && hasColors) {
33 *colorOffset = sizeof(SkPoint);
34 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
35 } else if (hasLocalCoords) {
36 *texOffset = sizeof(SkPoint);
37 } else if (hasColors) {
38 *colorOffset = sizeof(SkPoint);
39 }
40 return GrDefaultGeoProcFactory::Create(gpColor, coverage, localCoords, viewMatrix);
41}
42
43GrDrawVerticesBatch::GrDrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
44 const SkMatrix& viewMatrix,
45 const SkPoint* positions, int vertexCount,
46 const uint16_t* indices, int indexCount,
47 const GrColor* colors, const SkPoint* localCoords,
48 const SkRect& bounds) {
49 this->initClassID<GrDrawVerticesBatch>();
50 SkASSERT(positions);
51
52 fBatch.fViewMatrix = viewMatrix;
53 Geometry& installedGeo = fGeoData.push_back(geometry);
54
55 installedGeo.fPositions.append(vertexCount, positions);
56 if (indices) {
57 installedGeo.fIndices.append(indexCount, indices);
58 fBatch.fHasIndices = true;
59 } else {
60 fBatch.fHasIndices = false;
61 }
62
63 if (colors) {
64 installedGeo.fColors.append(vertexCount, colors);
65 fBatch.fHasColors = true;
66 } else {
67 fBatch.fHasColors = false;
68 }
69
70 if (localCoords) {
71 installedGeo.fLocalCoords.append(vertexCount, localCoords);
72 fBatch.fHasLocalCoords = true;
73 } else {
74 fBatch.fHasLocalCoords = false;
75 }
76 fBatch.fVertexCount = vertexCount;
77 fBatch.fIndexCount = indexCount;
78 fBatch.fPrimitiveType = primitiveType;
79
80 this->setBounds(bounds);
81}
82
83void GrDrawVerticesBatch::getInvariantOutputColor(GrInitInvariantOutput* out) const {
84 // When this is called on a batch, there is only one geometry bundle
85 if (this->hasColors()) {
86 out->setUnknownFourComponents();
87 } else {
88 out->setKnownFourComponents(fGeoData[0].fColor);
89 }
90}
91
92void GrDrawVerticesBatch::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
93 out->setKnownSingleComponent(0xff);
94}
95
bsalomon91d844d2015-08-10 10:47:29 -070096void GrDrawVerticesBatch::initBatchTracker(const GrPipelineOptimizations& opt) {
joshualitt2771b562015-08-07 12:46:26 -070097 // Handle any color overrides
bsalomon91d844d2015-08-10 10:47:29 -070098 if (!opt.readsColor()) {
joshualitt2771b562015-08-07 12:46:26 -070099 fGeoData[0].fColor = GrColor_ILLEGAL;
100 }
bsalomon91d844d2015-08-10 10:47:29 -0700101 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt2771b562015-08-07 12:46:26 -0700102
103 // setup batch properties
bsalomon91d844d2015-08-10 10:47:29 -0700104 fBatch.fColorIgnored = !opt.readsColor();
joshualitt2771b562015-08-07 12:46:26 -0700105 fBatch.fColor = fGeoData[0].fColor;
bsalomon91d844d2015-08-10 10:47:29 -0700106 fBatch.fUsesLocalCoords = opt.readsLocalCoords();
107 fBatch.fCoverageIgnored = !opt.readsCoverage();
joshualitt2771b562015-08-07 12:46:26 -0700108}
109
bsalomon75398562015-08-17 12:55:38 -0700110void GrDrawVerticesBatch::onPrepareDraws(Target* target) {
joshualitt2771b562015-08-07 12:46:26 -0700111 int colorOffset = -1, texOffset = -1;
112 SkAutoTUnref<const GrGeometryProcessor> gp(
113 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
114 &texOffset, this->color(), this->viewMatrix(),
115 this->coverageIgnored()));
116
bsalomon75398562015-08-17 12:55:38 -0700117 target->initDraw(gp, this->pipeline());
joshualitt2771b562015-08-07 12:46:26 -0700118
119 size_t vertexStride = gp->getVertexStride();
120
121 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
122 + (this->hasColors() ? sizeof(GrColor) : 0));
123
124 int instanceCount = fGeoData.count();
125
126 const GrVertexBuffer* vertexBuffer;
127 int firstVertex;
128
bsalomon75398562015-08-17 12:55:38 -0700129 void* verts = target->makeVertexSpace(vertexStride, this->vertexCount(),
130 &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700131
132 if (!verts) {
133 SkDebugf("Could not allocate vertices\n");
134 return;
135 }
136
137 const GrIndexBuffer* indexBuffer = NULL;
138 int firstIndex = 0;
139
140 uint16_t* indices = NULL;
141 if (this->hasIndices()) {
bsalomon75398562015-08-17 12:55:38 -0700142 indices = target->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700143
144 if (!indices) {
145 SkDebugf("Could not allocate indices\n");
146 return;
147 }
148 }
149
150 int indexOffset = 0;
151 int vertexOffset = 0;
152 for (int i = 0; i < instanceCount; i++) {
153 const Geometry& args = fGeoData[i];
154
155 // TODO we can actually cache this interleaved and then just memcopy
156 if (this->hasIndices()) {
157 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
158 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
159 }
160 }
161
162 for (int j = 0; j < args.fPositions.count(); ++j) {
163 *((SkPoint*)verts) = args.fPositions[j];
164 if (this->hasColors()) {
165 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
166 }
167 if (this->hasLocalCoords()) {
168 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
169 }
170 verts = (void*)((intptr_t)verts + vertexStride);
171 vertexOffset++;
172 }
173 }
174
175 GrVertices vertices;
176 if (this->hasIndices()) {
177 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
178 firstIndex, this->vertexCount(), this->indexCount());
179
180 } else {
181 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
182 }
bsalomon75398562015-08-17 12:55:38 -0700183 target->draw(vertices);
joshualitt2771b562015-08-07 12:46:26 -0700184}
185
bsalomoncb02b382015-08-12 11:14:50 -0700186bool GrDrawVerticesBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
bsalomonabd30f52015-08-13 13:34:48 -0700187 GrDrawVerticesBatch* that = t->cast<GrDrawVerticesBatch>();
188
189 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
190 that->bounds(), caps)) {
joshualitt2771b562015-08-07 12:46:26 -0700191 return false;
192 }
193
joshualitt2771b562015-08-07 12:46:26 -0700194 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
195 return false;
196 }
197
198 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
199
200 // We currently use a uniform viewmatrix for this batch
201 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
202 return false;
203 }
204
205 if (this->hasColors() != that->hasColors()) {
206 return false;
207 }
208
209 if (this->hasIndices() != that->hasIndices()) {
210 return false;
211 }
212
213 if (this->hasLocalCoords() != that->hasLocalCoords()) {
214 return false;
215 }
216
217 if (!this->hasColors() && this->color() != that->color()) {
218 return false;
219 }
220
221 if (this->color() != that->color()) {
222 fBatch.fColor = GrColor_ILLEGAL;
223 }
224 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
225 fBatch.fVertexCount += that->vertexCount();
226 fBatch.fIndexCount += that->indexCount();
227
228 this->joinBounds(that->bounds());
229 return true;
230}
231
232///////////////////////////////////////////////////////////////////////////////////////////////////
233
234#ifdef GR_TEST_UTILS
235
236#include "GrBatchTest.h"
237
238static uint32_t seed_vertices(GrPrimitiveType type) {
239 switch (type) {
240 case kTriangles_GrPrimitiveType:
241 case kTriangleStrip_GrPrimitiveType:
242 case kTriangleFan_GrPrimitiveType:
243 return 3;
244 case kPoints_GrPrimitiveType:
245 return 1;
246 case kLines_GrPrimitiveType:
247 case kLineStrip_GrPrimitiveType:
248 return 2;
249 }
250 SkFAIL("Incomplete switch\n");
251 return 0;
252}
253
254static uint32_t primitive_vertices(GrPrimitiveType type) {
255 switch (type) {
256 case kTriangles_GrPrimitiveType:
257 return 3;
258 case kLines_GrPrimitiveType:
259 return 2;
260 case kTriangleStrip_GrPrimitiveType:
261 case kTriangleFan_GrPrimitiveType:
262 case kPoints_GrPrimitiveType:
263 case kLineStrip_GrPrimitiveType:
264 return 1;
265 }
266 SkFAIL("Incomplete switch\n");
267 return 0;
268}
269
270static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
271 SkPoint p;
272 p.fX = random->nextRangeScalar(min, max);
273 p.fY = random->nextRangeScalar(min, max);
274 return p;
275}
276
277static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
278 SkRandom* random,
279 SkTArray<SkPoint>* positions,
280 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
281 SkTArray<GrColor>* colors, bool hasColors,
282 SkTArray<uint16_t>* indices, bool hasIndices) {
283 for (uint32_t v = 0; v < count; v++) {
284 positions->push_back(random_point(random, min, max));
285 if (hasTexCoords) {
286 texCoords->push_back(random_point(random, min, max));
287 }
288 if (hasColors) {
289 colors->push_back(GrRandomColor(random));
290 }
291 if (hasIndices) {
292 SkASSERT(maxVertex <= SK_MaxU16);
293 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
294 }
295 }
296}
297
bsalomonabd30f52015-08-13 13:34:48 -0700298DRAW_BATCH_TEST_DEFINE(VerticesBatch) {
joshualitt2771b562015-08-07 12:46:26 -0700299 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
300 uint32_t primitiveCount = random->nextRangeU(1, 100);
301
302 // TODO make 'sensible' indexbuffers
303 SkTArray<SkPoint> positions;
304 SkTArray<SkPoint> texCoords;
305 SkTArray<GrColor> colors;
306 SkTArray<uint16_t> indices;
307
308 bool hasTexCoords = random->nextBool();
309 bool hasIndices = random->nextBool();
310 bool hasColors = random->nextBool();
311
312 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
313
314 static const SkScalar kMinVertExtent = -100.f;
315 static const SkScalar kMaxVertExtent = 100.f;
316 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
317 random,
318 &positions,
319 &texCoords, hasTexCoords,
320 &colors, hasColors,
321 &indices, hasIndices);
322
323 for (uint32_t i = 1; i < primitiveCount; i++) {
324 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
325 random,
326 &positions,
327 &texCoords, hasTexCoords,
328 &colors, hasColors,
329 &indices, hasIndices);
330 }
331
332 SkMatrix viewMatrix = GrTest::TestMatrix(random);
333 SkRect bounds;
334 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
335 SkASSERT(result);
336
337 viewMatrix.mapRect(&bounds);
338
339 GrDrawVerticesBatch::Geometry geometry;
340 geometry.fColor = GrRandomColor(random);
341 return GrDrawVerticesBatch::Create(geometry, type, viewMatrix,
342 positions.begin(), vertexCount,
343 indices.begin(), hasIndices ? vertexCount : 0,
344 colors.begin(),
345 texCoords.begin(),
346 bounds);
347}
348
349#endif