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