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 AAHairlineBatch::onPrepareDraws(Target* target) const { // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. SkMatrix invert; if (!this->viewMatrix().invert(&invert)) { return; } // we will transform to identity space if the viewmatrix does not have perspective bool hasPerspective = this->viewMatrix().hasPerspective(); const SkMatrix* geometryProcessorViewM = &SkMatrix::I(); const SkMatrix* geometryProcessorLocalM = &invert; const SkMatrix* toDevice = nullptr; const SkMatrix* toSrc = nullptr; if (hasPerspective) { geometryProcessorViewM = &this->viewMatrix(); geometryProcessorLocalM = &SkMatrix::I(); toDevice = &this->viewMatrix(); toSrc = &invert; } // This is hand inlined for maximum performance. PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; PREALLOC_PTARRAY(128) conics; IntArray qSubdivs; FloatArray cWeights; int quadCount = 0; int instanceCount = fGeoData.count(); for (int i = 0; i < instanceCount; i++) { const Geometry& args = fGeoData[i]; quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds, &lines, &quads, &conics, &qSubdivs, &cWeights); } int lineCount = lines.count() / 2; int conicCount = conics.count() / 3; // do lines first if (lineCount) { SkAutoTUnref<const GrGeometryProcessor> lineGP; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(Coverage::kAttribute_Type); LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); localCoords.fMatrix = geometryProcessorLocalM; lineGP.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, *geometryProcessorViewM)); } SkAutoTUnref<const GrBuffer> linesIndexBuffer( ref_lines_index_buffer(target->resourceProvider())); const GrBuffer* vertexBuffer; int firstVertex; size_t vertexStride = lineGP->getVertexStride(); int vertexCount = kLineSegNumVertices * lineCount; LineVertex* verts = reinterpret_cast<LineVertex*>( target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex)); if (!verts|| !linesIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex)); for (int i = 0; i < lineCount; ++i) { add_line(&lines[2*i], toSrc, this->coverage(), &verts); } GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer, firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount, kLineSegsNumInIdxBuffer); target->draw(lineGP, mesh); } if (quadCount || conicCount) { SkAutoTUnref<const GrGeometryProcessor> quadGP( GrQuadEffect::Create(this->color(), *geometryProcessorViewM, kHairlineAA_GrProcessorEdgeType, target->caps(), *geometryProcessorLocalM, this->usesLocalCoords(), this->coverage())); SkAutoTUnref<const GrGeometryProcessor> conicGP( GrConicEffect::Create(this->color(), *geometryProcessorViewM, kHairlineAA_GrProcessorEdgeType, target->caps(), *geometryProcessorLocalM, this->usesLocalCoords(), this->coverage())); const GrBuffer* vertexBuffer; int firstVertex; SkAutoTUnref<const GrBuffer> quadsIndexBuffer( ref_quads_index_buffer(target->resourceProvider())); size_t vertexStride = sizeof(BezierVertex); int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount; void *vertices = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!vertices || !quadsIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } // Setup vertices BezierVertex* bezVerts = reinterpret_cast<BezierVertex*>(vertices); int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { SkASSERT(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &bezVerts); } // Start Conics for (int i = 0; i < conicCount; ++i) { add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &bezVerts); } if (quadCount > 0) { GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount, kQuadsNumInIdxBuffer); target->draw(quadGP, mesh); firstVertex += quadCount * kQuadNumVertices; } if (conicCount > 0) { GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount, kQuadsNumInIdxBuffer); target->draw(conicGP, mesh); } } }
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); }
void GrAtlasTextBatch::onPrepareDraws(Target* target) const { // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix. // TODO actually only invert if we don't have RGBA SkMatrix localMatrix; if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } GrTexture* texture = fFontCache->getTexture(this->maskFormat()); if (!texture) { SkDebugf("Could not allocate backing texture for atlas\n"); return; } GrMaskFormat maskFormat = this->maskFormat(); SkAutoTUnref<const GrGeometryProcessor> gp; if (this->usesDistanceFields()) { gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture)); } else { GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); gp.reset(GrBitmapTextGeoProc::Create(this->color(), texture, params, maskFormat, localMatrix, this->usesLocalCoords())); } FlushInfo flushInfo; flushInfo.fGlyphsToFlush = 0; size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat)); target->initDraw(gp); int glyphCount = this->numGlyphs(); const GrBuffer* vertexBuffer; void* vertices = target->makeVertexSpace(vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset); flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); if (!vertices || !flushInfo.fVertexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices); // We cache some values to avoid going to the glyphcache for the same fontScaler twice // in a row const SkDescriptor* desc = nullptr; SkGlyphCache* cache = nullptr; GrFontScaler* scaler = nullptr; SkTypeface* typeface = nullptr; GrBlobRegenHelper helper(this, target, &flushInfo, gp); for (int i = 0; i < fGeoCount; i++) { const Geometry& args = fGeoData[i]; Blob* blob = args.fBlob; size_t byteCount; void* blobVertices; int subRunGlyphCount; blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &cache, &typeface, &scaler, &desc, vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor, &blobVertices, &byteCount, &subRunGlyphCount); // now copy all vertices memcpy(currVertex, blobVertices, byteCount); #ifdef SK_DEBUG // bounds sanity check SkRect rect; rect.setLargestInverted(); SkPoint* vertex = (SkPoint*) ((char*)blobVertices); rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount); if (this->usesDistanceFields()) { args.fViewMatrix.mapRect(&rect); } SkASSERT(fBounds.contains(rect)); #endif currVertex += byteCount; } // Make sure to attach the last cache if applicable if (cache) { SkGlyphCache::AttachCache(cache); } this->flush(target, &flushInfo); }