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);
    }
Example #5
0
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);
}