blob: ed2c072b0350e473b502f50a2e6aa3c28201633a [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,
Brian Salomon8c852be2017-01-04 10:44:42 -050017 const SkMatrix& viewMatrix) {
joshualitt2771b562015-08-07 12:46:26 -070018 using namespace GrDefaultGeoProcFactory;
19 *texOffset = -1;
20 *colorOffset = -1;
joshualitt2771b562015-08-07 12:46:26 -070021
Brian Salomon8c852be2017-01-04 10:44:42 -050022 LocalCoords::Type localCoordsType =
23 hasLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUsePosition_Type;
bsalomon14eaaa62015-09-24 07:01:26 -070024 *colorOffset = sizeof(SkPoint);
25 if (hasLocalCoords) {
joshualitt2771b562015-08-07 12:46:26 -070026 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
joshualitt2771b562015-08-07 12:46:26 -070027 }
Brian Salomon8c852be2017-01-04 10:44:42 -050028 return GrDefaultGeoProcFactory::Make(Color::kAttribute_Type, Coverage::kSolid_Type,
29 localCoordsType, viewMatrix);
joshualitt2771b562015-08-07 12:46:26 -070030}
31
Brian Salomonfc527d22016-12-14 21:07:01 -050032GrDrawVerticesOp::GrDrawVerticesOp(GrColor color, GrPrimitiveType primitiveType,
33 const SkMatrix& viewMatrix, const SkPoint* positions,
34 int vertexCount, const uint16_t* indices, int indexCount,
35 const GrColor* colors, const SkPoint* localCoords,
36 const SkRect& bounds)
37 : INHERITED(ClassID()) {
joshualitt2771b562015-08-07 12:46:26 -070038 SkASSERT(positions);
39
bsalomon14eaaa62015-09-24 07:01:26 -070040 fViewMatrix = viewMatrix;
bsalomond92b4192016-06-30 07:59:23 -070041 Mesh& mesh = fMeshes.push_back();
42 mesh.fColor = color;
joshualitt2771b562015-08-07 12:46:26 -070043
bsalomond92b4192016-06-30 07:59:23 -070044 mesh.fPositions.append(vertexCount, positions);
joshualitt2771b562015-08-07 12:46:26 -070045 if (indices) {
bsalomond92b4192016-06-30 07:59:23 -070046 mesh.fIndices.append(indexCount, indices);
joshualitt2771b562015-08-07 12:46:26 -070047 }
48
49 if (colors) {
bsalomon14eaaa62015-09-24 07:01:26 -070050 fVariableColor = true;
bsalomond92b4192016-06-30 07:59:23 -070051 mesh.fColors.append(vertexCount, colors);
joshualitt2771b562015-08-07 12:46:26 -070052 } else {
bsalomon14eaaa62015-09-24 07:01:26 -070053 fVariableColor = false;
joshualitt2771b562015-08-07 12:46:26 -070054 }
55
56 if (localCoords) {
bsalomond92b4192016-06-30 07:59:23 -070057 mesh.fLocalCoords.append(vertexCount, localCoords);
joshualitt2771b562015-08-07 12:46:26 -070058 }
bsalomon14eaaa62015-09-24 07:01:26 -070059 fVertexCount = vertexCount;
60 fIndexCount = indexCount;
61 fPrimitiveType = primitiveType;
joshualitt2771b562015-08-07 12:46:26 -070062
bsalomon88cf17d2016-07-08 06:40:56 -070063 IsZeroArea zeroArea;
64 if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) {
65 zeroArea = IsZeroArea::kYes;
66 } else {
67 zeroArea = IsZeroArea::kNo;
68 }
69 this->setBounds(bounds, HasAABloat::kNo, zeroArea);
joshualitt2771b562015-08-07 12:46:26 -070070}
71
Brian Salomon92aee3d2016-12-21 09:20:25 -050072void GrDrawVerticesOp::getPipelineAnalysisInput(GrPipelineAnalysisDrawOpInput* input) const {
bsalomon14eaaa62015-09-24 07:01:26 -070073 if (fVariableColor) {
Brian Salomon92aee3d2016-12-21 09:20:25 -050074 input->pipelineColorInput()->setUnknownFourComponents();
joshualitt2771b562015-08-07 12:46:26 -070075 } else {
Brian Salomon92aee3d2016-12-21 09:20:25 -050076 input->pipelineColorInput()->setKnownFourComponents(fMeshes[0].fColor);
joshualitt2771b562015-08-07 12:46:26 -070077 }
Brian Salomon92aee3d2016-12-21 09:20:25 -050078 input->pipelineCoverageInput()->setKnownSingleComponent(0xff);
joshualitt2771b562015-08-07 12:46:26 -070079}
80
Brian Salomon92aee3d2016-12-21 09:20:25 -050081void GrDrawVerticesOp::applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) {
bsalomond92b4192016-06-30 07:59:23 -070082 SkASSERT(fMeshes.count() == 1);
bsalomon14eaaa62015-09-24 07:01:26 -070083 GrColor overrideColor;
Brian Salomon92aee3d2016-12-21 09:20:25 -050084 if (optimizations.getOverrideColorIfSet(&overrideColor)) {
bsalomond92b4192016-06-30 07:59:23 -070085 fMeshes[0].fColor = overrideColor;
86 fMeshes[0].fColors.reset();
bsalomon14eaaa62015-09-24 07:01:26 -070087 fVariableColor = false;
joshualitt2771b562015-08-07 12:46:26 -070088 }
Brian Salomon92aee3d2016-12-21 09:20:25 -050089 if (!optimizations.readsLocalCoords()) {
bsalomond92b4192016-06-30 07:59:23 -070090 fMeshes[0].fLocalCoords.reset();
bsalomon14eaaa62015-09-24 07:01:26 -070091 }
joshualitt2771b562015-08-07 12:46:26 -070092}
93
Brian Salomonfc527d22016-12-14 21:07:01 -050094void GrDrawVerticesOp::onPrepareDraws(Target* target) const {
bsalomond92b4192016-06-30 07:59:23 -070095 bool hasLocalCoords = !fMeshes[0].fLocalCoords.isEmpty();
joshualitt2771b562015-08-07 12:46:26 -070096 int colorOffset = -1, texOffset = -1;
Brian Salomon8c852be2017-01-04 10:44:42 -050097 sk_sp<GrGeometryProcessor> gp(
98 set_vertex_attributes(hasLocalCoords, &colorOffset, &texOffset, fViewMatrix));
joshualitt2771b562015-08-07 12:46:26 -070099 size_t vertexStride = gp->getVertexStride();
100
Brian Salomonfc527d22016-12-14 21:07:01 -0500101 SkASSERT(vertexStride ==
102 sizeof(SkPoint) + (hasLocalCoords ? sizeof(SkPoint) : 0) + sizeof(GrColor));
joshualitt2771b562015-08-07 12:46:26 -0700103
bsalomond92b4192016-06-30 07:59:23 -0700104 int instanceCount = fMeshes.count();
joshualitt2771b562015-08-07 12:46:26 -0700105
cdalton397536c2016-03-25 12:15:03 -0700106 const GrBuffer* vertexBuffer;
joshualitt2771b562015-08-07 12:46:26 -0700107 int firstVertex;
108
bsalomon14eaaa62015-09-24 07:01:26 -0700109 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
joshualitt2771b562015-08-07 12:46:26 -0700110
111 if (!verts) {
112 SkDebugf("Could not allocate vertices\n");
113 return;
114 }
115
cdalton397536c2016-03-25 12:15:03 -0700116 const GrBuffer* indexBuffer = nullptr;
joshualitt2771b562015-08-07 12:46:26 -0700117 int firstIndex = 0;
118
halcanary96fcdcc2015-08-27 07:41:13 -0700119 uint16_t* indices = nullptr;
bsalomond92b4192016-06-30 07:59:23 -0700120 if (!fMeshes[0].fIndices.isEmpty()) {
bsalomon14eaaa62015-09-24 07:01:26 -0700121 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
joshualitt2771b562015-08-07 12:46:26 -0700122
123 if (!indices) {
124 SkDebugf("Could not allocate indices\n");
125 return;
126 }
127 }
128
129 int indexOffset = 0;
130 int vertexOffset = 0;
131 for (int i = 0; i < instanceCount; i++) {
bsalomond92b4192016-06-30 07:59:23 -0700132 const Mesh& mesh = fMeshes[i];
joshualitt2771b562015-08-07 12:46:26 -0700133
134 // TODO we can actually cache this interleaved and then just memcopy
bsalomon14eaaa62015-09-24 07:01:26 -0700135 if (indices) {
bsalomond92b4192016-06-30 07:59:23 -0700136 for (int j = 0; j < mesh.fIndices.count(); ++j, ++indexOffset) {
137 *(indices + indexOffset) = mesh.fIndices[j] + vertexOffset;
joshualitt2771b562015-08-07 12:46:26 -0700138 }
139 }
140
bsalomond92b4192016-06-30 07:59:23 -0700141 for (int j = 0; j < mesh.fPositions.count(); ++j) {
142 *((SkPoint*)verts) = mesh.fPositions[j];
143 if (mesh.fColors.isEmpty()) {
144 *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColor;
bsalomon14eaaa62015-09-24 07:01:26 -0700145 } else {
bsalomond92b4192016-06-30 07:59:23 -0700146 *(GrColor*)((intptr_t)verts + colorOffset) = mesh.fColors[j];
joshualitt2771b562015-08-07 12:46:26 -0700147 }
bsalomon14eaaa62015-09-24 07:01:26 -0700148 if (hasLocalCoords) {
bsalomond92b4192016-06-30 07:59:23 -0700149 *(SkPoint*)((intptr_t)verts + texOffset) = mesh.fLocalCoords[j];
joshualitt2771b562015-08-07 12:46:26 -0700150 }
151 verts = (void*)((intptr_t)verts + vertexStride);
152 vertexOffset++;
153 }
154 }
155
egdaniel0e1853c2016-03-17 11:35:45 -0700156 GrMesh mesh;
bsalomon14eaaa62015-09-24 07:01:26 -0700157 if (indices) {
Brian Salomonfc527d22016-12-14 21:07:01 -0500158 mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, firstIndex,
159 fVertexCount, fIndexCount);
joshualitt2771b562015-08-07 12:46:26 -0700160
161 } else {
egdaniel0e1853c2016-03-17 11:35:45 -0700162 mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700163 }
bungeman06ca8ec2016-06-09 08:01:03 -0700164 target->draw(gp.get(), mesh);
joshualitt2771b562015-08-07 12:46:26 -0700165}
166
Brian Salomonfc527d22016-12-14 21:07:01 -0500167bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
168 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
bsalomonabd30f52015-08-13 13:34:48 -0700169
170 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
171 that->bounds(), caps)) {
joshualitt2771b562015-08-07 12:46:26 -0700172 return false;
173 }
174
Brian Salomon53e4c3c2016-12-21 11:38:53 -0500175 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
joshualitt2771b562015-08-07 12:46:26 -0700176 return false;
177 }
178
Brian Salomonfc527d22016-12-14 21:07:01 -0500179 // We currently use a uniform viewmatrix for this op.
bsalomon14eaaa62015-09-24 07:01:26 -0700180 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
joshualitt2771b562015-08-07 12:46:26 -0700181 return false;
182 }
183
bsalomond92b4192016-06-30 07:59:23 -0700184 if (fMeshes[0].fIndices.isEmpty() != that->fMeshes[0].fIndices.isEmpty()) {
joshualitt2771b562015-08-07 12:46:26 -0700185 return false;
186 }
187
bsalomond92b4192016-06-30 07:59:23 -0700188 if (fMeshes[0].fLocalCoords.isEmpty() != that->fMeshes[0].fLocalCoords.isEmpty()) {
joshualitt2771b562015-08-07 12:46:26 -0700189 return false;
190 }
191
bsalomon14eaaa62015-09-24 07:01:26 -0700192 if (!fVariableColor) {
bsalomond92b4192016-06-30 07:59:23 -0700193 if (that->fVariableColor || that->fMeshes[0].fColor != fMeshes[0].fColor) {
bsalomon14eaaa62015-09-24 07:01:26 -0700194 fVariableColor = true;
195 }
joshualitt2771b562015-08-07 12:46:26 -0700196 }
197
bsalomond92b4192016-06-30 07:59:23 -0700198 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
bsalomon14eaaa62015-09-24 07:01:26 -0700199 fVertexCount += that->fVertexCount;
200 fIndexCount += that->fIndexCount;
joshualitt2771b562015-08-07 12:46:26 -0700201
bsalomon88cf17d2016-07-08 06:40:56 -0700202 this->joinBounds(*that);
joshualitt2771b562015-08-07 12:46:26 -0700203 return true;
204}
205
206///////////////////////////////////////////////////////////////////////////////////////////////////
207
208#ifdef GR_TEST_UTILS
209
Brian Salomon5ec9def2016-12-20 15:34:05 -0500210#include "GrDrawOpTest.h"
joshualitt2771b562015-08-07 12:46:26 -0700211
212static uint32_t seed_vertices(GrPrimitiveType type) {
213 switch (type) {
214 case kTriangles_GrPrimitiveType:
215 case kTriangleStrip_GrPrimitiveType:
216 case kTriangleFan_GrPrimitiveType:
217 return 3;
218 case kPoints_GrPrimitiveType:
219 return 1;
220 case kLines_GrPrimitiveType:
221 case kLineStrip_GrPrimitiveType:
222 return 2;
223 }
224 SkFAIL("Incomplete switch\n");
225 return 0;
226}
227
228static uint32_t primitive_vertices(GrPrimitiveType type) {
229 switch (type) {
230 case kTriangles_GrPrimitiveType:
231 return 3;
232 case kLines_GrPrimitiveType:
233 return 2;
234 case kTriangleStrip_GrPrimitiveType:
235 case kTriangleFan_GrPrimitiveType:
236 case kPoints_GrPrimitiveType:
237 case kLineStrip_GrPrimitiveType:
238 return 1;
239 }
240 SkFAIL("Incomplete switch\n");
241 return 0;
242}
243
244static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
245 SkPoint p;
246 p.fX = random->nextRangeScalar(min, max);
247 p.fY = random->nextRangeScalar(min, max);
248 return p;
249}
250
251static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
Brian Salomonfc527d22016-12-14 21:07:01 -0500252 SkRandom* random, SkTArray<SkPoint>* positions,
joshualitt2771b562015-08-07 12:46:26 -0700253 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
Brian Salomonfc527d22016-12-14 21:07:01 -0500254 SkTArray<GrColor>* colors, bool hasColors, SkTArray<uint16_t>* indices,
255 bool hasIndices) {
joshualitt2771b562015-08-07 12:46:26 -0700256 for (uint32_t v = 0; v < count; v++) {
257 positions->push_back(random_point(random, min, max));
258 if (hasTexCoords) {
259 texCoords->push_back(random_point(random, min, max));
260 }
261 if (hasColors) {
262 colors->push_back(GrRandomColor(random));
263 }
264 if (hasIndices) {
265 SkASSERT(maxVertex <= SK_MaxU16);
266 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
267 }
268 }
269}
270
Brian Salomon5ec9def2016-12-20 15:34:05 -0500271DRAW_OP_TEST_DEFINE(VerticesOp) {
joshualitt2771b562015-08-07 12:46:26 -0700272 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
273 uint32_t primitiveCount = random->nextRangeU(1, 100);
274
275 // TODO make 'sensible' indexbuffers
276 SkTArray<SkPoint> positions;
277 SkTArray<SkPoint> texCoords;
278 SkTArray<GrColor> colors;
279 SkTArray<uint16_t> indices;
280
281 bool hasTexCoords = random->nextBool();
282 bool hasIndices = random->nextBool();
283 bool hasColors = random->nextBool();
284
285 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
286
287 static const SkScalar kMinVertExtent = -100.f;
288 static const SkScalar kMaxVertExtent = 100.f;
Brian Salomonfc527d22016-12-14 21:07:01 -0500289 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
290 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
291 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700292
293 for (uint32_t i = 1; i < primitiveCount; i++) {
294 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
Brian Salomonfc527d22016-12-14 21:07:01 -0500295 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
296 hasIndices);
joshualitt2771b562015-08-07 12:46:26 -0700297 }
298
299 SkMatrix viewMatrix = GrTest::TestMatrix(random);
300 SkRect bounds;
Brian Salomonfc527d22016-12-14 21:07:01 -0500301 SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount);
joshualitt2771b562015-08-07 12:46:26 -0700302 SkASSERT(result);
303
304 viewMatrix.mapRect(&bounds);
305
bsalomond92b4192016-06-30 07:59:23 -0700306 GrColor color = GrRandomColor(random);
Brian Salomonfc527d22016-12-14 21:07:01 -0500307 return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount,
308 indices.begin(), hasIndices ? vertexCount : 0, colors.begin(),
Brian Salomon5ec9def2016-12-20 15:34:05 -0500309 texCoords.begin(), bounds);
joshualitt2771b562015-08-07 12:46:26 -0700310}
311
312#endif