bool GrAAHairLinePathRenderer::createGeom( const SkPath& path, GrDrawTarget* target, int* lineCnt, int* quadCnt, GrDrawTarget::AutoReleaseGeometry* arg) { const GrDrawState& drawState = target->getDrawState(); int rtHeight = drawState.getRenderTarget()->height(); GrIRect devClipBounds; target->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds); GrVertexLayout layout = GrDrawState::kEdge_VertexLayoutBit; SkMatrix viewM = drawState.getViewMatrix(); PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; IntArray qSubdivs; *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, &lines, &quads, &qSubdivs); *lineCnt = lines.count() / 2; int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; GrAssert(sizeof(Vertex) == GrDrawState::VertexSize(layout)); if (!arg->set(target, layout, vertCnt, 0)) { return false; } Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); const SkMatrix* toDevice = NULL; const SkMatrix* toSrc = NULL; SkMatrix ivm; if (viewM.hasPerspective()) { if (viewM.invert(&ivm)) { toDevice = &viewM; toSrc = &ivm; } } for (int i = 0; i < *lineCnt; ++i) { add_line(&lines[2*i], rtHeight, toSrc, &verts); } int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { GrAssert(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); } return true; }
bool GrAAHairLinePathRenderer::createGeom(GrDrawTarget::StageBitfield stages) { int rtHeight = fTarget->getRenderTarget()->height(); GrIRect clip; if (fTarget->getClip().hasConservativeBounds()) { GrRect clipRect = fTarget->getClip().getConservativeBounds(); clipRect.roundOut(&clip); } else { clip.setLargest(); } // If none of the inputs that affect generation of path geometry have // have changed since last previous path draw then we can reuse the // previous geoemtry. if (stages == fPreviousStages && fPreviousViewMatrix == fTarget->getViewMatrix() && fPreviousTranslate == fTranslate && rtHeight == fPreviousRTHeight && fClipRect == clip) { return true; } GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit; for (int s = 0; s < GrDrawState::kNumStages; ++s) { if ((1 << s) & stages) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } GrMatrix viewM = fTarget->getViewMatrix(); PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; IntArray qSubdivs; fQuadCnt = generate_lines_and_quads(*fPath, viewM, fTranslate, clip, &lines, &quads, &qSubdivs); fLineSegmentCnt = lines.count() / 2; int vertCnt = kVertsPerLineSeg * fLineSegmentCnt + kVertsPerQuad * fQuadCnt; GrAssert(sizeof(Vertex) == GrDrawTarget::VertexSize(layout)); Vertex* verts; if (!fTarget->reserveVertexSpace(layout, vertCnt, (void**)&verts)) { return false; } Vertex* base = verts; const GrMatrix* toDevice = NULL; const GrMatrix* toSrc = NULL; GrMatrix ivm; if (viewM.hasPerspective()) { if (viewM.invert(&ivm)) { toDevice = &viewM; toSrc = &ivm; } } for (int i = 0; i < fLineSegmentCnt; ++i) { add_line(&lines[2*i], rtHeight, toSrc, &verts); } int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { GrAssert(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); } fPreviousStages = stages; fPreviousViewMatrix = fTarget->getViewMatrix(); fPreviousRTHeight = rtHeight; fClipRect = clip; fPreviousTranslate = fTranslate; return true; }
bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target, bool antiAlias) { GrDrawState* drawState = target->drawState(); SkScalar hairlineCoverage; if (IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), &hairlineCoverage)) { uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * target->getDrawState().getCoverage()); target->drawState()->setCoverage(newCoverage); } SkIRect devClipBounds; target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); int lineCnt; int quadCnt; int conicCnt; PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; PREALLOC_PTARRAY(128) conics; IntArray qSubdivs; FloatArray cWeights; quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClipBounds, &lines, &quads, &conics, &qSubdivs, &cWeights); lineCnt = lines.count() / 2; conicCnt = conics.count() / 3; // do lines first if (lineCnt) { GrDrawTarget::AutoReleaseGeometry arg; SkRect devBounds; if (!this->createLineGeom(path, target, lines, lineCnt, &arg, &devBounds)) { return false; } GrDrawTarget::AutoStateRestore asr; // createLineGeom transforms the geometry to device space when the matrix does not have // perspective. if (target->getDrawState().getViewMatrix().hasPerspective()) { asr.set(target, GrDrawTarget::kPreserve_ASRInit); } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { return false; } GrDrawState* drawState = target->drawState(); // Check devBounds SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), kVertsPerLineSeg * lineCnt)); { GrDrawState::AutoRestoreEffects are(drawState); target->setIndexSourceToBuffer(fLinesIndexBuffer); int lines = 0; while (lines < lineCnt) { int n = SkTMin(lineCnt - lines, kNumLineSegsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerLineSeg*lines, // startV 0, // startI kVertsPerLineSeg*n, // vCount kIdxsPerLineSeg*n, // iCount &devBounds); lines += n; } } } // then quadratics/conics if (quadCnt || conicCnt) { GrDrawTarget::AutoReleaseGeometry arg; SkRect devBounds; if (!this->createBezierGeom(path, target, quads, quadCnt, conics, conicCnt, qSubdivs, cWeights, &arg, &devBounds)) { return false; } GrDrawTarget::AutoStateRestore asr; // createGeom transforms the geometry to device space when the matrix does not have // perspective. if (target->getDrawState().getViewMatrix().hasPerspective()) { asr.set(target, GrDrawTarget::kPreserve_ASRInit); } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { return false; } GrDrawState* drawState = target->drawState(); static const int kEdgeAttrIndex = 1; // Check devBounds SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(), kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt)); if (quadCnt > 0) { GrEffect* hairQuadEffect = GrQuadEffect::Create(kHairlineAA_GrEffectEdgeType, *target->caps()); SkASSERT(hairQuadEffect); GrDrawState::AutoRestoreEffects are(drawState); target->setIndexSourceToBuffer(fQuadsIndexBuffer); drawState->setGeometryProcessor(hairQuadEffect, kEdgeAttrIndex)->unref(); int quads = 0; while (quads < quadCnt) { int n = SkTMin(quadCnt - quads, kNumQuadsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerQuad*quads, // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n, // iCount &devBounds); quads += n; } } if (conicCnt > 0) { GrDrawState::AutoRestoreEffects are(drawState); GrEffect* hairConicEffect = GrConicEffect::Create(kHairlineAA_GrEffectEdgeType, *target->caps()); SkASSERT(hairConicEffect); drawState->setGeometryProcessor(hairConicEffect, 1, 2)->unref(); int conics = 0; while (conics < conicCnt) { int n = SkTMin(conicCnt - conics, kNumQuadsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerQuad*(quadCnt + conics), // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n, // iCount &devBounds); conics += n; } } } target->resetIndexSource(); return true; }