Example #1
0
// Returns whether or not the gpu can fast path the dash line effect.
static bool can_fast_path_dash(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
                               const GrDrawTarget& target, const SkMatrix& viewMatrix) {
    if (target.getDrawState().getRenderTarget()->isMultisampled()) {
        return false;
    }

    // Pts must be either horizontal or vertical in src space
    if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
        return false;
    }

    // May be able to relax this to include skew. As of now cannot do perspective
    // because of the non uniform scaling of bloating a rect
    if (!viewMatrix.preservesRightAngles()) {
        return false;
    }

    if (!strokeInfo.isDashed() || 2 != strokeInfo.dashCount()) {
        return false;
    }

    const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
    if (0 == info.fIntervals[0] && 0 == info.fIntervals[1]) {
        return false;
    }

    SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap();
    // Current we do don't handle Round or Square cap dashes
    if (SkPaint::kRound_Cap == cap && info.fIntervals[0] != 0.f) {
        return false;
    }

    return true;
}
bool GrStencilAndCoverPathRenderer::canDrawPath(const GrDrawTarget* target,
                                                const GrPipelineBuilder* pipelineBuilder,
                                                const SkMatrix& viewMatrix,
                                                const SkPath& path,
                                                const GrStrokeInfo& stroke,
                                                bool antiAlias) const {
    return !stroke.getStrokeRec().isHairlineStyle() &&
        !stroke.isDashed() &&
        !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
        pipelineBuilder->getStencil().isDisabled();
}
Example #3
0
void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke) {
    SkASSERT(stroke.needToApply());
    SkASSERT(!stroke.isDashed());
    SkASSERT(!stroke.isHairlineStyle());
    GR_GL_CALL(gpu->glInterface(),
               PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
    GR_GL_CALL(gpu->glInterface(),
               PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
    GrGLenum join = join_to_gl_join(stroke.getJoin());
    GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
    GrGLenum cap = cap_to_gl_cap(stroke.getCap());
    GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
    GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
}
bool GrSoftwarePathRenderer::canDrawPath(const GrDrawTarget*,
                                         const GrPipelineBuilder*,
                                         const SkMatrix& viewMatrix,
                                         const SkPath&,
                                         const GrStrokeInfo& stroke,
                                         bool antiAlias) const {
    if (NULL == fContext) {
        return false;
    }
    if (stroke.isDashed()) {
        return false;
    }
    return true;
}
bool GrAALinearizingConvexPathRenderer::canDrawPath(const GrDrawTarget* target,
                                                    const GrPipelineBuilder*,
                                                    const SkMatrix& viewMatrix,
                                                    const SkPath& path,
                                                    const GrStrokeInfo& stroke,
                                                    bool antiAlias) const {
    if (!antiAlias) {
        return false;
    }
    if (path.isInverseFillType()) {
        return false;
    }
    if (!path.isConvex()) {
        return false;
    }
    if (stroke.getStyle() == SkStrokeRec::kStroke_Style) {
        return viewMatrix.isSimilarity() && stroke.getWidth() >= 1.0f && 
                stroke.getWidth() <= kMaxStrokeWidth && !stroke.isDashed() && 
                SkPathPriv::LastVerbIsClose(path) && stroke.getJoin() != SkPaint::Join::kRound_Join;
    }
    return stroke.getStyle() == SkStrokeRec::kFill_Style;
}
bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
                                               GrPipelineBuilder* pipelineBuilder,
                                               GrColor color,
                                               const SkMatrix& viewMatrix,
                                               const SkPath& path,
                                               const GrStrokeInfo& stroke,
                                               bool antiAlias) {
    SkASSERT(!antiAlias);
    SkASSERT(!stroke.getStrokeRec().isHairlineStyle());
    SkASSERT(!stroke.isDashed());
    SkASSERT(pipelineBuilder->getStencil().isDisabled());

    SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke.getStrokeRec()));

    if (path.isInverseFillType()) {
        GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
            kZero_StencilOp,
            kZero_StencilOp,
            // We know our rect will hit pixels outside the clip and the user bits will be 0
            // outside the clip. So we can't just fill where the user bits are 0. We also need to
            // check that the clip bit is set.
            kEqualIfInClip_StencilFunc,
            0xffff,
            0x0000,
            0xffff);

        pipelineBuilder->setStencil(kInvertedStencilPass);

        // fake inverse with a stencil and cover
        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix));
        target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));

        SkMatrix invert = SkMatrix::I();
        SkRect bounds =
            SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
                             SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
        SkMatrix vmi;
        // mapRect through persp matrix may not be correct
        if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
            vmi.mapRect(&bounds);
            // theoretically could set bloat = 0, instead leave it because of matrix inversion
            // precision.
            SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
            bounds.outset(bloat, bloat);
        } else {
            if (!viewMatrix.invert(&invert)) {
                return false;
            }
        }
        const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
        target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert);
    } else {
        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
            kZero_StencilOp,
            kZero_StencilOp,
            kNotEqual_StencilFunc,
            0xffff,
            0x0000,
            0xffff);

        pipelineBuilder->setStencil(kStencilPass);
        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color, viewMatrix));
        target->drawPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
    }

    pipelineBuilder->stencil()->setDisabled();
    return true;
}
Example #7
0
void GrGLPath::InitPathObject(GrGLGpu* gpu,
                              GrGLuint pathID,
                              const SkPath& skPath,
                              const GrStrokeInfo& stroke) {
    SkASSERT(!stroke.isDashed());
    if (!skPath.isEmpty()) {
        int verbCnt = skPath.countVerbs();
        int pointCnt = skPath.countPoints();
        int minCoordCnt = pointCnt * 2;

        SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
        SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);

        SkDEBUGCODE(int numCoords = 0);

        if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
            // This branch does type punning, converting SkPoint* to GrGLfloat*.
            SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, sk_point_not_two_floats);
            // This branch does not convert with SkScalarToFloat.
