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 { int instanceCount = fGeoData.count(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert viewmatrix\n"); return; } // Setup GrGeometryProcessor SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(this->color(), invert)); batchTarget->initDraw(quadProcessor, pipeline); // TODO remove this when batch is everywhere GrPipelineInfo init; init.fColorIgnored = fBatch.fColorIgnored; init.fOverrideColor = GrColor_ILLEGAL; init.fCoverageIgnored = fBatch.fCoverageIgnored; init.fUsesLocalCoords = this->usesLocalCoords(); quadProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init); // TODO generate all segments for all paths and use one vertex buffer for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; // 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; if (viewMatrix->hasPerspective()) { args.fPath.transform(*viewMatrix); viewMatrix = &SkMatrix::I(); } int vertexCount; int indexCount; enum { kPreallocSegmentCnt = 512 / sizeof(Segment), kPreallocDrawCnt = 4, }; SkSTArray<kPreallocSegmentCnt, Segment, true> segments; SkPoint fanPt; if (!get_segments(args.fPath, *viewMatrix, &segments, &fanPt, &vertexCount, &indexCount)) { continue; } const GrVertexBuffer* vertexBuffer; int firstVertex; size_t vertexStride = quadProcessor->getVertexStride(); void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!vertices) { SkDebugf("Could not allocate vertices\n"); return; } const GrIndexBuffer* indexBuffer; int firstIndex; void *indices = batchTarget->indexPool()->makeSpace(indexCount, &indexBuffer, &firstIndex); if (!indices) { SkDebugf("Could not allocate indices\n"); return; } QuadVertex* verts = reinterpret_cast<QuadVertex*>(vertices); uint16_t* idxs = reinterpret_cast<uint16_t*>(indices); SkSTArray<kPreallocDrawCnt, Draw, true> draws; create_vertices(segments, fanPt, &draws, verts, idxs); GrDrawTarget::DrawInfo info; info.setVertexBuffer(vertexBuffer); info.setIndexBuffer(indexBuffer); info.setPrimitiveType(kTriangles_GrPrimitiveType); info.setStartIndex(firstIndex); int vOffset = 0; for (int i = 0; i < draws.count(); ++i) { const Draw& draw = draws[i]; info.setStartVertex(vOffset + firstVertex); info.setVertexCount(draw.fVertexCnt); info.setIndexCount(draw.fIndexCnt); batchTarget->draw(info); vOffset += draw.fVertexCnt; } } }