void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), "GrDefaultPathRenderer::onStencilPath"); SkASSERT(!args.fShape->inverseFilled()); GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Make()); paint.setAntiAlias(args.fIsAA); this->internalDrawPath(args.fDrawContext, paint, GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix, *args.fShape, true); }
// Create a mask of 'devPath' and place the result in 'mask'. static GrTexture* create_mask_GPU(GrContext* context, SkRect* maskRect, const SkPath& devPath, const GrStrokeInfo& strokeInfo, bool doAA, int sampleCnt) { // This mask will ultimately be drawn as a non-AA rect (see draw_mask). // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here // so the mask draws in a reproducible manner. *maskRect = SkRect::Make(maskRect->roundOut()); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = SkScalarCeilToInt(maskRect->width()); desc.fHeight = SkScalarCeilToInt(maskRect->height()); desc.fSampleCnt = doAA ? sampleCnt : 0; // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 desc.fConfig = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) { desc.fConfig = kAlpha_8_GrPixelConfig; } GrTexture* mask = context->textureProvider()->createApproxTexture(desc); if (nullptr == mask) { return nullptr; } SkRect clipRect = SkRect::MakeWH(maskRect->width(), maskRect->height()); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(mask->asRenderTarget())); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip GrClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-maskRect->fLeft, -maskRect->fTop); drawContext->drawPath(clip, tempPaint, translate, devPath, strokeInfo); return mask; }
// Create a mask of 'devPath' and place the result in 'mask'. static GrTexture* create_mask_GPU(GrContext* context, const SkRect& maskRect, const SkPath& devPath, const GrStrokeInfo& strokeInfo, bool doAA, int sampleCnt) { GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = SkScalarCeilToInt(maskRect.width()); desc.fHeight = SkScalarCeilToInt(maskRect.height()); desc.fSampleCnt = doAA ? sampleCnt : 0; // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 desc.fConfig = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) { desc.fConfig = kAlpha_8_GrPixelConfig; } GrTexture* mask = context->textureProvider()->createApproxTexture(desc); if (nullptr == mask) { return nullptr; } SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); GrDrawContext* drawContext = context->drawContext(); if (!drawContext) { return nullptr; } drawContext->clear(mask->asRenderTarget(), nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip GrClip clip(clipRect); // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint. SkMatrix translate; translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo); return mask; }
// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 GrPixelConfig config = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, sampleCnt > 0)) { config = kAlpha_8_GrPixelConfig; } sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), config, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), "GrDefaultPathRenderer::onStencilPath"); SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType()); SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType()); GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Make()); paint.setAntiAlias(args.fIsAA); this->internalDrawPath(args.fDrawContext, paint, &GrUserStencilSettings::kUnused, *args.fClip, GrColor_WHITE, *args.fViewMatrix, *args.fPath, GrStyle::SimpleFill(), true); }
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (context->abandoned()) { return; } if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } GrPaint paint; if (!SkPaintToGrPaint(context, dc, skPaint, viewMatrix, &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { // The run's "font" overrides the anti-aliasing of the passed in paint! paint.setAntiAlias(run->isAntiAlias()); run->draw(context, dc, paint, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } sk_sp<GrDrawContext> drawContext(context->makeDrawContextWithFallback(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), kAlpha_8_GrPixelConfig, nullptr, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
//////////////////////////////////////////////////////////////////////////////// // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device // (as opposed to canvas) coordinates bool GrClipMaskManager::CreateStencilClipMask(GrContext* context, GrDrawContext* drawContext, int32_t elementsGenID, GrReducedClip::InitialState initialState, const GrReducedClip::ElementList& elements, const SkIRect& clipSpaceIBounds, const SkIPoint& clipSpaceToStencilOffset) { SkASSERT(drawContext); GrStencilAttachment* stencilAttachment = context->resourceProvider()->attachStencilAttachment( drawContext->accessRenderTarget()); if (nullptr == stencilAttachment) { return false; } // TODO: these need to be swapped over to using a StencilAttachmentProxy if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) { stencilAttachment->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset); // Set the matrix so that rendered clip elements are transformed from clip to stencil space. SkVector translate = { SkIntToScalar(clipSpaceToStencilOffset.fX), SkIntToScalar(clipSpaceToStencilOffset.fY) }; SkMatrix viewMatrix; viewMatrix.setTranslate(translate); // We set the current clip to the bounds so that our recursive draws are scissored to them. SkIRect stencilSpaceIBounds(clipSpaceIBounds); stencilSpaceIBounds.offset(clipSpaceToStencilOffset); GrFixedClip clip(stencilSpaceIBounds); drawContext->drawContextPriv().clearStencilClip( stencilSpaceIBounds, GrReducedClip::kAllIn_InitialState == initialState); // walk through each clip element and perform its set op // with the existing clip. for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { const Element* element = iter.get(); bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled(); bool fillInverted = false; // enabled at bottom of loop clip.enableStencilClip(false); // This will be used to determine whether the clip shape can be rendered into the // stencil with arbitrary stencil settings. GrPathRenderer::StencilSupport stencilSupport; SkRegion::Op op = element->getOp(); GrPathRenderer* pr = nullptr; SkPath clipPath; if (Element::kRect_Type == element->getType()) { stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; fillInverted = false; } else { element->asPath(&clipPath); fillInverted = clipPath.isInverseFillType(); if (fillInverted) { clipPath.toggleInverseFillType(); } GrShape shape(clipPath, GrStyle::SimpleFill()); GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fShape = &shape; canDrawArgs.fAntiAlias = false; canDrawArgs.fHasUserStencilSettings = false; canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); pr = context->drawingManager()->getPathRenderer(canDrawArgs, false, GrPathRendererChain::kStencilOnly_DrawType, &stencilSupport); if (!pr) { return false; } } bool canRenderDirectToStencil = GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; bool drawDirectToClip; // Given the renderer, the element, // fill rule, and set operation should // we render the element directly to // stencil bit used for clipping. GrUserStencilSettings const* const* stencilPasses = GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted, &drawDirectToClip); // draw the element to the client stencil bits if necessary if (!drawDirectToClip) { static constexpr GrUserStencilSettings kDrawToStencil( GrUserStencilSettings::StaticInit< 0x0000, GrUserStencilTest::kAlways, 0xffff, GrUserStencilOp::kIncMaybeClamp, GrUserStencilOp::kIncMaybeClamp, 0xffff>() ); if (Element::kRect_Type == element->getType()) { drawContext->drawContextPriv().stencilRect(clip, &kDrawToStencil, useHWAA, viewMatrix, element->getRect()); } else { if (!clipPath.isEmpty()) { GrShape shape(clipPath, GrStyle::SimpleFill()); if (canRenderDirectToStencil) { GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Make()); paint.setAntiAlias(element->isAA()); GrPathRenderer::DrawPathArgs args; args.fResourceProvider = context->resourceProvider(); args.fPaint = &paint; args.fUserStencilSettings = &kDrawToStencil; args.fDrawContext = drawContext; args.fClip = &clip; args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fShape = &shape; args.fAntiAlias = false; args.fGammaCorrect = false; pr->drawPath(args); } else { GrPathRenderer::StencilPathArgs args; args.fResourceProvider = context->resourceProvider(); args.fDrawContext = drawContext; args.fClip = &clip; args.fViewMatrix = &viewMatrix; args.fIsAA = element->isAA(); args.fShape = &shape; pr->stencilPath(args); } } } } // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. clip.enableStencilClip(true); for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { if (drawDirectToClip) { if (Element::kRect_Type == element->getType()) { drawContext->drawContextPriv().stencilRect(clip, *pass, useHWAA, viewMatrix, element->getRect()); } else { GrShape shape(clipPath, GrStyle::SimpleFill()); GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Make()); paint.setAntiAlias(element->isAA()); GrPathRenderer::DrawPathArgs args; args.fResourceProvider = context->resourceProvider(); args.fPaint = &paint; args.fUserStencilSettings = *pass; args.fDrawContext = drawContext; args.fClip = &clip; args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fShape = &shape; args.fAntiAlias = false; args.fGammaCorrect = false; pr->drawPath(args); } } else { // The view matrix is setup to do clip space -> stencil space translation, so // draw rect in clip space. drawContext->drawContextPriv().stencilRect(clip, *pass, false, viewMatrix, SkRect::Make(clipSpaceIBounds)); } } } } return true; }
sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context, int32_t elementsGenID, GrReducedClip::InitialState initialState, const GrReducedClip::ElementList& elements, const SkVector& clipToMaskOffset, const SkIRect& clipSpaceIBounds) { GrResourceProvider* resourceProvider = context->resourceProvider(); GrUniqueKey key; GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) { return sk_sp<GrTexture>(texture); } // There's no texture in the cache. Let's try to allocate it then. GrPixelConfig config = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { config = kAlpha_8_GrPixelConfig; } sk_sp<GrDrawContext> dc(context->newDrawContext(SkBackingFit::kApprox, clipSpaceIBounds.width(), clipSpaceIBounds.height(), config)); if (!dc) { return nullptr; } // The texture may be larger than necessary, this rect represents the part of the texture // we populate with a rasterization of the clip. SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height()); // The scratch texture that we are drawing into can be substantially larger than the mask. Only // clear the part that we care about. dc->clear(&maskSpaceIBounds, GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000, true); // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); // It is important that we use maskSpaceIBounds as the stencil rect in the below loop. // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first // pass must not set values outside of this bounds or stencil values outside the rect won't be // cleared. // walk through each clip element and perform its set op for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) { const Element* element = iter.get(); SkRegion::Op op = element->getOp(); bool invert = element->isInverseFilled(); if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { GrFixedClip clip(maskSpaceIBounds); // draw directly into the result with the stencil set to make the pixels affected // by the clip shape be non-zero. static constexpr GrUserStencilSettings kStencilInElement( GrUserStencilSettings::StaticInit< 0xffff, GrUserStencilTest::kAlways, 0xffff, GrUserStencilOp::kReplace, GrUserStencilOp::kReplace, 0xffff>() ); if (!stencil_element(dc.get(), clip, &kStencilInElement, translate, element)) { return nullptr; } // Draw to the exterior pixels (those with a zero stencil value). static constexpr GrUserStencilSettings kDrawOutsideElement( GrUserStencilSettings::StaticInit< 0x0000, GrUserStencilTest::kEqual, 0xffff, GrUserStencilOp::kZero, GrUserStencilOp::kZero, 0xffff>() ); if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, false, translate, SkRect::Make(clipSpaceIBounds))) { return nullptr; } } else { // all the remaining ops can just be directly draw into the accumulation buffer GrPaint paint; paint.setAntiAlias(element->isAA()); paint.setCoverageSetOpXPFactory(op, false); draw_element(dc.get(), GrNoClip(), paint, translate, element); } } sk_sp<GrTexture> texture(dc->asTexture()); SkASSERT(texture); texture->resourcePriv().setUniqueKey(key); return texture; }