void GrVkGpuRTCommandBuffer::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { SkASSERT(!clip.hasWindowRectangles()); CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo]; GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment(); // this should only be called internally when we know we have a // stencil buffer. SkASSERT(sb); int stencilBitCount = sb->bits(); // The contract with the callers does not guarantee that we preserve all bits in the stencil // during this clear. Thus we will clear the entire stencil to the desired value. VkClearDepthStencilValue vkStencilColor; memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue)); if (insideStencilMask) { vkStencilColor.stencil = (1 << (stencilBitCount - 1)); } else { vkStencilColor.stencil = 0; } VkClearRect clearRect; // Flip rect if necessary SkIRect vkRect; if (!clip.scissorEnabled()) { vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height()); } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) { vkRect = clip.scissorRect(); } else { const SkIRect& scissor = clip.scissorRect(); vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom, scissor.fRight, fRenderTarget->height() - scissor.fTop); } clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() }; clearRect.baseArrayLayer = 0; clearRect.layerCount = 1; uint32_t stencilIndex; SkAssertResult(cbInfo.fRenderPass->stencilAttachmentIndex(&stencilIndex)); VkClearAttachment attachment; attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; attachment.colorAttachment = 0; // this value shouldn't matter attachment.clearValue.depthStencil = vkStencilColor; cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect); cbInfo.fIsEmpty = false; // Update command buffer bounds if (!clip.scissorEnabled()) { cbInfo.fBounds.join(fRenderTarget->getBoundsRect()); } else { cbInfo.fBounds.join(SkRect::Make(clip.scissorRect())); } }
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, GrDrawContext* drawContext, const GrClip& clip, const SkMatrix& viewMatrix, const GrPath* path, GrPathRendering::FillType fill) { // TODO: extract portions of checkDraw that are relevant to path stenciling. SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); // Setup clip GrAppliedClip appliedClip; if (!clip.apply(fContext, pipelineBuilder, drawContext, nullptr, &appliedClip)) { return; } // TODO: respect fClipBatchToBounds if we ever start computing bounds here. // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never // attempt this in a situation that would require coverage AA. SkASSERT(!appliedClip.getClipCoverageFragmentProcessor()); GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment( drawContext->accessRenderTarget()); if (!stencilAttachment) { SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); return; } GrBatch* batch = GrStencilPathBatch::Create(viewMatrix, pipelineBuilder.isHWAntialias(), fill, appliedClip.hasStencilClip(), stencilAttachment->bits(), appliedClip.scissorState(), drawContext->accessRenderTarget(), path); this->recordBatch(batch); batch->unref(); }
void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipelineBuilder, GrPipelineBuilder::AutoRestoreStencil* ars) { // We make two copies of the StencilSettings here (except in the early // exit scenario. One copy from draw state to the stack var. Then another // from the stack var to the gpu. We could make this class hold a ptr to // GrGpu's fStencilSettings and eliminate the stack copy here. // use stencil for clipping if clipping is enabled and the clip // has been written into the stencil. GrStencilSettings settings; // The GrGpu client may not be using the stencil buffer but we may need to // enable it in order to respect a stencil clip. if (pipelineBuilder.getStencil().isDisabled()) { if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { settings = basic_apply_stencil_clip_settings(); } else { return; } } else { settings = pipelineBuilder.getStencil(); } int stencilBits = 0; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); GrStencilAttachment* stencilAttachment = fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); if (stencilAttachment) { stencilBits = stencilAttachment->bits(); } SkASSERT(fDrawTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); SkASSERT(fDrawTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); this->adjustStencilParams(&settings, fClipMode, stencilBits); ars->set(&pipelineBuilder); ars->setStencil(settings); }
//////////////////////////////////////////////////////////////////////////////// // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device // (as opposed to canvas) coordinates bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, int32_t elementsGenID, GrReducedClip::InitialState initialState, const GrReducedClip::ElementList& elements, const SkIRect& clipSpaceIBounds, const SkIPoint& clipSpaceToStencilOffset) { SkASSERT(rt); GrStencilAttachment* stencilAttachment = fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); if (nullptr == stencilAttachment) { return false; } 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); GrClip clip(stencilSpaceIBounds); int clipBit = stencilAttachment->bits(); SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); clipBit = (1 << (clipBit-1)); fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds, GrReducedClip::kAllIn_InitialState == initialState, rt); // 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(); GrPipelineBuilder pipelineBuilder; pipelineBuilder.setClip(clip); pipelineBuilder.setRenderTarget(rt); pipelineBuilder.setDisableColorXPFactory(); // if the target is MSAA then we want MSAA enabled when the clip is soft if (rt->isStencilBufferMultisampled()) { pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, element->isAA()); } bool fillInverted = false; // enabled at bottom of loop fClipMode = kIgnoreClip_StencilClipMode; // This will be used to determine whether the clip shape can be rendered into the // stencil with arbitrary stencil settings. GrPathRenderer::StencilSupport stencilSupport; GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); 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(); } pr = this->getContext()->getPathRenderer(fDrawTarget, &pipelineBuilder, viewMatrix, clipPath, stroke, false, GrPathRendererChain::kStencilOnly_DrawType, &stencilSupport); if (nullptr == pr) { return false; } } int passes; GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; bool canRenderDirectToStencil = GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; 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); if (Element::kRect_Type == element->getType()) { *pipelineBuilder.stencil() = gDrawToStencil; // We need this AGP until everything is in GrBatch fDrawTarget->drawNonAARect(pipelineBuilder, GrColor_WHITE, viewMatrix, element->getRect()); } else { if (!clipPath.isEmpty()) { if (canRenderDirectToStencil) { *pipelineBuilder.stencil() = gDrawToStencil; GrPathRenderer::DrawPathArgs args; args.fTarget = fDrawTarget; args.fResourceProvider = this->getContext()->resourceProvider(); args.fPipelineBuilder = &pipelineBuilder; args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fPath = &clipPath; args.fStroke = &stroke; args.fAntiAlias = false; pr->drawPath(args); } else { GrPathRenderer::StencilPathArgs args; args.fTarget = fDrawTarget; args.fResourceProvider = this->getContext()->resourceProvider(); args.fPipelineBuilder = &pipelineBuilder; args.fViewMatrix = &viewMatrix; args.fPath = &clipPath; args.fStroke = &stroke; pr->stencilPath(args); } } } } // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. fClipMode = kModifyClip_StencilClipMode; for (int p = 0; p < passes; ++p) { *pipelineBuilder.stencil() = stencilSettings[p]; if (canDrawDirectToClip) { if (Element::kRect_Type == element->getType()) { // We need this AGP until everything is in GrBatch fDrawTarget->drawNonAARect(pipelineBuilder, GrColor_WHITE, viewMatrix, element->getRect()); } else { GrPathRenderer::DrawPathArgs args; args.fTarget = fDrawTarget; args.fResourceProvider = this->getContext()->resourceProvider(); args.fPipelineBuilder = &pipelineBuilder; args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fPath = &clipPath; args.fStroke = &stroke; args.fAntiAlias = false; pr->drawPath(args); } } else { // The view matrix is setup to do clip space -> stencil space translation, so // draw rect in clip space. fDrawTarget->drawNonAARect(pipelineBuilder, GrColor_WHITE, viewMatrix, SkRect::Make(clipSpaceIBounds)); } } } } fClipMode = kRespectClip_StencilClipMode; return true; }