• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrDrawVerticesOp.h"
9 #include "GrDefaultGeoProcFactory.h"
10 #include "GrOpFlushState.h"
11 #include "SkGr.h"
12 
Make(GrPaint && paint,sk_sp<SkVertices> vertices,const SkMatrix & viewMatrix,GrAAType aaType,bool gammaCorrect,sk_sp<GrColorSpaceXform> colorSpaceXform,GrPrimitiveType * overridePrimType)13 std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrPaint&& paint,
14                                                  sk_sp<SkVertices> vertices,
15                                                  const SkMatrix& viewMatrix,
16                                                  GrAAType aaType,
17                                                  bool gammaCorrect,
18                                                  sk_sp<GrColorSpaceXform> colorSpaceXform,
19                                                  GrPrimitiveType* overridePrimType) {
20     SkASSERT(vertices);
21     GrPrimitiveType primType = overridePrimType ? *overridePrimType
22                                                 : SkVertexModeToGrPrimitiveType(vertices->mode());
23     return Helper::FactoryHelper<GrDrawVerticesOp>(std::move(paint), std::move(vertices), primType,
24                                                    aaType, gammaCorrect, std::move(colorSpaceXform),
25                                                    viewMatrix);
26 }
27 
GrDrawVerticesOp(const Helper::MakeArgs & helperArgs,GrColor color,sk_sp<SkVertices> vertices,GrPrimitiveType primitiveType,GrAAType aaType,bool gammaCorrect,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix)28 GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
29                                    sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType,
30                                    GrAAType aaType, bool gammaCorrect,
31                                    sk_sp<GrColorSpaceXform> colorSpaceXform,
32                                    const SkMatrix& viewMatrix)
33         : INHERITED(ClassID())
34         , fHelper(helperArgs, aaType)
35         , fPrimitiveType(primitiveType)
36         , fColorSpaceXform(std::move(colorSpaceXform)) {
37     SkASSERT(vertices);
38 
39     fVertexCount = vertices->vertexCount();
40     fIndexCount = vertices->indexCount();
41     fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor
42                                             : ColorArrayType::kPremulGrColor;
43     // GrColor is linearized (and gamut converted) during paint conversion, but SkColors need to be
44     // handled in the shader
45     fLinearizeColors = gammaCorrect && vertices->hasColors();
46 
47     Mesh& mesh = fMeshes.push_back();
48     mesh.fColor = color;
49     mesh.fViewMatrix = viewMatrix;
50     mesh.fVertices = std::move(vertices);
51     mesh.fIgnoreTexCoords = false;
52     mesh.fIgnoreColors = false;
53 
54     fFlags = 0;
55     if (mesh.hasPerVertexColors()) {
56         fFlags |= kRequiresPerVertexColors_Flag;
57     }
58     if (mesh.hasExplicitLocalCoords()) {
59         fFlags |= kAnyMeshHasExplicitLocalCoords;
60     }
61 
62     IsZeroArea zeroArea;
63     if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
64         zeroArea = IsZeroArea::kYes;
65     } else {
66         zeroArea = IsZeroArea::kNo;
67     }
68     this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, HasAABloat::kNo, zeroArea);
69 }
70 
dumpInfo() const71 SkString GrDrawVerticesOp::dumpInfo() const {
72     SkString string;
73     string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", (int)fPrimitiveType,
74                    fMeshes.count(), fVertexCount, fIndexCount);
75     string += fHelper.dumpInfo();
76     string += INHERITED::dumpInfo();
77     return string;
78 }
79 
fixedFunctionFlags() const80 GrDrawOp::FixedFunctionFlags GrDrawVerticesOp::fixedFunctionFlags() const {
81     return fHelper.fixedFunctionFlags();
82 }
83 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrPixelConfigIsClamped dstIsClamped)84 GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps,
85                                                         const GrAppliedClip* clip,
86                                                         GrPixelConfigIsClamped dstIsClamped) {
87     GrProcessorAnalysisColor gpColor;
88     if (this->requiresPerVertexColors()) {
89         gpColor.setToUnknown();
90     } else {
91         gpColor.setToConstant(fMeshes.front().fColor);
92     }
93     auto result = fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
94                                                GrProcessorAnalysisCoverage::kNone, &gpColor);
95     if (gpColor.isConstant(&fMeshes.front().fColor)) {
96         fMeshes.front().fIgnoreColors = true;
97         fFlags &= ~kRequiresPerVertexColors_Flag;
98         fColorArrayType = ColorArrayType::kPremulGrColor;
99         fLinearizeColors = false;
100     }
101     if (!fHelper.usesLocalCoords()) {
102         fMeshes[0].fIgnoreTexCoords = true;
103         fFlags &= ~kAnyMeshHasExplicitLocalCoords;
104     }
105     return result;
106 }
107 
makeGP(bool * hasColorAttribute,bool * hasLocalCoordAttribute) const108 sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
109                                                     bool* hasLocalCoordAttribute) const {
110     using namespace GrDefaultGeoProcFactory;
111     LocalCoords::Type localCoordsType;
112     if (fHelper.usesLocalCoords()) {
113         // If we have multiple view matrices we will transform the positions into device space. We
114         // must then also provide untransformed positions as local coords.
115         if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
116             *hasLocalCoordAttribute = true;
117             localCoordsType = LocalCoords::kHasExplicit_Type;
118         } else {
119             *hasLocalCoordAttribute = false;
120             localCoordsType = LocalCoords::kUsePosition_Type;
121         }
122     } else {
123         localCoordsType = LocalCoords::kUnused_Type;
124         *hasLocalCoordAttribute = false;
125     }
126 
127     Color color(fMeshes[0].fColor);
128     if (this->requiresPerVertexColors()) {
129         color.fType = (fColorArrayType == ColorArrayType::kPremulGrColor)
130                               ? Color::kPremulGrColorAttribute_Type
131                               : Color::kUnpremulSkColorAttribute_Type;
132         color.fLinearize = fLinearizeColors;
133         color.fColorSpaceXform = fColorSpaceXform;
134         *hasColorAttribute = true;
135     } else {
136         *hasColorAttribute = false;
137     };
138     const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
139     return GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, vm);
140 }
141 
onPrepareDraws(Target * target)142 void GrDrawVerticesOp::onPrepareDraws(Target* target) {
143     bool hasColorAttribute;
144     bool hasLocalCoordsAttribute;
145     sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute);
146     size_t vertexStride = gp->getVertexStride();
147 
148     SkASSERT(vertexStride == sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) +
149                                      (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0));
150 
151     int instanceCount = fMeshes.count();
152 
153     const GrBuffer* vertexBuffer;
154     int firstVertex;
155 
156     void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
157 
158     if (!verts) {
159         SkDebugf("Could not allocate vertices\n");
160         return;
161     }
162 
163     const GrBuffer* indexBuffer = nullptr;
164     int firstIndex = 0;
165 
166     uint16_t* indices = nullptr;
167     if (this->isIndexed()) {
168         indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
169 
170         if (!indices) {
171             SkDebugf("Could not allocate indices\n");
172             return;
173         }
174     }
175 
176     int vertexOffset = 0;
177     // We have a fast case below for uploading the vertex data when the matrix is translate
178     // only and there are colors but not local coords.
179     bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute;
180     for (int i = 0; i < instanceCount; i++) {
181         const Mesh& mesh = fMeshes[i];
182         if (indices) {
183             int indexCount = mesh.fVertices->indexCount();
184             for (int j = 0; j < indexCount; ++j) {
185                 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
186             }
187         }
188         int vertexCount = mesh.fVertices->vertexCount();
189         const SkPoint* positions = mesh.fVertices->positions();
190         const SkColor* colors = mesh.fVertices->colors();
191         const SkPoint* localCoords = mesh.fVertices->texCoords();
192         bool fastMesh = (!this->hasMultipleViewMatrices() ||
193                          mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
194                         mesh.hasPerVertexColors();
195         if (fastAttrs && fastMesh) {
196             struct V {
197                 SkPoint fPos;
198                 uint32_t fColor;
199             };
200             SkASSERT(sizeof(V) == vertexStride);
201             V* v = (V*)verts;
202             Sk2f t(0, 0);
203             if (this->hasMultipleViewMatrices()) {
204                 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
205             }
206             for (int j = 0; j < vertexCount; ++j) {
207                 Sk2f p = Sk2f::Load(positions++) + t;
208                 p.store(&v[j].fPos);
209                 v[j].fColor = colors[j];
210             }
211             verts = v + vertexCount;
212         } else {
213             static constexpr size_t kColorOffset = sizeof(SkPoint);
214             size_t localCoordOffset =
215                     hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset;
216 
217             for (int j = 0; j < vertexCount; ++j) {
218                 if (this->hasMultipleViewMatrices()) {
219                     mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
220                 } else {
221                     *((SkPoint*)verts) = positions[j];
222                 }
223                 if (hasColorAttribute) {
224                     if (mesh.hasPerVertexColors()) {
225                         *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
226                     } else {
227                         *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
228                     }
229                 }
230                 if (hasLocalCoordsAttribute) {
231                     if (mesh.hasExplicitLocalCoords()) {
232                         *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
233                     } else {
234                         *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
235                     }
236                 }
237                 verts = (void*)((intptr_t)verts + vertexStride);
238             }
239         }
240         vertexOffset += vertexCount;
241     }
242 
243     GrMesh mesh(this->primitiveType());
244     if (!indices) {
245         mesh.setNonIndexedNonInstanced(fVertexCount);
246     } else {
247         mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1);
248     }
249     mesh.setVertexData(vertexBuffer, firstVertex);
250     target->draw(gp.get(), fHelper.makePipeline(target), mesh);
251 }
252 
onCombineIfPossible(GrOp * t,const GrCaps & caps)253 bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
254     GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
255 
256     if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
257         return false;
258     }
259 
260     if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
261         return false;
262     }
263 
264     if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
265         return false;
266     }
267 
268     if (fColorArrayType != that->fColorArrayType) {
269         return false;
270     }
271 
272     if (fLinearizeColors != that->fLinearizeColors) {
273         return false;
274     }
275 
276     if (fVertexCount + that->fVertexCount > SK_MaxU16) {
277         return false;
278     }
279 
280     // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
281     // gamut is determined by the render target context. A mis-match should be impossible.
282     SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get()));
283 
284     // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
285     // with multiple view matrices.
286     fFlags |= that->fFlags;
287 
288     if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
289         fFlags |= kRequiresPerVertexColors_Flag;
290     }
291     // Check whether we are about to acquire a mesh with a different view matrix.
292     if (!this->hasMultipleViewMatrices() &&
293         !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
294         fFlags |= kHasMultipleViewMatrices_Flag;
295     }
296 
297     fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
298     fVertexCount += that->fVertexCount;
299     fIndexCount += that->fIndexCount;
300 
301     this->joinBounds(*that);
302     return true;
303 }
304 
305 ///////////////////////////////////////////////////////////////////////////////////////////////////
306 
307 #if GR_TEST_UTILS
308 
309 #include "GrDrawOpTest.h"
310 
seed_vertices(GrPrimitiveType type)311 static uint32_t seed_vertices(GrPrimitiveType type) {
312     switch (type) {
313         case GrPrimitiveType::kTriangles:
314         case GrPrimitiveType::kTriangleStrip:
315         case GrPrimitiveType::kTriangleFan:
316             return 3;
317         case GrPrimitiveType::kPoints:
318             return 1;
319         case GrPrimitiveType::kLines:
320         case GrPrimitiveType::kLineStrip:
321             return 2;
322         case GrPrimitiveType::kLinesAdjacency:
323             return 4;
324     }
325     SK_ABORT("Incomplete switch\n");
326     return 0;
327 }
328 
primitive_vertices(GrPrimitiveType type)329 static uint32_t primitive_vertices(GrPrimitiveType type) {
330     switch (type) {
331         case GrPrimitiveType::kTriangles:
332             return 3;
333         case GrPrimitiveType::kLines:
334             return 2;
335         case GrPrimitiveType::kTriangleStrip:
336         case GrPrimitiveType::kTriangleFan:
337         case GrPrimitiveType::kPoints:
338         case GrPrimitiveType::kLineStrip:
339             return 1;
340         case GrPrimitiveType::kLinesAdjacency:
341             return 4;
342     }
343     SK_ABORT("Incomplete switch\n");
344     return 0;
345 }
346 
random_point(SkRandom * random,SkScalar min,SkScalar max)347 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
348     SkPoint p;
349     p.fX = random->nextRangeScalar(min, max);
350     p.fY = random->nextRangeScalar(min, max);
351     return p;
352 }
353 
randomize_params(size_t count,size_t maxVertex,SkScalar min,SkScalar max,SkRandom * random,SkTArray<SkPoint> * positions,SkTArray<SkPoint> * texCoords,bool hasTexCoords,SkTArray<uint32_t> * colors,bool hasColors,SkTArray<uint16_t> * indices,bool hasIndices)354 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
355                              SkRandom* random, SkTArray<SkPoint>* positions,
356                              SkTArray<SkPoint>* texCoords, bool hasTexCoords,
357                              SkTArray<uint32_t>* colors, bool hasColors,
358                              SkTArray<uint16_t>* indices, bool hasIndices) {
359     for (uint32_t v = 0; v < count; v++) {
360         positions->push_back(random_point(random, min, max));
361         if (hasTexCoords) {
362             texCoords->push_back(random_point(random, min, max));
363         }
364         if (hasColors) {
365             colors->push_back(GrRandomColor(random));
366         }
367         if (hasIndices) {
368             SkASSERT(maxVertex <= SK_MaxU16);
369             indices->push_back(random->nextULessThan((uint16_t)maxVertex));
370         }
371     }
372 }
373 
GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp)374 GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
375     GrPrimitiveType type;
376     do {
377        type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
378     } while (GrPrimTypeRequiresGeometryShaderSupport(type) &&
379              !context->caps()->shaderCaps()->geometryShaderSupport());
380 
381     uint32_t primitiveCount = random->nextRangeU(1, 100);
382 
383     // TODO make 'sensible' indexbuffers
384     SkTArray<SkPoint> positions;
385     SkTArray<SkPoint> texCoords;
386     SkTArray<uint32_t> colors;
387     SkTArray<uint16_t> indices;
388 
389     bool hasTexCoords = random->nextBool();
390     bool hasIndices = random->nextBool();
391     bool hasColors = random->nextBool();
392     bool linearizeColors = random->nextBool();
393 
394     uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
395 
396     static const SkScalar kMinVertExtent = -100.f;
397     static const SkScalar kMaxVertExtent = 100.f;
398     randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
399                      &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
400                      hasIndices);
401 
402     for (uint32_t i = 1; i < primitiveCount; i++) {
403         randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
404                          random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
405                          hasIndices);
406     }
407 
408     SkMatrix viewMatrix = GrTest::TestMatrix(random);
409 
410     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random);
411 
412     static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
413     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(),
414                                                       texCoords.begin(), colors.begin(),
415                                                       hasIndices ? indices.count() : 0,
416                                                       indices.begin());
417     GrAAType aaType = GrAAType::kNone;
418     if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
419         aaType = GrAAType::kMSAA;
420     }
421     return GrDrawVerticesOp::Make(std::move(paint), std::move(vertices), viewMatrix, aaType,
422                                   linearizeColors, std::move(colorSpaceXform), &type);
423 }
424 
425 #endif
426