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