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 "src/gpu/ops/DrawVerticesOp.h" 9 10#include "include/core/SkM44.h" 11#include "src/core/SkArenaAlloc.h" 12#include "src/core/SkDevice.h" 13#include "src/core/SkMatrixPriv.h" 14#include "src/core/SkVerticesPriv.h" 15#include "src/gpu/BufferWriter.h" 16#include "src/gpu/GrGeometryProcessor.h" 17#include "src/gpu/GrOpFlushState.h" 18#include "src/gpu/GrProgramInfo.h" 19#include "src/gpu/SkGr.h" 20#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h" 21#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 22#include "src/gpu/glsl/GrGLSLVarying.h" 23#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 24#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h" 25 26namespace skgpu::v1::DrawVerticesOp { 27 28namespace { 29 30enum class ColorArrayType { 31 kUnused, 32 kPremulGrColor, 33 kSkColor, 34}; 35 36enum class LocalCoordsType { 37 kUnused, 38 kUsePosition, 39 kExplicit, 40}; 41 42class VerticesGP : public GrGeometryProcessor { 43public: 44 static GrGeometryProcessor* Make(SkArenaAlloc* arena, 45 LocalCoordsType localCoordsType, 46 ColorArrayType colorArrayType, 47 const SkPMColor4f& color, 48 sk_sp<GrColorSpaceXform> colorSpaceXform, 49 const SkMatrix& viewMatrix) { 50 return arena->make([&](void* ptr) { 51 return new (ptr) VerticesGP(localCoordsType, colorArrayType, color, 52 std::move(colorSpaceXform), viewMatrix); 53 }); 54 } 55 56 const char* name() const override { return "VerticesGP"; } 57 58 SkString getShaderDfxInfo() const override { 59 SkString format; 60 format.printf("ShaderDfx_VerticesGP_%d_%d_%d_%d_%d", 61 fColorArrayType, GrColorSpaceXform::XformKey(fColorSpaceXform.get()), 62 fViewMatrix.isIdentity(), fViewMatrix.isScaleTranslate(), fViewMatrix.hasPerspective()); 63 return format; 64 } 65 66 const Attribute& positionAttr() const { return fAttributes[kPositionIndex]; } 67 const Attribute& colorAttr() const { return fAttributes[kColorIndex]; } 68 const Attribute& localCoordsAttr() const { return fAttributes[kLocalCoordsIndex]; } 69 70 void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 71 uint32_t key = 0; 72 key |= (fColorArrayType == ColorArrayType::kSkColor) ? 0x1 : 0; 73 key |= ProgramImpl::ComputeMatrixKey(caps, fViewMatrix) << 20; 74 b->add32(key); 75 b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get())); 76 } 77 78 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override { 79 return std::make_unique<Impl>(); 80 } 81 82private: 83 class Impl : public ProgramImpl { 84 public: 85 void setData(const GrGLSLProgramDataManager& pdman, 86 const GrShaderCaps& shaderCaps, 87 const GrGeometryProcessor& geomProc) override { 88 const VerticesGP& vgp = geomProc.cast<VerticesGP>(); 89 90 SetTransform(pdman, shaderCaps, fViewMatrixUniform, vgp.fViewMatrix, &fViewMatrix); 91 92 if (!vgp.colorAttr().isInitialized() && vgp.fColor != fColor) { 93 pdman.set4fv(fColorUniform, 1, vgp.fColor.vec()); 94 fColor = vgp.fColor; 95 } 96 97 fColorSpaceHelper.setData(pdman, vgp.fColorSpaceXform.get()); 98 } 99 100 private: 101 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 102 const VerticesGP& gp = args.fGeomProc.cast<VerticesGP>(); 103 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 104 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 105 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 106 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 107 108 // emit attributes 109 varyingHandler->emitAttributes(gp); 110 111 fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(), 112 kVertex_GrShaderFlag); 113 114 // Setup pass through color 115 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 116 if (gp.colorAttr().isInitialized()) { 117 GrGLSLVarying varying(kHalf4_GrSLType); 118 varyingHandler->addVarying("color", &varying); 119 vertBuilder->codeAppendf("half4 color = %s;", gp.colorAttr().name()); 120 121 // For SkColor, do a red/blue swap, possible color space conversion, and premul 122 if (gp.fColorArrayType == ColorArrayType::kSkColor) { 123 vertBuilder->codeAppend("color = color.bgra;"); 124 125 SkString xformedColor; 126 vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper); 127 vertBuilder->codeAppendf("color = %s;", xformedColor.c_str()); 128 129 vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);"); 130 } 131 132 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut()); 133 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); 134 } else { 135 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, 136 &fColorUniform); 137 } 138 139 // Setup position 140 WriteOutputPosition(vertBuilder, 141 uniformHandler, 142 *args.fShaderCaps, 143 gpArgs, 144 gp.positionAttr().name(), 145 gp.fViewMatrix, 146 &fViewMatrixUniform); 147 148 // emit transforms using either explicit local coords or positions 149 const auto& coordsAttr = gp.localCoordsAttr().isInitialized() ? gp.localCoordsAttr() 150 : gp.positionAttr(); 151 gpArgs->fLocalCoordVar = coordsAttr.asShaderVar(); 152 153 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage); 154 } 155 156 private: 157 SkMatrix fViewMatrix = SkMatrix::InvalidMatrix(); 158 SkPMColor4f fColor = SK_PMColor4fILLEGAL; 159 160 UniformHandle fViewMatrixUniform; 161 UniformHandle fColorUniform; 162 163 GrGLSLColorSpaceXformHelper fColorSpaceHelper; 164 }; 165 166 VerticesGP(LocalCoordsType localCoordsType, 167 ColorArrayType colorArrayType, 168 const SkPMColor4f& color, 169 sk_sp<GrColorSpaceXform> colorSpaceXform, 170 const SkMatrix& viewMatrix) 171 : INHERITED(kVerticesGP_ClassID) 172 , fColorArrayType(colorArrayType) 173 , fColor(color) 174 , fViewMatrix(viewMatrix) 175 , fColorSpaceXform(std::move(colorSpaceXform)) { 176 constexpr Attribute missingAttr; 177 fAttributes.push_back({"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType}); 178 fAttributes.push_back(fColorArrayType != ColorArrayType::kUnused 179 ? MakeColorAttribute("inColor", false) 180 : missingAttr); 181 fAttributes.push_back(localCoordsType == LocalCoordsType::kExplicit 182 ? Attribute{"inLocalCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType} 183 : missingAttr); 184 185 this->setVertexAttributes(fAttributes.data(), fAttributes.size()); 186 } 187 188 enum { 189 kPositionIndex = 0, 190 kColorIndex = 1, 191 kLocalCoordsIndex = 2, 192 }; 193 194 std::vector<Attribute> fAttributes; 195 ColorArrayType fColorArrayType; 196 SkPMColor4f fColor; 197 SkMatrix fViewMatrix; 198 sk_sp<GrColorSpaceXform> fColorSpaceXform; 199 200 using INHERITED = GrGeometryProcessor; 201}; 202 203class DrawVerticesOpImpl final : public GrMeshDrawOp { 204private: 205 using Helper = GrSimpleMeshDrawOpHelper; 206 207public: 208 DEFINE_OP_CLASS_ID 209 210 DrawVerticesOpImpl(GrProcessorSet*, 211 const SkPMColor4f&, 212 sk_sp<SkVertices>, 213 GrPrimitiveType, 214 GrAAType, 215 sk_sp<GrColorSpaceXform>, 216 const SkMatrixProvider&); 217 218 const char* name() const override { return "DrawVerticesOp"; } 219 220 void visitProxies(const GrVisitProxyFunc& func) const override { 221 if (fProgramInfo) { 222 fProgramInfo->visitFPProxies(func); 223 } else { 224 fHelper.visitProxies(func); 225 } 226 } 227 228 FixedFunctionFlags fixedFunctionFlags() const override; 229 230 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override; 231 232private: 233 GrProgramInfo* programInfo() override { return fProgramInfo; } 234 235 void onCreateProgramInfo(const GrCaps*, 236 SkArenaAlloc*, 237 const GrSurfaceProxyView& writeView, 238 bool usesMSAASurface, 239 GrAppliedClip&&, 240 const GrDstProxyView&, 241 GrXferBarrierFlags renderPassXferBarriers, 242 GrLoadOp colorLoadOp) override; 243 244 void onPrepareDraws(GrMeshDrawTarget*) override; 245 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; 246#if GR_TEST_UTILS 247 SkString onDumpInfo() const override; 248#endif 249 250 GrGeometryProcessor* makeGP(SkArenaAlloc*); 251 252 GrPrimitiveType primitiveType() const { return fPrimitiveType; } 253 bool combinablePrimitive() const { 254 return GrPrimitiveType::kTriangles == fPrimitiveType || 255 GrPrimitiveType::kLines == fPrimitiveType || 256 GrPrimitiveType::kPoints == fPrimitiveType; 257 } 258 259 CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps&) override; 260 261 struct Mesh { 262 SkPMColor4f fColor; // Used if this->hasPerVertexColors() is false. 263 sk_sp<SkVertices> fVertices; 264 SkMatrix fViewMatrix; 265 bool fIgnoreColors; 266 267 bool hasPerVertexColors() const { 268 return fVertices->priv().hasColors() && !fIgnoreColors; 269 } 270 }; 271 272 bool isIndexed() const { 273 // Consistency enforced in onCombineIfPossible. 274 return fMeshes[0].fVertices->priv().hasIndices(); 275 } 276 277 bool requiresPerVertexColors() const { 278 return fColorArrayType != ColorArrayType::kUnused; 279 } 280 281 bool requiresPerVertexLocalCoords() const { 282 return fLocalCoordsType == LocalCoordsType::kExplicit; 283 } 284 285 size_t vertexStride() const { 286 return sizeof(SkPoint) + 287 (this->requiresPerVertexColors() ? sizeof(uint32_t) : 0) + 288 (this->requiresPerVertexLocalCoords() ? sizeof(SkPoint) : 0); 289 } 290 291 Helper fHelper; 292 SkSTArray<1, Mesh, true> fMeshes; 293 // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore 294 // the SkVertices mode (though fPrimitiveType may have been inferred from it). 295 GrPrimitiveType fPrimitiveType; 296 int fVertexCount; 297 int fIndexCount; 298 bool fMultipleViewMatrices; 299 LocalCoordsType fLocalCoordsType; 300 ColorArrayType fColorArrayType; 301 sk_sp<GrColorSpaceXform> fColorSpaceXform; 302 303 GrSimpleMesh* fMesh = nullptr; 304 GrProgramInfo* fProgramInfo = nullptr; 305 306 using INHERITED = GrMeshDrawOp; 307}; 308 309DrawVerticesOpImpl::DrawVerticesOpImpl(GrProcessorSet* processorSet, 310 const SkPMColor4f& color, 311 sk_sp<SkVertices> vertices, 312 GrPrimitiveType primitiveType, 313 GrAAType aaType, 314 sk_sp<GrColorSpaceXform> colorSpaceXform, 315 const SkMatrixProvider& matrixProvider) 316 : INHERITED(ClassID()) 317 , fHelper(processorSet, aaType) 318 , fPrimitiveType(primitiveType) 319 , fMultipleViewMatrices(false) 320 , fColorSpaceXform(std::move(colorSpaceXform)) { 321 SkASSERT(vertices); 322 323 SkVerticesPriv info(vertices->priv()); 324 325 fVertexCount = info.vertexCount(); 326 fIndexCount = info.indexCount(); 327 fColorArrayType = info.hasColors() ? ColorArrayType::kSkColor 328 : ColorArrayType::kUnused; 329 fLocalCoordsType = info.hasTexCoords() ? LocalCoordsType::kExplicit 330 : LocalCoordsType::kUsePosition; 331 332 Mesh& mesh = fMeshes.push_back(); 333 mesh.fColor = color; 334 mesh.fViewMatrix = matrixProvider.localToDevice(); 335 mesh.fVertices = std::move(vertices); 336 mesh.fIgnoreColors = false; 337 338 IsHairline zeroArea; 339 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) { 340 zeroArea = IsHairline::kYes; 341 } else { 342 zeroArea = IsHairline::kNo; 343 } 344 345 this->setTransformedBounds(mesh.fVertices->bounds(), 346 mesh.fViewMatrix, 347 HasAABloat::kNo, 348 zeroArea); 349} 350 351#if GR_TEST_UTILS 352SkString DrawVerticesOpImpl::onDumpInfo() const { 353 return SkStringPrintf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n%s", 354 (int)fPrimitiveType, fMeshes.count(), fVertexCount, fIndexCount, 355 fHelper.dumpInfo().c_str()); 356} 357#endif 358 359GrDrawOp::FixedFunctionFlags DrawVerticesOpImpl::fixedFunctionFlags() const { 360 return fHelper.fixedFunctionFlags(); 361} 362 363GrProcessorSet::Analysis DrawVerticesOpImpl::finalize(const GrCaps& caps, 364 const GrAppliedClip* clip, 365 GrClampType clampType) { 366 GrProcessorAnalysisColor gpColor; 367 if (this->requiresPerVertexColors()) { 368 gpColor.setToUnknown(); 369 } else { 370 gpColor.setToConstant(fMeshes.front().fColor); 371 } 372 auto result = fHelper.finalizeProcessors(caps, clip, clampType, 373 GrProcessorAnalysisCoverage::kNone, &gpColor); 374 if (gpColor.isConstant(&fMeshes.front().fColor)) { 375 fMeshes.front().fIgnoreColors = true; 376 fColorArrayType = ColorArrayType::kUnused; 377 } 378 if (!fHelper.usesLocalCoords()) { 379 fLocalCoordsType = LocalCoordsType::kUnused; 380 } 381 return result; 382} 383 384GrGeometryProcessor* DrawVerticesOpImpl::makeGP(SkArenaAlloc* arena) { 385 const SkMatrix& vm = fMultipleViewMatrices ? SkMatrix::I() : fMeshes[0].fViewMatrix; 386 387 sk_sp<GrColorSpaceXform> csxform = 388 (fColorArrayType == ColorArrayType::kSkColor) ? fColorSpaceXform : nullptr; 389 390 auto gp = VerticesGP::Make(arena, fLocalCoordsType, fColorArrayType, fMeshes[0].fColor, 391 std::move(csxform), vm); 392 SkASSERT(this->vertexStride() == gp->vertexStride()); 393 return gp; 394} 395 396void DrawVerticesOpImpl::onCreateProgramInfo(const GrCaps* caps, 397 SkArenaAlloc* arena, 398 const GrSurfaceProxyView& writeView, 399 bool usesMSAASurface, 400 GrAppliedClip&& appliedClip, 401 const GrDstProxyView& dstProxyView, 402 GrXferBarrierFlags renderPassXferBarriers, 403 GrLoadOp colorLoadOp) { 404 GrGeometryProcessor* gp = this->makeGP(arena); 405 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, usesMSAASurface, 406 std::move(appliedClip), dstProxyView, gp, 407 this->primitiveType(), renderPassXferBarriers, 408 colorLoadOp); 409} 410 411void DrawVerticesOpImpl::onPrepareDraws(GrMeshDrawTarget* target) { 412 // Allocate buffers. 413 size_t vertexStride = this->vertexStride(); 414 sk_sp<const GrBuffer> vertexBuffer; 415 int firstVertex = 0; 416 VertexWriter verts{ 417 target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex)}; 418 if (!verts) { 419 SkDebugf("Could not allocate vertices\n"); 420 return; 421 } 422 423 sk_sp<const GrBuffer> indexBuffer; 424 int firstIndex = 0; 425 uint16_t* indices = nullptr; 426 if (this->isIndexed()) { 427 indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); 428 if (!indices) { 429 SkDebugf("Could not allocate indices\n"); 430 return; 431 } 432 } 433 434 // Copy data into the buffers. 435 bool hasColorAttribute = this->requiresPerVertexColors(); 436 bool hasLocalCoordsAttribute = this->requiresPerVertexLocalCoords(); 437 int vertexOffset = 0; 438 439 for (const auto& mesh : fMeshes) { 440 SkVerticesPriv info(mesh.fVertices->priv()); 441 442 // Copy data into the index buffer. 443 if (indices) { 444 int indexCount = info.indexCount(); 445 for (int i = 0; i < indexCount; ++i) { 446 *indices++ = info.indices()[i] + vertexOffset; 447 } 448 } 449 450 // Copy data into the vertex buffer. 451 int vertexCount = info.vertexCount(); 452 const SkPoint* positions = info.positions(); 453 const SkColor* colors = info.colors(); 454 const SkPoint* localCoords = info.texCoords() ? info.texCoords() : positions; 455 456 // TODO4F: Preserve float colors 457 GrColor meshColor = mesh.fColor.toBytes_RGBA(); 458 459 SkPoint* posBase = (SkPoint*)verts.ptr(); 460 461 for (int i = 0; i < vertexCount; ++i) { 462 verts << positions[i]; 463 if (hasColorAttribute) { 464 verts << (mesh.hasPerVertexColors() ? colors[i] : meshColor); 465 } 466 if (hasLocalCoordsAttribute) { 467 verts << localCoords[i]; 468 } 469 } 470 471 if (fMultipleViewMatrices) { 472 SkASSERT(!mesh.fViewMatrix.hasPerspective()); 473 SkMatrixPriv::MapPointsWithStride(mesh.fViewMatrix, posBase, vertexStride, 474 positions, sizeof(SkPoint), vertexCount); 475 } 476 477 vertexOffset += vertexCount; 478 } 479 480 SkASSERT(!fMesh); 481 fMesh = target->allocMesh(); 482 if (this->isIndexed()) { 483 fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1, 484 GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex); 485 } else { 486 fMesh->set(std::move(vertexBuffer), fVertexCount, firstVertex); 487 } 488} 489 490void DrawVerticesOpImpl::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { 491 if (!fProgramInfo) { 492 this->createProgramInfo(flushState); 493 } 494 495 if (!fProgramInfo || !fMesh) { 496 return; 497 } 498 499 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 500 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 501 flushState->drawMesh(*fMesh); 502} 503 504GrOp::CombineResult DrawVerticesOpImpl::onCombineIfPossible(GrOp* t, 505 SkArenaAlloc*, 506 const GrCaps& caps) { 507 auto that = t->cast<DrawVerticesOpImpl>(); 508 509 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 510 return CombineResult::kCannotCombine; 511 } 512 513 if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) { 514 return CombineResult::kCannotCombine; 515 } 516 517 if (this->isIndexed() != that->isIndexed()) { 518 return CombineResult::kCannotCombine; 519 } 520 521 if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) { 522 return CombineResult::kCannotCombine; 523 } 524 525 // We can't mix draws that use SkColor vertex colors with those that don't. We can mix uniform 526 // color draws with GrColor draws (by expanding the uniform color into vertex color). 527 if ((fColorArrayType == ColorArrayType::kSkColor) != 528 (that->fColorArrayType == ColorArrayType::kSkColor)) { 529 return CombineResult::kCannotCombine; 530 } 531 532 // If we're acquiring a mesh with a different view matrix, or an op that needed multiple view 533 // matrices, we need multiple view matrices. 534 bool needMultipleViewMatrices = 535 fMultipleViewMatrices || that->fMultipleViewMatrices || 536 !SkMatrixPriv::CheapEqual(this->fMeshes[0].fViewMatrix, that->fMeshes[0].fViewMatrix); 537 538 // ... but we can't enable multiple view matrices if any of them have perspective, or our other 539 // varyings won't be interpolated correctly. 540 if (needMultipleViewMatrices && (this->fMeshes[0].fViewMatrix.hasPerspective() || 541 that->fMeshes[0].fViewMatrix.hasPerspective())) { 542 return CombineResult::kCannotCombine; 543 } else { 544 fMultipleViewMatrices = needMultipleViewMatrices; 545 } 546 547 // If the other op already required per-vertex colors, the combined mesh does. 548 if (that->fColorArrayType == ColorArrayType::kPremulGrColor) { 549 fColorArrayType = ColorArrayType::kPremulGrColor; 550 } 551 552 // If we combine meshes with different (uniform) colors, switch to per-vertex colors. 553 if (fColorArrayType == ColorArrayType::kUnused) { 554 SkASSERT(that->fColorArrayType == ColorArrayType::kUnused); 555 if (this->fMeshes[0].fColor != that->fMeshes[0].fColor) { 556 fColorArrayType = ColorArrayType::kPremulGrColor; 557 } 558 } 559 560 // NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination 561 // gamut is determined by the render target context. A mis-match should be impossible. 562 SkASSERT(GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())); 563 564 // If the other op already required explicit local coords the combined mesh does. 565 if (that->fLocalCoordsType == LocalCoordsType::kExplicit) { 566 fLocalCoordsType = LocalCoordsType::kExplicit; 567 } 568 569 // If we were planning to use positions for local coords but now have multiple view matrices, 570 // switch to explicit local coords. 571 if (fLocalCoordsType == LocalCoordsType::kUsePosition && fMultipleViewMatrices) { 572 fLocalCoordsType = LocalCoordsType::kExplicit; 573 } 574 575 fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin()); 576 fVertexCount += that->fVertexCount; 577 fIndexCount += that->fIndexCount; 578 579 return CombineResult::kMerged; 580} 581 582static GrPrimitiveType SkVertexModeToGrPrimitiveType(SkVertices::VertexMode mode) { 583 switch (mode) { 584 case SkVertices::kTriangles_VertexMode: 585 return GrPrimitiveType::kTriangles; 586 case SkVertices::kTriangleStrip_VertexMode: 587 return GrPrimitiveType::kTriangleStrip; 588 case SkVertices::kTriangleFan_VertexMode: 589 break; 590 } 591 SK_ABORT("Invalid mode"); 592} 593 594} // anonymous namespace 595 596GrOp::Owner Make(GrRecordingContext* context, 597 GrPaint&& paint, 598 sk_sp<SkVertices> vertices, 599 const SkMatrixProvider& matrixProvider, 600 GrAAType aaType, 601 sk_sp<GrColorSpaceXform> colorSpaceXform, 602 GrPrimitiveType* overridePrimType) { 603 SkASSERT(vertices); 604 GrPrimitiveType primType = overridePrimType 605 ? *overridePrimType 606 : SkVertexModeToGrPrimitiveType(vertices->priv().mode()); 607 return GrSimpleMeshDrawOpHelper::FactoryHelper<DrawVerticesOpImpl>(context, 608 std::move(paint), 609 std::move(vertices), 610 primType, 611 aaType, 612 std::move(colorSpaceXform), 613 matrixProvider); 614} 615 616} // namespace skgpu::v1::DrawVerticesOp 617 618/////////////////////////////////////////////////////////////////////////////////////////////////// 619 620#if GR_TEST_UTILS 621 622#include "src/gpu/GrDrawOpTest.h" 623 624static uint32_t seed_vertices(GrPrimitiveType type) { 625 switch (type) { 626 case GrPrimitiveType::kTriangles: 627 case GrPrimitiveType::kTriangleStrip: 628 return 3; 629 case GrPrimitiveType::kPoints: 630 return 1; 631 case GrPrimitiveType::kLines: 632 case GrPrimitiveType::kLineStrip: 633 return 2; 634 case GrPrimitiveType::kPatches: 635 case GrPrimitiveType::kPath: 636 SkASSERT(0); 637 return 0; 638 } 639 SK_ABORT("Incomplete switch\n"); 640} 641 642static uint32_t primitive_vertices(GrPrimitiveType type) { 643 switch (type) { 644 case GrPrimitiveType::kTriangles: 645 return 3; 646 case GrPrimitiveType::kLines: 647 return 2; 648 case GrPrimitiveType::kTriangleStrip: 649 case GrPrimitiveType::kPoints: 650 case GrPrimitiveType::kLineStrip: 651 return 1; 652 case GrPrimitiveType::kPatches: 653 case GrPrimitiveType::kPath: 654 SkASSERT(0); 655 return 0; 656 } 657 SK_ABORT("Incomplete switch\n"); 658} 659 660static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { 661 SkPoint p; 662 p.fX = random->nextRangeScalar(min, max); 663 p.fY = random->nextRangeScalar(min, max); 664 return p; 665} 666 667static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max, 668 SkRandom* random, SkTArray<SkPoint>* positions, 669 SkTArray<SkPoint>* texCoords, bool hasTexCoords, 670 SkTArray<uint32_t>* colors, bool hasColors, 671 SkTArray<uint16_t>* indices, bool hasIndices) { 672 for (uint32_t v = 0; v < count; v++) { 673 positions->push_back(random_point(random, min, max)); 674 if (hasTexCoords) { 675 texCoords->push_back(random_point(random, min, max)); 676 } 677 if (hasColors) { 678 colors->push_back(GrTest::RandomColor(random)); 679 } 680 if (hasIndices) { 681 SkASSERT(maxVertex <= UINT16_MAX); 682 indices->push_back(random->nextULessThan((uint16_t)maxVertex)); 683 } 684 } 685} 686 687GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp) { 688 GrPrimitiveType types[] = { 689 GrPrimitiveType::kTriangles, 690 GrPrimitiveType::kTriangleStrip, 691 GrPrimitiveType::kPoints, 692 GrPrimitiveType::kLines, 693 GrPrimitiveType::kLineStrip 694 }; 695 auto type = types[random->nextULessThan(SK_ARRAY_COUNT(types))]; 696 697 uint32_t primitiveCount = random->nextRangeU(1, 100); 698 699 // TODO make 'sensible' indexbuffers 700 SkTArray<SkPoint> positions; 701 SkTArray<SkPoint> texCoords; 702 SkTArray<uint32_t> colors; 703 SkTArray<uint16_t> indices; 704 705 bool hasTexCoords = random->nextBool(); 706 bool hasIndices = random->nextBool(); 707 bool hasColors = random->nextBool(); 708 709 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type); 710 711 static const SkScalar kMinVertExtent = -100.f; 712 static const SkScalar kMaxVertExtent = 100.f; 713 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random, 714 &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, 715 hasIndices); 716 717 for (uint32_t i = 1; i < primitiveCount; i++) { 718 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, 719 random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices, 720 hasIndices); 721 } 722 723 SkSimpleMatrixProvider matrixProvider(GrTest::TestMatrix(random)); 724 725 sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(random); 726 727 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; 728 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions.begin(), 729 texCoords.begin(), colors.begin(), 730 hasIndices ? indices.count() : 0, 731 indices.begin()); 732 GrAAType aaType = GrAAType::kNone; 733 if (numSamples > 1 && random->nextBool()) { 734 aaType = GrAAType::kMSAA; 735 } 736 return skgpu::v1::DrawVerticesOp::Make(context, 737 std::move(paint), 738 std::move(vertices), 739 matrixProvider, 740 aaType, 741 std::move(colorSpaceXform), 742 &type); 743} 744 745#endif 746