bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds) { if (!pipelineBuilder.willXPNeedDstCopy(*this->caps(), colorPOI, coveragePOI)) { return true; } SkIRect copyRect; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); pipelineBuilder.clip().getConservativeBounds(rt, ©Rect); if (drawBounds) { SkIRect drawIBounds; drawBounds->roundOut(&drawIBounds); if (!copyRect.intersect(drawIBounds)) { #ifdef SK_DEBUG SkDebugf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n"); #endif return false; } } else { #ifdef SK_DEBUG //SkDebugf("No dev bounds when dst copy is made.\n"); #endif } // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrSurfaceDesc desc; this->initCopySurfaceDstDesc(rt, &desc); desc.fWidth = copyRect.width(); desc.fHeight = copyRect.height(); SkAutoTUnref<GrTexture> copy( fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch)); if (!copy) { SkDebugf("Failed to create temporary copy of destination texture.\n"); return false; } SkIPoint dstPoint = {0, 0}; if (this->copySurface(copy, rt, copyRect, dstPoint)) { dstCopy->setTexture(copy); dstCopy->setOffset(copyRect.fLeft, copyRect.fTop); return true; } else { return false; } }
bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder, const GrPipelineOptimizations& optimizations, GrXferProcessor::DstTexture* dstTexture, const SkRect& batchBounds) { SkRect bounds = batchBounds; bounds.outset(0.5f, 0.5f); if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) { return true; } GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); if (this->caps()->textureBarrierSupport()) { if (GrTexture* rtTex = rt->asTexture()) { // The render target is a texture, so we can read from it directly in the shader. The XP // will be responsible to detect this situation and request a texture barrier. dstTexture->setTexture(rtTex); dstTexture->setOffset(0, 0); return true; } } SkIRect copyRect; pipelineBuilder.clip().getConservativeBounds(rt->width(), rt->height(), ©Rect); SkIRect drawIBounds; bounds.roundOut(&drawIBounds); if (!copyRect.intersect(drawIBounds)) { #ifdef SK_DEBUG GrCapsDebugf(this->caps(), "Missed an early reject. " "Bailing on draw from setupDstReadIfNecessary.\n"); #endif return false; } // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrSurfaceDesc desc; if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) { desc.fOrigin = kDefault_GrSurfaceOrigin; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fConfig = rt->config(); } desc.fWidth = copyRect.width(); desc.fHeight = copyRect.height(); static const uint32_t kFlags = 0; SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags)); if (!copy) { SkDebugf("Failed to create temporary copy of destination texture.\n"); return false; } SkIPoint dstPoint = {0, 0}; this->copySurface(copy, rt, copyRect, dstPoint); dstTexture->setTexture(copy); dstTexture->setOffset(copyRect.fLeft, copyRect.fTop); return true; }
//////////////////////////////////////////////////////////////////////////////// // sort out what kind of clip mask needs to be created: alpha, stencil, // scissor, or entirely software bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, GrPipelineBuilder::AutoRestoreStencil* ars, GrScissorState* scissorState, const SkRect* devBounds, GrAppliedClip* out) { if (kRespectClip_StencilClipMode == fClipMode) { fClipMode = kIgnoreClip_StencilClipMode; } GrReducedClip::ElementList elements(16); int32_t genID = 0; GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialState; SkIRect clipSpaceIBounds; bool requiresAA = false; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); // GrDrawTarget should have filtered this for us SkASSERT(rt); SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); const GrClip& clip = pipelineBuilder.clip(); if (clip.isWideOpen(clipSpaceRTIBounds)) { this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } // The clip mask manager always draws with a single IRect so we special case that logic here // Image filters just use a rect, so we also special case that logic switch (clip.clipType()) { case GrClip::kWideOpen_ClipType: SkFAIL("Should have caught this with clip.isWideOpen()"); return true; case GrClip::kIRect_ClipType: { SkIRect scissor = clip.irect(); if (scissor.intersect(clipSpaceRTIBounds)) { scissorState->set(scissor); this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } return false; } case GrClip::kClipStack_ClipType: { clipSpaceRTIBounds.offset(clip.origin()); GrReducedClip::ReduceClipStack(*clip.clipStack(), clipSpaceRTIBounds, &elements, &genID, &initialState, &clipSpaceIBounds, &requiresAA); if (elements.isEmpty()) { if (GrReducedClip::kAllIn_InitialState == initialState) { if (clipSpaceIBounds == clipSpaceRTIBounds) { this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } } else { return false; } } } break; } // An element count of 4 was chosen because of the common pattern in Blink of: // isect RR // diff RR // isect convex_poly // isect convex_poly // when drawing rounded div borders. This could probably be tuned based on a // configuration's relative costs of switching RTs to generate a mask vs // longer shaders. if (elements.count() <= kMaxAnalyticElements) { SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), SkIntToScalar(-clip.origin().fY) }; // When there are multiple color samples we want to do per-sample clipping, not compute // a fractional pixel coverage. bool disallowAnalyticAA = pipelineBuilder.getRenderTarget()->isUnifiedMultisampled(); const GrFragmentProcessor* clipFP = nullptr; if (elements.isEmpty() || (requiresAA && !disallowAnalyticAA && SkToBool(clipFP = this->getAnalyticClipProcessor(elements, clipToRTOffset, devBounds)))) { SkIRect scissorSpaceIBounds(clipSpaceIBounds); scissorSpaceIBounds.offset(-clip.origin()); if (nullptr == devBounds || !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { scissorState->set(scissorSpaceIBounds); } this->setPipelineBuilderStencil(pipelineBuilder, ars); out->fClipCoverageFP.reset(clipFP); return true; } } // If MSAA is enabled we can do everything in the stencil buffer. if (0 == rt->numStencilSamples() && requiresAA) { SkAutoTUnref<GrTexture> result; // The top-left of the mask corresponds to the top-left corner of the bounds. SkVector clipToMaskOffset = { SkIntToScalar(-clipSpaceIBounds.fLeft), SkIntToScalar(-clipSpaceIBounds.fTop) }; if (this->useSWOnlyPath(pipelineBuilder, clipToMaskOffset, elements)) { // The clip geometry is complex enough that it will be more efficient to create it // entirely in software result.reset(this->createSoftwareClipMask(genID, initialState, elements, clipToMaskOffset, clipSpaceIBounds)); } else { result.reset(this->createAlphaClipMask(genID, initialState, elements, clipToMaskOffset, clipSpaceIBounds)); } if (result) { // The mask's top left coord should be pinned to the rounded-out top left corner of // clipSpace bounds. We determine the mask's position WRT to the render target here. SkIRect rtSpaceMaskBounds = clipSpaceIBounds; rtSpaceMaskBounds.offset(-clip.origin()); out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds)); this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } // if alpha clip mask creation fails fall through to the non-AA code paths } // use the stencil clip if we can't represent the clip as a rectangle. SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); this->createStencilClipMask(rt, genID, initialState, elements, clipSpaceIBounds, clipSpaceToStencilSpaceOffset); // This must occur after createStencilClipMask. That function may change the scissor. Also, it // only guarantees that the stencil mask is correct within the bounds it was passed, so we must // use both stencil and scissor test to the bounds for the final draw. SkIRect scissorSpaceIBounds(clipSpaceIBounds); scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); scissorState->set(scissorSpaceIBounds); this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; }