#ifndef SK_SCALAR_IS_FLOAT
#error Need SK_SCALAR_IS_FLOAT.
#endif
            pathCommands.resize_back(verbCnt);
            pathCoords.resize_back(minCoordCnt);
            skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
            skPath.getVerbs(&pathCommands[0], verbCnt);
            for (int i = 0; i < verbCnt; ++i) {
                SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
                pathCommands[i] = verb_to_gl_path_cmd(v);
                SkDEBUGCODE(numCoords += num_coords(v));
            }
        } else {
            SkPoint points[4];
            SkPath::RawIter iter(skPath);
            SkPath::Verb verb;
            while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
                pathCommands.push_back(verb_to_gl_path_cmd(verb));
                GrGLfloat coords[6];
                int coordsForVerb;
                switch (verb) {
                    case SkPath::kMove_Verb:
                        points_to_coords(points, 0, 1, coords);
                        coordsForVerb = 2;
                        break;
                    case SkPath::kLine_Verb:
                        points_to_coords(points, 1, 1, coords);
                        coordsForVerb = 2;
                        break;
                    case SkPath::kConic_Verb:
                        points_to_coords(points, 1, 2, coords);
                        coords[4] = SkScalarToFloat(iter.conicWeight());
                        coordsForVerb = 5;
                        break;
                    case SkPath::kQuad_Verb:
                        points_to_coords(points, 1, 2, coords);
                        coordsForVerb = 4;
                        break;
                    case SkPath::kCubic_Verb:
                        points_to_coords(points, 1, 3, coords);
                        coordsForVerb = 6;
                        break;
                    case SkPath::kClose_Verb:
                        continue;
                    default:
                        SkASSERT(false);  // Not reached.
                        continue;
                }
                SkDEBUGCODE(numCoords += num_coords(verb));
                pathCoords.push_back_n(coordsForVerb, coords);
            }
        }

        SkASSERT(verbCnt == pathCommands.count());
        SkASSERT(numCoords == pathCoords.count());

        GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
                   pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
    } else {
        GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, NULL, 0, GR_GL_FLOAT, NULL));
    }

    if (stroke.needToApply()) {
        SkASSERT(!stroke.isHairlineStyle());
        GR_GL_CALL(gpu->glInterface(),
            PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
        GR_GL_CALL(gpu->glInterface(),
            PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
        GrGLenum join = join_to_gl_join(stroke.getJoin());
        GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
        GrGLenum cap = cap_to_gl_cap(stroke.getCap());
        GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
        GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
    }
}