Ejemplo n.º 1
0
void GrClip::setFromRect(const GrRect& r) {
    fList.reset();
    if (r.isEmpty()) {
        // use a canonical empty rect for == testing.
        setEmpty();
    } else {
        fList.push_back();
        fList.back().fRect = r;
        fList.back().fType = kRect_ClipType;
        fConservativeBounds = r;
        fConservativeBoundsValid = true;
    }
}
Ejemplo n.º 2
0
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
    const GrIRect* r = NULL;
    GrIRect clipRect;

    GrDrawState* drawState = this->drawState();
    const GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

    if (drawState->isClipState()) {

        GrRect bounds;
        GrRect rtRect;
        rtRect.setLTRB(0, 0,
                       GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
        if (fClip.hasConservativeBounds()) {
            bounds = fClip.getConservativeBounds();
            if (!bounds.intersect(rtRect)) {
                bounds.setEmpty();
            }
        } else {
            bounds = rtRect;
        }

        bounds.roundOut(&clipRect);
        if  (clipRect.isEmpty()) {
            clipRect.setLTRB(0,0,0,0);
        }
        r = &clipRect;

        // use the stencil clip if we can't represent the clip as a rectangle.
        fClipInStencil = !fClip.isRect() && !fClip.isEmpty() && 
                         !bounds.isEmpty();

        // TODO: dynamically attach a SB when needed.
        GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
        if (fClipInStencil && NULL == stencilBuffer) {
            return false;
        }

        if (fClipInStencil &&
            stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {

            stencilBuffer->setLastClip(fClip, rt->width(), rt->height());

            // we set the current clip to the bounds so that our recursive
            // draws are scissored to them. We use the copy of the complex clip
            // we just stashed on the SB to render from. We set it back after
            // we finish drawing it into the stencil.
            const GrClip& clip = stencilBuffer->getLastClip();
            fClip.setFromRect(bounds);

            AutoStateRestore asr(this);
            AutoGeometryPush agp(this);

            drawState->setViewMatrix(GrMatrix::I());
            this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
            drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#else
            drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
#endif
            int count = clip.getElementCount();
            int clipBit = stencilBuffer->bits();
            SkASSERT((clipBit <= 16) &&
                     "Ganesh only handles 16b or smaller stencil buffers");
            clipBit = (1 << (clipBit-1));
            
            bool clearToInside;
            GrSetOp startOp = kReplace_SetOp; // suppress warning
            int start = process_initial_clip_elements(clip,
                                                      rtRect,
                                                      &clearToInside,
                                                      &startOp);

            this->clearStencilClip(clipRect, clearToInside);

            // walk through each clip element and perform its set op
            // with the existing clip.
            for (int c = start; c < count; ++c) {
                GrPathFill fill;
                bool fillInverted;
                // enabled at bottom of loop
                drawState->disableState(kModifyStencilClip_StateBit);

                bool canRenderDirectToStencil; // can the clip element be drawn
                                               // directly to the stencil buffer
                                               // with a non-inverted fill rule
                                               // without extra passes to
                                               // resolve in/out status.

                GrPathRenderer* pr = NULL;
                const GrPath* clipPath = NULL;
                GrPathRenderer::AutoClearPath arp;
                if (kRect_ClipType == clip.getElementType(c)) {
                    canRenderDirectToStencil = true;
                    fill = kEvenOdd_PathFill;
                    fillInverted = false;
                    // there is no point in intersecting a screen filling
                    // rectangle.
                    if (kIntersect_SetOp == clip.getOp(c) &&
                        clip.getRect(c).contains(rtRect)) {
                        continue;
                    }
                } else {
                    fill = clip.getPathFill(c);
                    fillInverted = GrIsFillInverted(fill);
                    fill = GrNonInvertedFill(fill);
                    clipPath = &clip.getPath(c);
                    pr = this->getClipPathRenderer(*clipPath, fill);
                    if (NULL == pr) {
                        fClipInStencil = false;
                        fClip = clip;
                        return false;
                    }
                    canRenderDirectToStencil =
                        !pr->requiresStencilPass(this, *clipPath, fill);
                    arp.set(pr, this, clipPath, fill, false, NULL);
                }

                GrSetOp op = (c == start) ? startOp : clip.getOp(c);
                int passes;
                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

                bool canDrawDirectToClip; // Given the renderer, the element,
                                          // fill rule, and set operation can
                                          // we render the element directly to
                                          // stencil bit used for clipping.
                canDrawDirectToClip =
                    GrStencilSettings::GetClipPasses(op,
                                                     canRenderDirectToStencil,
                                                     clipBit,
                                                     fillInverted,
                                                     &passes, stencilSettings);

                // draw the element to the client stencil bits if necessary
                if (!canDrawDirectToClip) {
                    GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
                        kIncClamp_StencilOp,
                        kIncClamp_StencilOp,
                        kAlways_StencilFunc,
                        0xffff,
                        0x0000,
                        0xffff);
                    SET_RANDOM_COLOR
                    if (kRect_ClipType == clip.getElementType(c)) {
                        *drawState->stencil() = gDrawToStencil;
                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
                    } else {
                        if (canRenderDirectToStencil) {
                            *drawState->stencil() = gDrawToStencil;
                            pr->drawPath(0);
                        } else {
                            pr->drawPathToStencil();
                        }
                    }
                }

                // now we modify the clip bit by rendering either the clip
                // element directly or a bounding rect of the entire clip.
                drawState->enableState(kModifyStencilClip_StateBit);
                for (int p = 0; p < passes; ++p) {
                    *drawState->stencil() = stencilSettings[p];
                    if (canDrawDirectToClip) {
                        if (kRect_ClipType == clip.getElementType(c)) {
                            SET_RANDOM_COLOR
                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
                        } else {
                            SET_RANDOM_COLOR
                            pr->drawPath(0);
                        }
                    } else {
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(bounds, NULL, 0);
                    }
                }
            }
Ejemplo n.º 3
0
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::createClipMask(GrGpu* gpu, 
                                       const GrClip& clipIn,
                                       ScissoringSettings* scissorSettings) {

    GrAssert(scissorSettings);

    scissorSettings->fEnableScissoring = false;
    fClipMaskInStencil = false;
    fClipMaskInAlpha = false;

    GrDrawState* drawState = gpu->drawState();
    if (!drawState->isClipState()) {
        return true;
    }

    GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

#if GR_SW_CLIP
    if (create_mask_in_sw()) {
        // The clip geometry is complex enough that it will be more
        // efficient to create it entirely in software
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }
    }
#endif

#if GR_AA_CLIP
    // If MSAA is enabled use the (faster) stencil path for AA clipping
    // otherwise the alpha clip mask is our only option
    if (clipIn.requiresAA() && 0 == rt->numSamples()) {
        // Since we are going to create a destination texture of the correct
        // size for the mask (rather than being bound by the size of the
        // render target) we aren't going to use scissoring like the stencil
        // path does (see scissorSettings below)
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if alpha clip mask creation fails fall through to the stencil
        // buffer method
    }
#endif // GR_AA_CLIP

    GrRect bounds;
    GrRect rtRect;
    rtRect.setLTRB(0, 0,
                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
    if (clipIn.hasConservativeBounds()) {
        bounds = clipIn.getConservativeBounds();
        if (!bounds.intersect(rtRect)) {
            bounds.setEmpty();
        }
    } else {
        bounds = rtRect;
    }

    bounds.roundOut(&scissorSettings->fScissorRect);
    if  (scissorSettings->fScissorRect.isEmpty()) {
        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
        // TODO: I think we can do an early exit here - after refactoring try:
        //  set fEnableScissoring to true but leave fClipMaskInStencil false
        //  and return - everything is going to be scissored away anyway!
    }
    scissorSettings->fEnableScissoring = true;

    // use the stencil clip if we can't represent the clip as a rectangle.
    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
                         !bounds.isEmpty();

    if (fClipMaskInStencil) {
        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
    }

    return true;
}
Ejemplo n.º 4
0
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
    const GrIRect* r = NULL;
    GrIRect clipRect;

    // we check this early because we need a valid
    // render target to setup stencil clipping
    // before even going into flushGraphicsState
    if (NULL == fCurrDrawState.fRenderTarget) {
        GrAssert(!"No render target bound.");
        return false;
    }

    if (fCurrDrawState.fFlagBits & kClip_StateBit) {
        GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;

        GrRect bounds;
        GrRect rtRect;
        rtRect.setLTRB(0, 0,
                       GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
        if (fClip.hasConservativeBounds()) {
            bounds = fClip.getConservativeBounds();
            bounds.intersectWith(rtRect);
        } else {
            bounds = rtRect;
        }

        bounds.roundOut(&clipRect);
        if  (clipRect.isEmpty()) {
            clipRect.setLTRB(0,0,0,0);
        }
        r = &clipRect;

        fClipState.fClipInStencil = !fClip.isRect() &&
                                    !fClip.isEmpty() &&
                                    !bounds.isEmpty();

        if (fClipState.fClipInStencil &&
            (fClipState.fClipIsDirty ||
             fClip != rt.fLastStencilClip)) {

            rt.fLastStencilClip = fClip;
            // we set the current clip to the bounds so that our recursive
            // draws are scissored to them. We use the copy of the complex clip
            // in the rt to render
            const GrClip& clip = rt.fLastStencilClip;
            fClip.setFromRect(bounds);

            AutoStateRestore asr(this);
            AutoInternalDrawGeomRestore aidgr(this);

            this->setViewMatrix(GrMatrix::I());
            this->eraseStencilClip(clipRect);
            this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
            this->enableState(kNoColorWrites_StateBit);
#else
            this->disableState(kNoColorWrites_StateBit);
#endif
            int count = clip.getElementCount();
            int clipBit = rt.stencilBits();
            clipBit = (1 << (clipBit-1));

            // often we'll see the first two elements of the clip are
            // the full rt size and another element intersected with it.
            // We can skip the first full-size rect and save a big rect draw.
            int firstElement = 0;
            if (clip.getElementCount() > 1 &&
                kRect_ClipType == clip.getElementType(0) &&
                kIntersect_SetOp == clip.getOp(1)&&
                clip.getRect(0).contains(bounds)) {
                firstElement = 1;
            }

            // walk through each clip element and perform its set op
            // with the existing clip.
            for (int c = firstElement; c < count; ++c) {
                GrPathFill fill;
                // enabled at bottom of loop
                this->disableState(kModifyStencilClip_StateBit);

                bool canDrawDirectToClip;
                if (kRect_ClipType == clip.getElementType(c)) {
                    canDrawDirectToClip = true;
                    fill = kEvenOdd_PathFill;
                } else {
                    fill = clip.getPathFill(c);
                    GrPathRenderer* pr = this->getPathRenderer();
                    canDrawDirectToClip = pr->requiresStencilPass(this, clip.getPath(c), fill);
                }

                GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
                int passes;
                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

                canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canDrawDirectToClip,
                                                                       clipBit, IsFillInverted(fill),
                                                                       &passes, stencilSettings);

                // draw the element to the client stencil bits if necessary
                if (!canDrawDirectToClip) {
                    if (kRect_ClipType == clip.getElementType(c)) {
                        static const GrStencilSettings gDrawToStencil = {
                            kIncClamp_StencilOp, kIncClamp_StencilOp,
                            kIncClamp_StencilOp, kIncClamp_StencilOp,
                            kAlways_StencilFunc, kAlways_StencilFunc,
                            0xffffffff,          0xffffffff,
                            0x00000000,          0x00000000,
                            0xffffffff,          0xffffffff,
                        };
                        this->setStencil(gDrawToStencil);
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
                    } else {
                        SET_RANDOM_COLOR
                        getPathRenderer()->drawPathToStencil(this, clip.getPath(c),
                                                             NonInvertedFill(fill),
                                                             NULL);
                    }
                }

                // now we modify the clip bit by rendering either the clip
                // element directly or a bounding rect of the entire clip.
                this->enableState(kModifyStencilClip_StateBit);
                for (int p = 0; p < passes; ++p) {
                    this->setStencil(stencilSettings[p]);
                    if (canDrawDirectToClip) {
                        if (kRect_ClipType == clip.getElementType(c)) {
                            SET_RANDOM_COLOR
                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
                        } else {
                            SET_RANDOM_COLOR
                            getPathRenderer()->drawPath(this, 0,
                                                        clip.getPath(c),
                                                        fill, NULL);
                        }
                    } else {
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(bounds, 0, NULL);
                    }
                }
            }
            fClip = clip;
            // recusive draws would have disabled this.
            fClipState.fClipInStencil = true;
        }

        fClipState.fClipIsDirty = false;
    }

    // Must flush the scissor after graphics state
    if (!this->flushGraphicsState(type)) {
        return false;
    }
    this->flushScissor(r);
    return true;
}
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::createClipMask(GrGpu* gpu, 
                                       const GrClip& clipIn,
                                       ScissoringSettings* scissorSettings) {

    GrAssert(scissorSettings);

    scissorSettings->fEnableScissoring = false;
    fClipMaskInStencil = false;
    fClipMaskInAlpha = false;

    GrDrawState* drawState = gpu->drawState();
    if (!drawState->isClipState()) {
        return true;
    }

    GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

#if GR_SW_CLIP
    // If MSAA is enabled we can do everything in the stencil buffer.
    // Otherwise check if we should just create the entire clip mask 
    // in software (this will only happen if the clip mask is anti-aliased
    // and too complex for the gpu to handle in its entirety)
    if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
        // The clip geometry is complex enough that it will be more
        // efficient to create it entirely in software
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if SW clip mask creation fails fall through to the other
        // two possible methods (bottoming out at stencil clipping)
    }
#endif // GR_SW_CLIP

#if GR_AA_CLIP
    // If MSAA is enabled use the (faster) stencil path for AA clipping
    // otherwise the alpha clip mask is our only option
    if (0 == rt->numSamples() && clipIn.requiresAA()) {
        // Since we are going to create a destination texture of the correct
        // size for the mask (rather than being bound by the size of the
        // render target) we aren't going to use scissoring like the stencil
        // path does (see scissorSettings below)
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if alpha clip mask creation fails fall through to the stencil
        // buffer method
    }
#endif // GR_AA_CLIP

    // Either a hard (stencil buffer) clip was explicitly requested or 
    // an antialiased clip couldn't be created. In either case, free up
    // the texture in the antialiased mask cache.
    // TODO: this may require more investigation. Ganesh performs a lot of
    // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit
    // the stencil buffer path. These may be "incorrectly" clearing the 
    // AA cache.
    fAACache.reset();

    GrRect bounds;
    GrRect rtRect;
    rtRect.setLTRB(0, 0,
                   GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
    if (clipIn.hasConservativeBounds()) {
        bounds = clipIn.getConservativeBounds();
        if (!bounds.intersect(rtRect)) {
            bounds.setEmpty();
        }
    } else {
        bounds = rtRect;
    }

    bounds.roundOut(&scissorSettings->fScissorRect);
    if  (scissorSettings->fScissorRect.isEmpty()) {
        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
        // TODO: I think we can do an early exit here - after refactoring try:
        //  set fEnableScissoring to true but leave fClipMaskInStencil false
        //  and return - everything is going to be scissored away anyway!
    }
    scissorSettings->fEnableScissoring = true;

    // use the stencil clip if we can't represent the clip as a rectangle.
    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
                         !bounds.isEmpty();

    if (fClipMaskInStencil) {
        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
    }

    return true;
}