Пример #1
0
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu,
                                            const GrClip& clipIn,
                                            GrTexture** result,
                                            GrIRect *resultBounds) {

    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
        return true;
    }

    GrTexture* accum = fAACache.getLastMask();
    if (NULL == accum) {
        fClipMaskInAlpha = false;
        fAACache.reset();
        return false;
    }

    GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
    GrDrawState* drawState = gpu->drawState();

    GrDrawTarget::AutoGeometryPush agp(gpu);

    int count = clipIn.getElementCount();

    if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
        // if we were able to trim down the size of the mask we need to 
        // offset the paths & rects that will be used to compute it
        GrMatrix m;

        m.setTranslate(SkIntToScalar(-resultBounds->fLeft), 
                       SkIntToScalar(-resultBounds->fTop));

        drawState->setViewMatrix(m);
    }

    bool clearToInside;
    SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
    int start = process_initial_clip_elements(clipIn,
                                              *resultBounds,
                                              &clearToInside,
                                              &startOp);

    clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000);

    GrAutoScratchTexture temp;

    // walk through each clip element and perform its set op
    for (int c = start; c < count; ++c) {

        SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c);

        if (SkRegion::kReplace_Op == op) {
            // TODO: replace is actually a lot faster then intersection
            // for this path - refactor the stencil path so it can handle
            // replace ops and alter GrClip to allow them through

            // clear the accumulator and draw the new object directly into it
            clear(gpu, accum, 0x00000000);

            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(gpu, accum, clipIn, c);

        } else if (SkRegion::kReverseDifference_Op == op ||
                   SkRegion::kIntersect_Op == op) {
            // there is no point in intersecting a screen filling rectangle.
            if (SkRegion::kIntersect_Op == op &&
                kRect_ClipType == clipIn.getElementType(c) &&
                contains(clipIn.getRect(c), *resultBounds)) {
                continue;
            }

            getTemp(*resultBounds, &temp);
            if (NULL == temp.texture()) {
                fClipMaskInAlpha = false;
                fAACache.reset();
                return false;
            }

            // clear the temp target & draw into it
            clear(gpu, temp.texture(), 0x00000000);

            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
            this->drawClipShape(gpu, temp.texture(), clipIn, c);

            // TODO: rather than adding these two translations here
            // compute the bounding box needed to render the texture
            // into temp
            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
                GrMatrix m;

                m.setTranslate(SkIntToScalar(resultBounds->fLeft), 
                               SkIntToScalar(resultBounds->fTop));

                drawState->preConcatViewMatrix(m);
            }

            // Now draw into the accumulator using the real operation
            // and the temp buffer as a texture
            setup_boolean_blendcoeffs(drawState, op);
            this->drawTexture(gpu, accum, temp.texture());

            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
                GrMatrix m;

                m.setTranslate(SkIntToScalar(-resultBounds->fLeft), 
                               SkIntToScalar(-resultBounds->fTop));

                drawState->preConcatViewMatrix(m);
            }

        } else {
            // all the remaining ops can just be directly draw into 
            // the accumulation buffer
            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(gpu, accum, clipIn, c);
        }
    }

    *result = accum;

    return true;
}
/*
 * This method traverses the clip stack to see if the GrSoftwarePathRenderer
 * will be used on any element. If so, it returns true to indicate that the
 * entire clip should be rendered in SW and then uploaded en masse to the gpu.
 */
bool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) {

    if (!clipIn.requiresAA()) {
        // The stencil buffer can handle this case
        return false;
    }

    // TODO: generalize this test so that when
    // a clip gets complex enough it can just be done in SW regardless
    // of whether it would invoke the GrSoftwarePathRenderer.
    bool useSW = false;

    for (int i = 0; i < clipIn.getElementCount(); ++i) {

        if (SkRegion::kReplace_Op == clipIn.getOp(i)) {
            // Everything before a replace op can be ignored so start
            // afresh w.r.t. determining if any element uses the SW path
            useSW = false;
        }

        if (!clipIn.getDoAA(i)) {
            // non-anti-aliased rects and paths can always be drawn either
            // directly or by the GrDefaultPathRenderer
            continue;
        }

        if (kRect_ClipType == clipIn.getElementType(i)) {
            // Antialiased rects are converted to paths and then drawn with
            // kEvenOdd_PathFill. 
            if (!GrAAConvexPathRenderer::staticCanDrawPath(
                                                    true,     // always convex
                                                    kEvenOdd_PathFill,
                                                    gpu, 
                                                    true)) {  // anti-aliased
                // if the GrAAConvexPathRenderer can't render this rect (due
                // to lack of derivative support in the shaders) then 
                // the GrSoftwarePathRenderer will be used
                useSW = true;
            }

            continue;
        }

        // only paths need to be considered in the rest of the loop body

        if (GrAAHairLinePathRenderer::staticCanDrawPath(clipIn.getPath(i),
                                                        clipIn.getPathFill(i),
                                                        gpu,
                                                        clipIn.getDoAA(i))) {
            // the hair line path renderer can handle this one
            continue;
        }

        if (GrAAConvexPathRenderer::staticCanDrawPath(
                                                clipIn.getPath(i).isConvex(),
                                                clipIn.getPathFill(i),
                                                gpu,
                                                clipIn.getDoAA(i))) {
            // the convex path renderer can handle this one
            continue;
        }

        // otherwise the GrSoftwarePathRenderer is going to be invoked
        useSW = true;
    }

    return useSW;
}