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; } } }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { // Go to device coords to allow batching across matrix changes SkMatrix invert = SkMatrix::I(); // if we have a local rect, then we apply the localMatrix directly to the localRect to // generate vertex local coords bool hasExplicitLocalCoords = this->hasLocalRect(); if (!hasExplicitLocalCoords) { if (!this->viewMatrix().isIdentity() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert\n"); return; } if (this->hasLocalMatrix()) { invert.preConcat(this->localMatrix()); } } SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords, this->color(), &invert)); 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); size_t vertexStride = gp->getVertexStride(); SkASSERT(hasExplicitLocalCoords ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); int instanceCount = fGeoData.count(); int vertexCount = kVertsPerRect * instanceCount; const GrVertexBuffer* vertexBuffer; int firstVertex; void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!vertices || !batchTarget->quadIndexBuffer()) { SkDebugf("Could not allocate buffers\n"); return; } for (int i = 0; i < instanceCount; i++) { const Geometry& args = fGeoData[i]; intptr_t offset = GrTCast<intptr_t>(vertices) + kVertsPerRect * i * vertexStride; SkPoint* positions = GrTCast<SkPoint*>(offset); positions->setRectFan(args.fRect.fLeft, args.fRect.fTop, args.fRect.fRight, args.fRect.fBottom, vertexStride); args.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVertsPerRect); if (args.fHasLocalRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = GrTCast<SkPoint*>(offset + kLocalOffset); coords->setRectFan(args.fLocalRect.fLeft, args.fLocalRect.fTop, args.fLocalRect.fRight, args.fLocalRect.fBottom, vertexStride); if (args.fHasLocalMatrix) { args.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVertsPerRect); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = GrTCast<GrColor*>(offset + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = args.fColor; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } } const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer(); GrDrawTarget::DrawInfo drawInfo; drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); drawInfo.setStartVertex(0); drawInfo.setStartIndex(0); drawInfo.setVerticesPerInstance(kVertsPerRect); drawInfo.setIndicesPerInstance(kIndicesPerRect); drawInfo.adjustStartVertex(firstVertex); drawInfo.setVertexBuffer(vertexBuffer); drawInfo.setIndexBuffer(quadIndexBuffer); int maxInstancesPerDraw = quadIndexBuffer->maxQuads(); while (instanceCount) { drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw)); drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance()); drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance()); batchTarget->draw(drawInfo); drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount()); instanceCount -= drawInfo.instanceCount(); } }