void onPrepareDraws(Target* target) const override { // construct a cache key from the path's genID and the view matrix static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; int clipBoundsSize32 = fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32); builder[0] = fPath.getGenerationID(); builder[1] = fPath.getFillType(); // For inverse fills, the tessellation is dependent on clip bounds. if (fPath.isInverseFillType()) { memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); } fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); builder.finish(); GrResourceProvider* rp = target->resourceProvider(); SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrVertexBuffer>(key)); int actualCount; SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; SkScalar tol = GrPathUtils::scaleToleranceToSrc( screenSpaceTol, fViewMatrix, fPath.getBounds()); if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(); actualCount = this->tessellate(&key, rp, vertexBuffer, canMapVB); } if (actualCount == 0) { return; } SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(fColor); LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); Coverage::Type coverageType; if (fPipelineInfo.readsCoverage()) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kNone_Type; } Coverage coverage(coverageType); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, fViewMatrix)); } target->initDraw(gp, this->pipeline()); SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType : kTriangles_GrPrimitiveType; GrVertices vertices; vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); target->draw(vertices); }
void onPrepareDraws(Target* target) const override { SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : Coverage::kNone_Type); LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, this->viewMatrix())); } target->initDraw(gp, this->pipeline()); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); const Geometry& args = fGeoData[0]; int vertexCount = kVertsPerHairlineRect; if (args.fStrokeWidth > 0) { vertexCount = kVertsPerStrokeRect; } const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); GrPrimitiveType primType; if (args.fStrokeWidth > 0) {; primType = kTriangleStrip_GrPrimitiveType; init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth); } else { // hairline primType = kLineStrip_GrPrimitiveType; vertex[0].set(args.fRect.fLeft, args.fRect.fTop); vertex[1].set(args.fRect.fRight, args.fRect.fTop); vertex[2].set(args.fRect.fRight, args.fRect.fBottom); vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); vertex[4].set(args.fRect.fLeft, args.fRect.fTop); } GrVertices vertices; vertices.init(primType, vertexBuffer, firstVertex, vertexCount); target->draw(vertices); }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { SkAutoTUnref<const GrGeometryProcessor> gp( GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, this->color(), this->usesLocalCoords(), this->coverageIgnored(), this->viewMatrix(), SkMatrix::I())); batchTarget->initDraw(gp, pipeline); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); Geometry& args = fGeoData[0]; int vertexCount = kVertsPerHairlineRect; if (args.fStrokeWidth > 0) { vertexCount = kVertsPerStrokeRect; } const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); GrPrimitiveType primType; if (args.fStrokeWidth > 0) {; primType = kTriangleStrip_GrPrimitiveType; args.fRect.sort(); this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth); } else { // hairline primType = kLineStrip_GrPrimitiveType; vertex[0].set(args.fRect.fLeft, args.fRect.fTop); vertex[1].set(args.fRect.fRight, args.fRect.fTop); vertex[2].set(args.fRect.fRight, args.fRect.fBottom); vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); vertex[4].set(args.fRect.fLeft, args.fRect.fTop); } GrVertices vertices; vertices.init(primType, vertexBuffer, firstVertex, vertexCount); batchTarget->draw(vertices); }
void onPrepareDraws(Target* target) const override { int instanceCount = fGeoData.count(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert viewmatrix\n"); return; } // Setup GrGeometryProcessors SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor( PLSAATriangleEffect::Create(invert, this->usesLocalCoords())); SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor( PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords())); GrResourceProvider* rp = target->resourceProvider(); for (int i = 0; i < instanceCount; ++i) { const Geometry& args = fGeoData[i]; SkRect bounds = args.fPath.getBounds(); args.fViewMatrix.mapRect(&bounds); bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft); bounds.fTop = SkScalarFloorToScalar(bounds.fTop); bounds.fRight = SkScalarCeilToScalar(bounds.fRight); bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom); triangleProcessor->setBounds(bounds); quadProcessor->setBounds(bounds); // We use the fact that SkPath::transform path does subdivision based on // perspective. Otherwise, we apply the view matrix when copying to the // segment representation. const SkMatrix* viewMatrix = &args.fViewMatrix; // We avoid initializing the path unless we have to const SkPath* pathPtr = &args.fPath; SkTLazy<SkPath> tmpPath; if (viewMatrix->hasPerspective()) { SkPath* tmpPathPtr = tmpPath.init(*pathPtr); tmpPathPtr->setIsVolatile(true); tmpPathPtr->transform(*viewMatrix); viewMatrix = &SkMatrix::I(); pathPtr = tmpPathPtr; } GrVertices grVertices; PLSVertices triVertices; PLSVertices quadVertices; if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) { continue; } if (triVertices.count()) { const GrVertexBuffer* triVertexBuffer; int firstTriVertex; size_t triStride = triangleProcessor->getVertexStride(); PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex)); if (!triVerts) { SkDebugf("Could not allocate vertices\n"); return; } for (int i = 0; i < triVertices.count(); ++i) { triVerts[i] = triVertices[i]; } grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, triVertices.count()); target->initDraw(triangleProcessor, this->pipeline()); target->draw(grVertices); } if (quadVertices.count()) { const GrVertexBuffer* quadVertexBuffer; int firstQuadVertex; size_t quadStride = quadProcessor->getVertexStride(); PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex)); if (!quadVerts) { SkDebugf("Could not allocate vertices\n"); return; } for (int i = 0; i < quadVertices.count(); ++i) { quadVerts[i] = quadVertices[i]; } grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, quadVertices.count()); target->initDraw(quadProcessor, this->pipeline()); target->draw(grVertices); } SkAutoTUnref<GrGeometryProcessor> finishProcessor( PLSFinishEffect::Create(this->color(), pathPtr->getFillType() == SkPath::FillType::kEvenOdd_FillType, invert, this->usesLocalCoords())); const GrVertexBuffer* rectVertexBuffer; size_t finishStride = finishProcessor->getVertexStride(); int firstRectVertex; static const int kRectVertexCount = 6; SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace( finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex)); if (!rectVerts) { SkDebugf("Could not allocate vertices\n"); return; } rectVerts[0] = { bounds.fLeft, bounds.fTop }; rectVerts[1] = { bounds.fLeft, bounds.fBottom }; rectVerts[2] = { bounds.fRight, bounds.fBottom }; rectVerts[3] = { bounds.fLeft, bounds.fTop }; rectVerts[4] = { bounds.fRight, bounds.fTop }; rectVerts[5] = { bounds.fRight, bounds.fBottom }; grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, kRectVertexCount); target->initDraw(finishProcessor, this->pipeline()); target->draw(grVertices); } }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { SkAutoTUnref<const GrGeometryProcessor> gp( GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, this->color(), this->viewMatrix(), SkMatrix::I(), this->coverage())); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(SkPoint)); batchTarget->initDraw(gp, pipeline); // TODO this is hacky, but the only way we have to initialize the GP is to use the // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch // everywhere we can remove this nastiness GrPipelineInfo init; init.fColorIgnored = fBatch.fColorIgnored; init.fOverrideColor = GrColor_ILLEGAL; init.fCoverageIgnored = fBatch.fCoverageIgnored; init.fUsesLocalCoords = this->usesLocalCoords(); gp->initBatchTracker(batchTarget->currentBatchTracker(), init); int instanceCount = fGeoData.count(); // compute number of vertices int maxVertices = 0; // We will use index buffers if we have multiple paths or one path with multiple contours bool isIndexed = instanceCount > 1; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int contourCount; maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, args.fTolerance); isIndexed = isIndexed || contourCount > 1; } if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { SkDebugf("Cannot render path (%d)\n", maxVertices); return; } // determine primitiveType int maxIndices = 0; GrPrimitiveType primitiveType; if (this->isHairline()) { if (isIndexed) { maxIndices = 2 * maxVertices; primitiveType = kLines_GrPrimitiveType; } else { primitiveType = kLineStrip_GrPrimitiveType; } } else { if (isIndexed) { maxIndices = 3 * maxVertices; primitiveType = kTriangles_GrPrimitiveType; } else { primitiveType = kTriangleFan_GrPrimitiveType; } } // allocate vertex / index buffers const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = batchTarget->makeVertSpace(vertexStride, maxVertices, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } const GrIndexBuffer* indexBuffer = NULL; int firstIndex = 0; void* indices = NULL; if (isIndexed) { indices = batchTarget->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex); if (!indices) { SkDebugf("Could not allocate indices\n"); return; } } // fill buffers int vertexOffset = 0; int indexOffset = 0; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int vertexCnt = 0; int indexCnt = 0; if (!this->createGeom(verts, vertexOffset, indices, indexOffset, &vertexCnt, &indexCnt, args.fPath, args.fTolerance, isIndexed)) { return; } vertexOffset += vertexCnt; indexOffset += indexCnt; SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); } GrVertices vertices; if (isIndexed) { vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, vertexOffset, indexOffset); } else { vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); } batchTarget->draw(vertices); // put back reserves batchTarget->putBackIndices((size_t)(maxIndices - indexOffset)); batchTarget->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); }
void onPrepareDraws(Target* target) override { SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(this->coverage()); if (this->coverageIgnored()) { coverage.fType = Coverage::kNone_Type; } LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, this->viewMatrix())); } size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(SkPoint)); target->initDraw(gp, this->pipeline()); int instanceCount = fGeoData.count(); // compute number of vertices int maxVertices = 0; // We will use index buffers if we have multiple paths or one path with multiple contours bool isIndexed = instanceCount > 1; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int contourCount; maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, args.fTolerance); isIndexed = isIndexed || contourCount > 1; } if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { SkDebugf("Cannot render path (%d)\n", maxVertices); return; } // determine primitiveType int maxIndices = 0; GrPrimitiveType primitiveType; if (this->isHairline()) { if (isIndexed) { maxIndices = 2 * maxVertices; primitiveType = kLines_GrPrimitiveType; } else { primitiveType = kLineStrip_GrPrimitiveType; } } else { if (isIndexed) { maxIndices = 3 * maxVertices; primitiveType = kTriangles_GrPrimitiveType; } else { primitiveType = kTriangleFan_GrPrimitiveType; } } // allocate vertex / index buffers const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = target->makeVertexSpace(vertexStride, maxVertices, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } const GrIndexBuffer* indexBuffer = nullptr; int firstIndex = 0; void* indices = nullptr; if (isIndexed) { indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex); if (!indices) { SkDebugf("Could not allocate indices\n"); return; } } // fill buffers int vertexOffset = 0; int indexOffset = 0; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int vertexCnt = 0; int indexCnt = 0; if (!this->createGeom(verts, vertexOffset, indices, indexOffset, &vertexCnt, &indexCnt, args.fPath, args.fTolerance, isIndexed)) { return; } vertexOffset += vertexCnt; indexOffset += indexCnt; SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); } GrVertices vertices; if (isIndexed) { vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, vertexOffset, indexOffset); } else { vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); } target->draw(vertices); // put back reserves target->putBackIndices((size_t)(maxIndices - indexOffset)); target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); }