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 13 std::unique_ptr<GrMeshDrawOp> GrDrawVerticesOp::Make( 14 GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, 15 const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount, 16 const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds, 17 GrRenderTargetContext::ColorArrayType colorArrayType) { 18 static constexpr SkCanvas::VertexMode kIgnoredMode = SkCanvas::kTriangles_VertexMode; 19 SkASSERT(positions); 20 if (!colors) { 21 // When we tessellate we will fill a color array with the GrColor value passed above as 22 // 'color'. 23 colorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; 24 } 25 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions, 26 localCoords, colors, indexCount, indices); 27 if (!vertices) { 28 return nullptr; 29 } 30 return std::unique_ptr<GrMeshDrawOp>(new GrDrawVerticesOp(std::move(vertices), primitiveType, 31 color, colorArrayType, viewMatrix)); 32 } 33 34 std::unique_ptr<GrMeshDrawOp> GrDrawVerticesOp::Make(GrColor color, sk_sp<SkVertices> vertices, 35 const SkMatrix& viewMatrix) { 36 SkASSERT(vertices); 37 GrPrimitiveType primType = SkVertexModeToGrPrimitiveType(vertices->mode()); 38 return std::unique_ptr<GrMeshDrawOp>(new GrDrawVerticesOp( 39 std::move(vertices), primType, color, GrRenderTargetContext::ColorArrayType::kSkColor, 40 viewMatrix)); 41 } 42 43 GrDrawVerticesOp::GrDrawVerticesOp(sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType, 44 GrColor color, 45 GrRenderTargetContext::ColorArrayType colorArrayType, 46 const SkMatrix& viewMatrix, uint32_t flags) 47 : INHERITED(ClassID()), fColorArrayType(colorArrayType) { 48 SkASSERT(vertices); 49 50 fVertexCount = vertices->vertexCount(); 51 fIndexCount = vertices->indexCount(); 52 fPrimitiveType = primitiveType; 53 54 Mesh& mesh = fMeshes.push_back(); 55 mesh.fColor = color; 56 mesh.fViewMatrix = viewMatrix; 57 mesh.fVertices = std::move(vertices); 58 mesh.fFlags = flags; 59 60 fFlags = 0; 61 if (mesh.hasPerVertexColors()) { 62 fFlags |= kRequiresPerVertexColors_Flag; 63 } 64 if (mesh.hasExplicitLocalCoords()) { 65 fFlags |= kAnyMeshHasExplicitLocalCoords; 66 } 67 68 IsZeroArea zeroArea; 69 if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) { 70 zeroArea = IsZeroArea::kYes; 71 } else { 72 zeroArea = IsZeroArea::kNo; 73 } 74 this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, HasAABloat::kNo, zeroArea); 75 } 76 77 void GrDrawVerticesOp::getFragmentProcessorAnalysisInputs( 78 GrPipelineAnalysisColor* color, GrPipelineAnalysisCoverage* coverage) const { 79 if (this->requiresPerVertexColors()) { 80 color->setToUnknown(); 81 } else { 82 color->setToConstant(fMeshes[0].fColor); 83 } 84 *coverage = GrPipelineAnalysisCoverage::kNone; 85 } 86 87 void GrDrawVerticesOp::applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) { 88 SkASSERT(fMeshes.count() == 1); 89 GrColor overrideColor; 90 if (optimizations.getOverrideColorIfSet(&overrideColor)) { 91 fMeshes[0].fColor = overrideColor; 92 fMeshes[0].fFlags |= kIgnoreColors_VerticesFlag; 93 fFlags &= ~kRequiresPerVertexColors_Flag; 94 fColorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; 95 } 96 if (optimizations.readsLocalCoords()) { 97 fFlags |= kPipelineRequiresLocalCoords_Flag; 98 } else { 99 fFlags |= kIgnoreTexCoords_VerticesFlag; 100 fFlags &= ~kAnyMeshHasExplicitLocalCoords; 101 } 102 } 103 104 sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute, 105 bool* hasLocalCoordAttribute) const { 106 using namespace GrDefaultGeoProcFactory; 107 LocalCoords::Type localCoordsType; 108 if (this->pipelineRequiresLocalCoords()) { 109 // If we have multiple view matrices we will transform the positions into device space. We 110 // must then also provide untransformed positions as local coords. 111 if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) { 112 *hasLocalCoordAttribute = true; 113 localCoordsType = LocalCoords::kHasExplicit_Type; 114 } else { 115 *hasLocalCoordAttribute = false; 116 localCoordsType = LocalCoords::kUsePosition_Type; 117 } 118 } else { 119 localCoordsType = LocalCoords::kUnused_Type; 120 *hasLocalCoordAttribute = false; 121 } 122 123 Color color(fMeshes[0].fColor); 124 if (this->requiresPerVertexColors()) { 125 color.fType = (fColorArrayType == GrRenderTargetContext::ColorArrayType::kPremulGrColor) 126 ? Color::kPremulGrColorAttribute_Type 127 : Color::kUnpremulSkColorAttribute_Type; 128 *hasColorAttribute = true; 129 } else { 130 *hasColorAttribute = false; 131 }; 132 const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix; 133 return GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, vm); 134 } 135 136 void GrDrawVerticesOp::onPrepareDraws(Target* target) const { 137 bool hasColorAttribute; 138 bool hasLocalCoordsAttribute; 139 sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute); 140 size_t vertexStride = gp->getVertexStride(); 141 142 SkASSERT(vertexStride == sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) + 143 (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0)); 144 145 int instanceCount = fMeshes.count(); 146 147 const GrBuffer* vertexBuffer; 148 int firstVertex; 149 150 void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex); 151 152 if (!verts) { 153 SkDebugf("Could not allocate vertices\n"); 154 return; 155 } 156 157 const GrBuffer* indexBuffer = nullptr; 158 int firstIndex = 0; 159 160 uint16_t* indices = nullptr; 161 if (this->isIndexed()) { 162 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); 163 164 if (!indices) { 165 SkDebugf("Could not allocate indices\n"); 166 return; 167 } 168 } 169 170 int vertexOffset = 0; 171 // We have a fast case below for uploading the vertex data when the matrix is translate 172 // only and there are colors but not local coords. 173 bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute; 174 for (int i = 0; i < instanceCount; i++) { 175 const Mesh& mesh = fMeshes[i]; 176 if (indices) { 177 int indexCount = mesh.fVertices->indexCount(); 178 for (int j = 0; j < indexCount; ++j) { 179 *indices++ = mesh.fVertices->indices()[j] + vertexOffset; 180 } 181 } 182 int vertexCount = mesh.fVertices->vertexCount(); 183 const SkPoint* positions = mesh.fVertices->positions(); 184 const SkColor* colors = mesh.fVertices->colors(); 185 const SkPoint* localCoords = mesh.fVertices->texCoords(); 186 bool fastMesh = (!this->hasMultipleViewMatrices() || 187 mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) && 188 mesh.hasPerVertexColors(); 189 if (fastAttrs && fastMesh) { 190 struct V { 191 SkPoint fPos; 192 uint32_t fColor; 193 }; 194 SkASSERT(sizeof(V) == vertexStride); 195 V* v = (V*)verts; 196 Sk2f t(0, 0); 197 if (this->hasMultipleViewMatrices()) { 198 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY()); 199 } 200 for (int j = 0; j < vertexCount; ++j) { 201 Sk2f p = Sk2f::Load(positions++) + t; 202 p.store(&v[j].fPos); 203 v[j].fColor = colors[j]; 204 } 205 verts = v + vertexCount; 206 } else { 207 static constexpr size_t kColorOffset = sizeof(SkPoint); 208 size_t localCoordOffset = 209 hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset; 210 211 for (int j = 0; j < vertexCount; ++j) { 212 if (this->hasMultipleViewMatrices()) { 213 mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1); 214 } else { 215 *((SkPoint*)verts) = positions[j]; 216 } 217 if (hasColorAttribute) { 218 if (mesh.hasPerVertexColors()) { 219 *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j]; 220 } else { 221 *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor; 222 } 223 } 224 if (hasLocalCoordsAttribute) { 225 if (mesh.hasExplicitLocalCoords()) { 226 *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j]; 227 } else { 228 *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j]; 229 } 230 } 231 verts = (void*)((intptr_t)verts + vertexStride); 232 } 233 } 234 vertexOffset += vertexCount; 235 } 236 237 GrMesh mesh; 238 if (indices) { 239 mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, firstIndex, 240 fVertexCount, fIndexCount); 241 242 } else { 243 mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount); 244 } 245 target->draw(gp.get(), mesh); 246 } 247 248 bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { 249 GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>(); 250 251 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 252 that->bounds(), caps)) { 253 return false; 254 } 255 256 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) { 257 return false; 258 } 259 260 if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) { 261 return false; 262 } 263 264 if (fColorArrayType != that->fColorArrayType) { 265 return false; 266 } 267 268 if (fVertexCount + that->fVertexCount > SK_MaxU16) { 269 return false; 270 } 271 272 // If either op required explicit local coords or per-vertex colors the combined mesh does. Same 273 // with multiple view matrices. 274 fFlags |= that->fFlags; 275 276 if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) { 277 fFlags |= kRequiresPerVertexColors_Flag; 278 } 279 // Check whether we are about to acquire a mesh with a different view matrix. 280 if (!this->hasMultipleViewMatrices() && 281 !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) { 282 fFlags |= kHasMultipleViewMatrices_Flag; 283 } 284 285 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin()); 286 fVertexCount += that->fVertexCount; 287 fIndexCount += that->fIndexCount; 288 289 this->joinBounds(*that); 290 return true; 291 } 292 293 /////////////////////////////////////////////////////////////////////////////////////////////////// 294 295 #if GR_TEST_UTILS 296 297 #include "GrDrawOpTest.h" 298 299 static uint32_t seed_vertices(GrPrimitiveType type) { 300 switch (type) { 301 case kTriangles_GrPrimitiveType: 302 case kTriangleStrip_GrPrimitiveType: 303 case kTriangleFan_GrPrimitiveType: 304 return 3; 305 case kPoints_GrPrimitiveType: 306 return 1; 307 case kLines_GrPrimitiveType: 308 case kLineStrip_GrPrimitiveType: 309 return 2; 310 } 311 SkFAIL("Incomplete switch\n"); 312 return 0; 313 } 314 315 static uint32_t primitive_vertices(GrPrimitiveType type) { 316 switch (type) { 317 case kTriangles_GrPrimitiveType: 318 return 3; 319 case kLines_GrPrimitiveType: 320 return 2; 321 case kTriangleStrip_GrPrimitiveType: 322 case kTriangleFan_GrPrimitiveType: 323 case kPoints_GrPrimitiveType: 324 case kLineStrip_GrPrimitiveType: 325 return 1; 326 } 327 SkFAIL("Incomplete switch\n"); 328 return 0; 329 } 330 331 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { 332 SkPoint p; 333 p.fX = random->nextRangeScalar(min, max); 334 p.fY = random->nextRangeScalar(min, max); 335 return p; 336 } 337 338 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max, 339 SkRandom* random, SkTArray<SkPoint>* positions, 340 SkTArray<SkPoint>* texCoords, bool hasTexCoords, 341 SkTArray<uint32_t>* colors, bool hasColors, 342 SkTArray<uint16_t>* indices, bool hasIndices) { 343 for (uint32_t v = 0; v < count; v++) { 344 positions->push_back(random_point(random, min, max)); 345 if (hasTexCoords) { 346 texCoords->push_back(random_point(random, min, max)); 347 } 348 if (hasColors) { 349 colors->push_back(GrRandomColor(random)); 350 } 351 if (hasIndices) { 352 SkASSERT(maxVertex <= SK_MaxU16); 353 indices->push_back(random->nextULessThan((uint16_t)maxVertex)); 354 } 355 } 356 } 357 358 DRAW_OP_TEST_DEFINE(VerticesOp) { 359 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1)); 360 uint32_t primitiveCount = random->nextRangeU(1, 100); 361 362 // TODO make 'sensible' indexbuffers 363 SkTArray<SkPoint> positions; 364 SkTArray<SkPoint> texCoords; 365 SkTArray<uint32_t> colors; 366 SkTArray<uint16_t> indices; 367 368 bool hasTexCoords = random->nextBool(); 369 bool hasIndices = random->nextBool(); 370 bool hasColors = random->nextBool(); 371 372 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type); 373 374 static const SkScalar kMinVertExtent = -100.f; 375 static const SkScalar kMaxVertExtent = 100.f; 376 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random, 377 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, 378 hasIndices); 379 380 for (uint32_t i = 1; i < primitiveCount; i++) { 381 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, 382 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, 383 hasIndices); 384 } 385 386 GrRenderTargetContext::ColorArrayType colorArrayType = 387 random->nextBool() ? GrRenderTargetContext::ColorArrayType::kPremulGrColor 388 : GrRenderTargetContext::ColorArrayType::kSkColor; 389 SkMatrix viewMatrix = GrTest::TestMatrix(random); 390 SkRect bounds; 391 SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount); 392 SkASSERT(result); 393 394 GrColor color = GrRandomColor(random); 395 return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount, 396 indices.begin(), hasIndices ? indices.count() : 0, colors.begin(), 397 texCoords.begin(), bounds, colorArrayType); 398 } 399 400 #endif 401