コード例 #1
0
void GrClipMaskManager::mergeMask(GrTexture* dstMask,
                                  GrTexture* srcMask,
                                  SkRegion::Op op,
                                  const GrIRect& dstBound,
                                  const GrIRect& srcBound) {
    GrDrawState* drawState = fGpu->drawState();
    GrAssert(NULL != drawState);
    SkMatrix oldMatrix = drawState->getViewMatrix();
    drawState->viewMatrix()->reset();

    drawState->setRenderTarget(dstMask->asRenderTarget());

    setup_boolean_blendcoeffs(drawState, op);

    SkMatrix sampleM;
    sampleM.setIDiv(srcMask->width(), srcMask->height());
    drawState->stage(0)->setEffect(
        GrTextureDomainEffect::Create(srcMask,
                                      sampleM,
                                      GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound),
                                      GrTextureDomainEffect::kDecal_WrapMode))->unref();
    fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL);

    drawState->disableStage(0);
    drawState->setViewMatrix(oldMatrix);
}
コード例 #2
0
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn,
                                            GrTexture** result,
                                            GrIRect *devResultBounds) {
    GrAssert(NULL != devResultBounds);
    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);

    if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) {
        fCurrClipMaskType = kAlpha_ClipMaskType;
        return true;
    }

    // Note: 'resultBounds' is in device (as opposed to canvas) coordinates

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

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

    GrDrawTarget::AutoGeometryPush agp(fGpu);

    // The mask we generate is translated so that its upper-left corner is at devResultBounds
    // upper-left corner in device space.
    GrIRect maskResultBounds = GrIRect::MakeWH(devResultBounds->width(), devResultBounds->height());

    // Set the matrix so that rendered clip elements are transformed from the space of the clip
    // stack to the alpha-mask. This accounts for both translation due to the clip-origin and the
    // placement of the mask within the device.
    SkVector clipToMaskOffset = {
        SkIntToScalar(-devResultBounds->fLeft - clipDataIn.fOrigin.fX),
        SkIntToScalar(-devResultBounds->fTop - clipDataIn.fOrigin.fY)
    };
    drawState->viewMatrix()->setTranslate(clipToMaskOffset);

    bool clearToInside;
    SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning

    SkClipStack::Iter iter(*clipDataIn.fClipStack,
                           SkClipStack::Iter::kBottom_IterStart);
    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                              *devResultBounds,
                                                              &clearToInside,
                                                              &firstOp,
                                                              clipDataIn);
    // The scratch texture that we are drawing into can be substantially larger than the mask. Only
    // clear the part that we care about.
    fGpu->clear(&maskResultBounds,
                clearToInside ? 0xffffffff : 0x00000000,
                accum->asRenderTarget());
    bool accumClearedToZero = !clearToInside;

    GrAutoScratchTexture temp;
    bool first = true;
    // walk through each clip element and perform its set op
    for ( ; NULL != clip; clip = iter.nextCombined()) {

        SkRegion::Op op = clip->fOp;
        if (first) {
            first = false;
            op = firstOp;
        }

        if (SkRegion::kReplace_Op == op) {
            // clear the accumulator and draw the new object directly into it
            if (!accumClearedToZero) {
                fGpu->clear(&maskResultBounds, 0x00000000, accum->asRenderTarget());
            }

            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(accum, clip, *devResultBounds);

        } 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 && NULL != clip->fRect &&
                contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
                continue;
            }

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

            // this is the bounds of the clip element in the space of the alpha-mask. The temporary
            // mask buffer can be substantially larger than the actually clip stack element. We
            // touch the minimum number of pixels necessary and use decal mode to combine it with
            // the accumulator
            GrRect elementMaskBounds = clip->getBounds();
            elementMaskBounds.offset(clipToMaskOffset);
            GrIRect elementMaskIBounds;
            elementMaskBounds.roundOut(&elementMaskIBounds);

            // clear the temp target & draw into it
            fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget());

            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
            this->drawClipShape(temp.texture(), clip, elementMaskIBounds);

            // Now draw into the accumulator using the real operation
            // and the temp buffer as a texture
            this->mergeMask(accum, temp.texture(), op, maskResultBounds, elementMaskIBounds);
        } else {
            // all the remaining ops can just be directly draw into
            // the accumulation buffer
            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(accum, clip, *devResultBounds);
        }
        accumClearedToZero = false;
    }

    *result = accum;
    fCurrClipMaskType = kAlpha_ClipMaskType;
    return true;
}
コード例 #3
0
ファイル: GrClipMaskManager.cpp プロジェクト: Beifeng/WTL-DUI
////////////////////////////////////////////////////////////////////////////////
// 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;
}
コード例 #4
0
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn,
                                            GrTexture** result,
                                            GrIRect *devResultBounds) {
    GrAssert(NULL != devResultBounds);
    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);

    if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) {
        fCurrClipMaskType = kAlpha_ClipMaskType;
        return true;
    }

    // Note: 'resultBounds' is in device (as opposed to canvas) coordinates

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

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

    GrDrawTarget::AutoGeometryPush agp(fGpu);

    if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
        0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
        // 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
        drawState->viewMatrix()->setTranslate(
                SkIntToScalar(-devResultBounds->fLeft-clipDataIn.fOrigin.fX),
                SkIntToScalar(-devResultBounds->fTop-clipDataIn.fOrigin.fY));
    }

    bool clearToInside;
    SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning

    SkClipStack::Iter iter(*clipDataIn.fClipStack,
                           SkClipStack::Iter::kBottom_IterStart);
    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                              *devResultBounds,
                                                              &clearToInside,
                                                              &firstOp,
                                                              clipDataIn);

    fGpu->clear(NULL,
                clearToInside ? 0xffffffff : 0x00000000,
                accum->asRenderTarget());

    GrAutoScratchTexture temp;
    bool first = true;
    // walk through each clip element and perform its set op
    for ( ; NULL != clip; clip = iter.next()) {

        SkRegion::Op op = clip->fOp;
        if (first) {
            first = false;
            op = firstOp;
        }

        if (SkRegion::kReplace_Op == op) {
            // clear the accumulator and draw the new object directly into it
            fGpu->clear(NULL, 0x00000000, accum->asRenderTarget());

            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(accum, clip, *devResultBounds);

        } 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 && NULL != clip->fRect &&
                contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
                continue;
            }

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

            // clear the temp target & draw into it
            fGpu->clear(NULL, 0x00000000, temp.texture()->asRenderTarget());

            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
            this->drawClipShape(temp.texture(), clip, *devResultBounds);

            // TODO: rather than adding these two translations here
            // compute the bounding box needed to render the texture
            // into temp
            if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
                0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
                // In order for the merge of the temp clip into the accumulator
                // to work we need to disable the translation
                drawState->viewMatrix()->reset();
            }

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

            if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
                0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
                drawState->viewMatrix()->setTranslate(
                  SkIntToScalar(-devResultBounds->fLeft-clipDataIn.fOrigin.fX),
                  SkIntToScalar(-devResultBounds->fTop-clipDataIn.fOrigin.fY));
            }

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

    *result = accum;
    fCurrClipMaskType = kAlpha_ClipMaskType;
    return true;
}