1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceFillContext_v1.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/GrImageContext.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrDstProxyView.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrImageContextPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 14cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 15cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrRect.h" 16cb93a386Sopenharmony_ci#include "src/gpu/ops/ClearOp.h" 17cb93a386Sopenharmony_ci#include "src/gpu/ops/FillRectOp.h" 18cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner()) 21cb93a386Sopenharmony_ci#define RETURN_IF_ABANDONED if (fContext->abandoned()) { return; } 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciclass AutoCheckFlush { 24cb93a386Sopenharmony_cipublic: 25cb93a386Sopenharmony_ci AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { 26cb93a386Sopenharmony_ci SkASSERT(fDrawingManager); 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); } 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ciprivate: 31cb93a386Sopenharmony_ci GrDrawingManager* fDrawingManager; 32cb93a386Sopenharmony_ci}; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cinamespace skgpu::v1 { 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress 37cb93a386Sopenharmony_ci// OpsTask to be picked up and added to by SurfaceFillContext lower in the call 38cb93a386Sopenharmony_ci// stack. When this occurs with a closed OpsTask, a new one will be allocated 39cb93a386Sopenharmony_ci// when the SurfaceFillContext attempts to use it (via getOpsTask). 40cb93a386Sopenharmony_ciSurfaceFillContext::SurfaceFillContext(GrRecordingContext* rContext, 41cb93a386Sopenharmony_ci GrSurfaceProxyView readView, 42cb93a386Sopenharmony_ci GrSurfaceProxyView writeView, 43cb93a386Sopenharmony_ci const GrColorInfo& colorInfo, 44cb93a386Sopenharmony_ci bool flushTimeOpsTask) 45cb93a386Sopenharmony_ci : skgpu::SurfaceFillContext(rContext, 46cb93a386Sopenharmony_ci std::move(readView), 47cb93a386Sopenharmony_ci std::move(writeView), 48cb93a386Sopenharmony_ci std::move(colorInfo)) 49cb93a386Sopenharmony_ci , fFlushTimeOpsTask(flushTimeOpsTask) { 50cb93a386Sopenharmony_ci fOpsTask = sk_ref_sp(rContext->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy())); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_civoid SurfaceFillContext::fillRectWithFP(const SkIRect& dstRect, 56cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp) { 57cb93a386Sopenharmony_ci ASSERT_SINGLE_OWNER 58cb93a386Sopenharmony_ci RETURN_IF_ABANDONED 59cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 60cb93a386Sopenharmony_ci GR_CREATE_TRACE_MARKER_CONTEXT("v1::SurfaceFillContext", "fillRectWithFP", fContext); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci AutoCheckFlush acf(this->drawingManager()); 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci GrPaint paint; 65cb93a386Sopenharmony_ci paint.setColorFragmentProcessor(std::move(fp)); 66cb93a386Sopenharmony_ci paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 67cb93a386Sopenharmony_ci auto op = FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), 68cb93a386Sopenharmony_ci SkRect::Make(dstRect)); 69cb93a386Sopenharmony_ci this->addDrawOp(std::move(op)); 70cb93a386Sopenharmony_ci} 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_civoid SurfaceFillContext::addDrawOp(GrOp::Owner owner) { 73cb93a386Sopenharmony_ci GrDrawOp* op = static_cast<GrDrawOp*>(owner.get()); 74cb93a386Sopenharmony_ci GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType()); 75cb93a386Sopenharmony_ci auto clip = GrAppliedClip::Disabled(); 76cb93a386Sopenharmony_ci const GrCaps& caps = *this->caps(); 77cb93a386Sopenharmony_ci GrProcessorSet::Analysis analysis = op->finalize(caps, &clip, clampType); 78cb93a386Sopenharmony_ci SkASSERT(!op->usesStencil()); 79cb93a386Sopenharmony_ci SkASSERT(!analysis.requiresDstTexture()); 80cb93a386Sopenharmony_ci SkRect bounds = owner->bounds(); 81cb93a386Sopenharmony_ci // We shouldn't have coverage AA or hairline draws in fill contexts. 82cb93a386Sopenharmony_ci SkASSERT(!op->hasAABloat() && !op->hasZeroArea()); 83cb93a386Sopenharmony_ci if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) { 84cb93a386Sopenharmony_ci return; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci op->setClippedBounds(op->bounds()); 87cb93a386Sopenharmony_ci SkDEBUGCODE(op->fAddDrawOpCalled = true;) 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci GrDstProxyView dstProxyView; 90cb93a386Sopenharmony_ci this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(), 91cb93a386Sopenharmony_ci std::move(owner), 92cb93a386Sopenharmony_ci op->usesMSAA(), 93cb93a386Sopenharmony_ci analysis, 94cb93a386Sopenharmony_ci std::move(clip), 95cb93a386Sopenharmony_ci dstProxyView, 96cb93a386Sopenharmony_ci GrTextureResolveManager(this->drawingManager()), 97cb93a386Sopenharmony_ci caps); 98cb93a386Sopenharmony_ci} 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_civoid SurfaceFillContext::ClearToGrPaint(std::array<float, 4> color, GrPaint* paint) { 101cb93a386Sopenharmony_ci paint->setColor4f({color[0], color[1], color[2], color[3]}); 102cb93a386Sopenharmony_ci if (color[3] == 1.f) { 103cb93a386Sopenharmony_ci // Can just rely on the src-over blend mode to do the right thing. 104cb93a386Sopenharmony_ci // This may improve batching. 105cb93a386Sopenharmony_ci paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver); 106cb93a386Sopenharmony_ci } else { 107cb93a386Sopenharmony_ci // A clear overwrites the prior color, so even if it's transparent, it behaves as if it 108cb93a386Sopenharmony_ci // were src blended 109cb93a386Sopenharmony_ci paint->setPorterDuffXPFactory(SkBlendMode::kSrc); 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_civoid SurfaceFillContext::addOp(GrOp::Owner op) { 114cb93a386Sopenharmony_ci auto direct = fContext->priv().asDirectContext(); 115cb93a386Sopenharmony_ci if (direct && op) { 116cb93a386Sopenharmony_ci op->setGrOpTag(direct->getCurrentGrResourceTag()); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci GrDrawingManager* drawingMgr = this->drawingManager(); 119cb93a386Sopenharmony_ci this->getOpsTask()->addOp(drawingMgr, 120cb93a386Sopenharmony_ci std::move(op), 121cb93a386Sopenharmony_ci GrTextureResolveManager(drawingMgr), 122cb93a386Sopenharmony_ci *this->caps()); 123cb93a386Sopenharmony_ci} 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ciOpsTask* SurfaceFillContext::getOpsTask() { 126cb93a386Sopenharmony_ci ASSERT_SINGLE_OWNER 127cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci if (!fOpsTask || fOpsTask->isClosed()) { 130cb93a386Sopenharmony_ci this->replaceOpsTask(); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci SkASSERT(!fOpsTask->isClosed()); 133cb93a386Sopenharmony_ci return fOpsTask.get(); 134cb93a386Sopenharmony_ci} 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_cisk_sp<GrRenderTask> SurfaceFillContext::refRenderTask() { 137cb93a386Sopenharmony_ci return sk_ref_sp(this->getOpsTask()); 138cb93a386Sopenharmony_ci} 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ciOpsTask* SurfaceFillContext::replaceOpsTask() { 141cb93a386Sopenharmony_ci sk_sp<OpsTask> newOpsTask = this->drawingManager()->newOpsTask( 142cb93a386Sopenharmony_ci this->writeSurfaceView(), this->arenas(), fFlushTimeOpsTask); 143cb93a386Sopenharmony_ci this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get()); 144cb93a386Sopenharmony_ci fOpsTask = std::move(newOpsTask); 145cb93a386Sopenharmony_ci return fOpsTask.get(); 146cb93a386Sopenharmony_ci} 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci#ifdef SK_DEBUG 149cb93a386Sopenharmony_civoid SurfaceFillContext::onValidate() const { 150cb93a386Sopenharmony_ci if (fOpsTask && !fOpsTask->isClosed()) { 151cb93a386Sopenharmony_ci SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get()); 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci} 154cb93a386Sopenharmony_ci#endif 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_civoid SurfaceFillContext::discard() { 157cb93a386Sopenharmony_ci ASSERT_SINGLE_OWNER 158cb93a386Sopenharmony_ci RETURN_IF_ABANDONED 159cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 160cb93a386Sopenharmony_ci GR_CREATE_TRACE_MARKER_CONTEXT("v1::SurfaceFillContext", "discard", fContext); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci AutoCheckFlush acf(this->drawingManager()); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci this->getOpsTask()->discard(); 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_civoid SurfaceFillContext::internalClear(const SkIRect* scissor, 168cb93a386Sopenharmony_ci std::array<float, 4> color, 169cb93a386Sopenharmony_ci bool upgradePartialToFull) { 170cb93a386Sopenharmony_ci ASSERT_SINGLE_OWNER 171cb93a386Sopenharmony_ci RETURN_IF_ABANDONED 172cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 173cb93a386Sopenharmony_ci GR_CREATE_TRACE_MARKER_CONTEXT("v1::SurfaceFillContext", "clear", fContext); 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci // There are three ways clears are handled: load ops, native clears, and draws. Load ops are 176cb93a386Sopenharmony_ci // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend 177cb93a386Sopenharmony_ci // supports then. Drawing an axis-aligned rect is the fallback path. 178cb93a386Sopenharmony_ci GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions()); 179cb93a386Sopenharmony_ci if (scissor && !scissorState.set(*scissor)) { 180cb93a386Sopenharmony_ci // The clear is offscreen, so skip it (normally this would be handled by addDrawOp, 181cb93a386Sopenharmony_ci // except clear ops are not draw ops). 182cb93a386Sopenharmony_ci return; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable 186cb93a386Sopenharmony_ci // the test. We only do this when the clear would be handled by a load op or natively. 187cb93a386Sopenharmony_ci if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) { 188cb93a386Sopenharmony_ci if (upgradePartialToFull && (this->caps()->preferFullscreenClears() || 189cb93a386Sopenharmony_ci this->caps()->shouldInitializeTextures())) { 190cb93a386Sopenharmony_ci // TODO: wrt the shouldInitializeTextures path, it would be more performant to 191cb93a386Sopenharmony_ci // only clear the entire target if we knew it had not been cleared before. As 192cb93a386Sopenharmony_ci // is this could end up doing a lot of redundant clears. 193cb93a386Sopenharmony_ci scissorState.setDisabled(); 194cb93a386Sopenharmony_ci } else { 195cb93a386Sopenharmony_ci // Unlike with stencil clears, we also allow clears up to the logical dimensions of the 196cb93a386Sopenharmony_ci // render target to overflow into any approx-fit padding of the backing store dimensions 197cb93a386Sopenharmony_ci scissorState.relaxTest(this->dimensions()); 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci if (!scissorState.enabled()) { 202cb93a386Sopenharmony_ci // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also 203cb93a386Sopenharmony_ci // discard all prior ops in the current task since the color buffer will be overwritten. 204cb93a386Sopenharmony_ci auto opsTask = this->getOpsTask(); 205cb93a386Sopenharmony_ci if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) && 206cb93a386Sopenharmony_ci !this->caps()->performColorClearsAsDraws()) { 207cb93a386Sopenharmony_ci color = this->writeSurfaceView().swizzle().applyTo(color); 208cb93a386Sopenharmony_ci // The op list was emptied and native clears are allowed, so just use the load op 209cb93a386Sopenharmony_ci opsTask->setColorLoadOp(GrLoadOp::kClear, color); 210cb93a386Sopenharmony_ci return; 211cb93a386Sopenharmony_ci } else { 212cb93a386Sopenharmony_ci // Will use an op for the clear, reset the load op to discard since the op will 213cb93a386Sopenharmony_ci // blow away the color buffer contents 214cb93a386Sopenharmony_ci opsTask->setColorLoadOp(GrLoadOp::kDiscard); 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci // At this point we are either a partial clear or a fullscreen clear that couldn't be applied 219cb93a386Sopenharmony_ci // as a load op. 220cb93a386Sopenharmony_ci bool clearAsDraw = this->caps()->performColorClearsAsDraws() || 221cb93a386Sopenharmony_ci (scissorState.enabled() && this->caps()->performPartialClearsAsDraws()); 222cb93a386Sopenharmony_ci if (clearAsDraw) { 223cb93a386Sopenharmony_ci GrPaint paint; 224cb93a386Sopenharmony_ci ClearToGrPaint(color, &paint); 225cb93a386Sopenharmony_ci auto op = FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), 226cb93a386Sopenharmony_ci SkRect::Make(scissorState.rect())); 227cb93a386Sopenharmony_ci this->addDrawOp(std::move(op)); 228cb93a386Sopenharmony_ci } else { 229cb93a386Sopenharmony_ci color = this->writeSurfaceView().swizzle().applyTo(color); 230cb93a386Sopenharmony_ci this->addOp(ClearOp::MakeColor(fContext, scissorState, color)); 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci} 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_cibool SurfaceFillContext::blitTexture(GrSurfaceProxyView view, 235cb93a386Sopenharmony_ci const SkIRect& srcRect, 236cb93a386Sopenharmony_ci const SkIPoint& dstPoint) { 237cb93a386Sopenharmony_ci SkASSERT(view.asTextureProxy()); 238cb93a386Sopenharmony_ci SkIRect clippedSrcRect; 239cb93a386Sopenharmony_ci SkIPoint clippedDstPoint; 240cb93a386Sopenharmony_ci if (!GrClipSrcRectAndDstPoint(this->dimensions(), 241cb93a386Sopenharmony_ci view.dimensions(), 242cb93a386Sopenharmony_ci srcRect, 243cb93a386Sopenharmony_ci dstPoint, 244cb93a386Sopenharmony_ci &clippedSrcRect, 245cb93a386Sopenharmony_ci &clippedDstPoint)) { 246cb93a386Sopenharmony_ci return false; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); 250cb93a386Sopenharmony_ci auto dstRect = SkIRect::MakePtSize(clippedDstPoint, clippedSrcRect.size()); 251cb93a386Sopenharmony_ci auto srcRectF = SkRect::Make(clippedSrcRect); 252cb93a386Sopenharmony_ci this->fillRectToRectWithFP(srcRectF, dstRect, std::move(fp)); 253cb93a386Sopenharmony_ci return true; 254cb93a386Sopenharmony_ci} 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci} // namespace skgpu::v1 257