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 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 108 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 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 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 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 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 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 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 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