Move the msaa dirty rect to GrRenderTargetProxy

Bug: skia:
Change-Id: I01d7932bce23dffafb86e4eb124c27420acefdd3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/239192
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2019-09-24 22:19:17 -06:00 committed by Skia Commit-Bot
parent c3f6314e70
commit 16a33c6244
22 changed files with 135 additions and 112 deletions

View File

@ -32,7 +32,9 @@ private:
// If instantiation failed, at flush time we simply will skip doing the copy.
void handleInternalAllocationFailure() override {}
void gatherProxyIntervals(GrResourceAllocator*) const override;
ExpectedOutcome onMakeClosed(const GrCaps&) override {
ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) override {
targetUpdateBounds->setXYWH(fDstPoint.x(), fDstPoint.y(), fSrcRect.width(),
fSrcRect.height());
return ExpectedOutcome::kTargetDirty;
}
bool onExecute(GrOpFlushState*) override;

View File

@ -531,7 +531,8 @@ GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[],
SkASSERT(rtProxy);
if (rtProxy->isMSAADirty()) {
SkASSERT(rtProxy->peekRenderTarget());
gpu->resolveRenderTarget(rtProxy->peekRenderTarget(), GrGpu::ForExternalIO::kYes);
gpu->resolveRenderTarget(rtProxy->peekRenderTarget(), rtProxy->msaaDirtyRect(),
rtProxy->origin(), GrGpu::ForExternalIO::kYes);
rtProxy->markMSAAResolved();
}
}

View File

@ -19,6 +19,7 @@
#include "src/gpu/GrDataUtils.h"
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrNativeRect.h"
#include "src/gpu/GrPathRendering.h"
#include "src/gpu/GrPipeline.h"
#include "src/gpu/GrRenderTargetPriv.h"
@ -580,8 +581,14 @@ bool GrGpu::regenerateMipMapLevels(GrTexture* texture) {
SkASSERT(texture);
SkASSERT(this->caps()->mipMapSupport());
SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes);
SkASSERT(texture->texturePriv().mipMapsAreDirty());
SkASSERT(!texture->asRenderTarget() || !texture->asRenderTarget()->needsResolve());
if (!texture->texturePriv().mipMapsAreDirty()) {
// This can happen when the proxy expects mipmaps to be dirty, but they are not dirty on the
// actual target. This may be caused by things that the drawingManager could not predict,
// i.e., ops that don't draw anything, aborting a draw for exceptional circumstances, etc.
// NOTE: This goes away once we quit tracking mipmap state on the actual texture.
return true;
}
if (texture->readOnly()) {
return false;
}
@ -597,10 +604,24 @@ void GrGpu::resetTextureBindings() {
this->onResetTextureBindings();
}
void GrGpu::resolveRenderTarget(GrRenderTarget* target, ForExternalIO forExternalIO) {
void GrGpu::resolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin origin, ForExternalIO forExternalIO) {
SkASSERT(target);
if (!target->needsResolve()) {
// This can happen when the proxy expects MSAA to be dirty, but it is not dirty on the
// actual target. This may be caused by things that the drawingManager could not predict,
// i.e., ops that don't draw anything, aborting a draw for exceptional circumstances, etc.
// NOTE: This goes away once we quit tracking dirty state on the actual render target.
return;
}
#ifdef SK_DEBUG
auto nativeResolveRect = GrNativeRect::MakeRelativeTo(origin, target->height(), resolveRect);
// The proxy will often track a tighter resolve rect than GrRenderTarget, but it should never be
// the other way around.
SkASSERT(target->getResolveRect().contains(nativeResolveRect.asSkIRect()));
#endif
this->handleDirtyContext();
this->onResolveRenderTarget(target, forExternalIO);
this->onResolveRenderTarget(target, resolveRect, origin, forExternalIO);
}
void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,

View File

@ -189,7 +189,8 @@ public:
/**
* Resolves MSAA.
*/
void resolveRenderTarget(GrRenderTarget*, ForExternalIO);
void resolveRenderTarget(GrRenderTarget*, const SkIRect& resolveRect, GrSurfaceOrigin,
ForExternalIO);
/**
* Uses the base of the texture to recompute the contents of the other levels.
@ -634,7 +635,8 @@ private:
GrGpuBuffer* transferBuffer, size_t offset) = 0;
// overridden by backend-specific derived class to perform the resolve
virtual void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) = 0;
virtual void onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO) = 0;
// overridden by backend specific derived class to perform mip map level regeneration.
virtual bool onRegenerateMipMapLevels(GrTexture*) = 0;

View File

@ -504,6 +504,9 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) {
void GrOpsTask::setColorLoadOp(GrLoadOp op, const SkPMColor4f& color) {
fColorLoadOp = op;
fLoadClearColor = color;
if (GrLoadOp::kClear == fColorLoadOp) {
fTotalBounds.setWH(fTarget->width(), fTarget->height());
}
}
bool GrOpsTask::resetForFullscreenClear(CanDiscardPreviousOps canDiscardPreviousOps) {
@ -534,6 +537,7 @@ void GrOpsTask::discard() {
if (this->isEmpty()) {
fColorLoadOp = GrLoadOp::kDiscard;
fStencilLoadOp = GrLoadOp::kDiscard;
fTotalBounds.setEmpty();
}
}
@ -671,6 +675,10 @@ void GrOpsTask::recordOp(
return;
}
// Account for this op's bounds before we attempt to combine.
// NOTE: The caller should have already called "op->setClippedBounds()" by now, if applicable.
fTotalBounds.join(op->bounds());
// Check if there is an op we can combine with by linearly searching back until we either
// 1) check every op
// 2) intersect with something
@ -747,3 +755,15 @@ void GrOpsTask::forwardCombine(const GrCaps& caps) {
}
}
GrRenderTask::ExpectedOutcome GrOpsTask::onMakeClosed(
const GrCaps& caps, SkIRect* targetUpdateBounds) {
this->forwardCombine(caps);
if (!this->isNoOp()) {
SkRect clippedContentBounds = SkRect::MakeIWH(fTarget->width(), fTarget->height());
if (clippedContentBounds.intersect(fTotalBounds)) {
clippedContentBounds.roundOut(targetUpdateBounds);
return ExpectedOutcome::kTargetDirty;
}
}
return ExpectedOutcome::kTargetUnchanged;
}

View File

@ -229,10 +229,7 @@ private:
void forwardCombine(const GrCaps&);
ExpectedOutcome onMakeClosed(const GrCaps& caps) override {
this->forwardCombine(caps);
return (this->isNoOp()) ? ExpectedOutcome::kTargetUnchanged : ExpectedOutcome::kTargetDirty;
}
ExpectedOutcome onMakeClosed(const GrCaps& caps, SkIRect* targetUpdateBounds) override;
friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive
@ -270,6 +267,8 @@ private:
// TODO: We could look into this being a set if we find we're adding a lot of duplicates that is
// causing slow downs.
SkTArray<GrTextureProxy*, true> fSampledProxies;
SkRect fTotalBounds = SkRect::MakeEmpty();
};
#endif

View File

@ -63,17 +63,22 @@ public:
bool wrapsVkSecondaryCB() const { return fWrapsVkSecondaryCB == WrapsVkSecondaryCB::kYes; }
void markMSAADirty() {
void markMSAADirty(const SkIRect& dirtyRect) {
SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(dirtyRect));
SkASSERT(this->requiresManualMSAAResolve());
fIsMSAADirty = true;
fMSAADirtyRect.join(dirtyRect);
}
void markMSAAResolved() {
SkASSERT(this->requiresManualMSAAResolve());
fIsMSAADirty = false;
fMSAADirtyRect.setEmpty();
}
bool isMSAADirty() const {
SkASSERT(!fIsMSAADirty || this->requiresManualMSAAResolve());
return fIsMSAADirty;
SkASSERT(fMSAADirtyRect.isEmpty() || this->requiresManualMSAAResolve());
return this->requiresManualMSAAResolve() && !fMSAADirtyRect.isEmpty();
}
const SkIRect& msaaDirtyRect() const {
SkASSERT(this->requiresManualMSAAResolve());
return fMSAADirtyRect;
}
// TODO: move this to a priv class!
@ -160,10 +165,7 @@ private:
int8_t fNumStencilSamples = 0;
WrapsVkSecondaryCB fWrapsVkSecondaryCB;
GrSwizzle fOutputSwizzle;
// Indicates whether some sub-rectangle of the render target requires MSAA resolve. We currently
// rely on the GrRenderTarget itself to track the actual dirty rect.
// TODO: In the future, convert the flag to a dirty rect and quit tracking it in GrRenderTarget.
bool fIsMSAADirty = false;
SkIRect fMSAADirtyRect = SkIRect::MakeEmpty();
// This is to fix issue in large comment above. Without the padding we end 6 bytes into a 16
// byte range, so the GrTextureProxy ends up starting 8 byte aligned by not 16. We add the
// padding here to get us right up to the 16 byte alignment (technically any padding of 3-10

View File

@ -51,10 +51,12 @@ void GrRenderTask::makeClosed(const GrCaps& caps) {
return;
}
if (ExpectedOutcome::kTargetDirty == this->onMakeClosed(caps)) {
SkIRect targetUpdateBounds;
if (ExpectedOutcome::kTargetDirty == this->onMakeClosed(caps, &targetUpdateBounds)) {
SkASSERT(SkIRect::MakeWH(fTarget->width(), fTarget->height()).contains(targetUpdateBounds));
if (fTarget->requiresManualMSAAResolve()) {
SkASSERT(fTarget->asRenderTargetProxy());
fTarget->asRenderTargetProxy()->markMSAADirty();
fTarget->asRenderTargetProxy()->markMSAADirty(targetUpdateBounds);
}
GrTextureProxy* textureProxy = fTarget->asTextureProxy();
if (textureProxy && GrMipMapped::kYes == textureProxy->mipMapped()) {

View File

@ -96,7 +96,12 @@ protected:
kTargetDirty,
};
virtual ExpectedOutcome onMakeClosed(const GrCaps&) = 0;
// Performs any work to finalize this renderTask prior to execution. If returning
// ExpectedOutcome::kTargetDiry, the caller is also responsible to fill out the area it will
// modify in targetUpdateBounds.
//
// targetUpdateBounds must not extend beyond the proxy bounds.
virtual ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) = 0;
sk_sp<GrSurfaceProxy> fTarget;

View File

@ -392,12 +392,12 @@ protected:
private:
// For wrapped resources, 'fFormat', 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always
// be filled in from the wrapped resource.
GrBackendFormat fFormat;
GrPixelConfig fConfig;
const GrBackendFormat fFormat;
const GrPixelConfig fConfig;
int fWidth;
int fHeight;
GrSurfaceOrigin fOrigin;
GrSwizzle fTextureSwizzle;
const GrSurfaceOrigin fOrigin;
const GrSwizzle fTextureSwizzle;
SkBackingFit fFit; // always kApprox for lazy-callback resources
// always kExact for wrapped resources

View File

@ -22,7 +22,10 @@ GrTextureResolveRenderTask::~GrTextureResolveRenderTask() {
}
void GrTextureResolveRenderTask::addProxy(
sk_sp<GrSurfaceProxy> proxy, GrSurfaceProxy::ResolveFlags flags, const GrCaps& caps) {
sk_sp<GrSurfaceProxy> proxyHolder, GrSurfaceProxy::ResolveFlags flags, const GrCaps& caps) {
fResolves.emplace_back(std::move(proxyHolder), flags);
GrSurfaceProxy* proxy = fResolves.back().fProxy.get();
// Ensure the last render task that operated on the proxy is closed. That's where msaa and
// mipmaps should have been marked dirty.
SkASSERT(!proxy->getLastRenderTask() || proxy->getLastRenderTask()->isClosed());
@ -32,6 +35,7 @@ void GrTextureResolveRenderTask::addProxy(
GrRenderTargetProxy* renderTargetProxy = proxy->asRenderTargetProxy();
SkASSERT(renderTargetProxy);
SkASSERT(renderTargetProxy->isMSAADirty());
fResolves.back().fMSAAResolveRect = renderTargetProxy->msaaDirtyRect();
renderTargetProxy->markMSAAResolved();
}
@ -44,10 +48,8 @@ void GrTextureResolveRenderTask::addProxy(
// Add the proxy as a dependency: We will read the existing contents of this texture while
// generating mipmap levels and/or resolving MSAA.
this->addDependency(proxy.get(), GrMipMapped::kNo, GrTextureResolveManager(nullptr), caps);
this->addDependency(proxy, GrMipMapped::kNo, GrTextureResolveManager(nullptr), caps);
proxy->setLastRenderTask(this);
fResolves.emplace_back(std::move(proxy), flags);
}
void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
@ -69,7 +71,10 @@ bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) {
// peekRenderTarget might be null if there was an instantiation error.
GrRenderTarget* renderTarget = resolve.fProxy->peekRenderTarget();
if (renderTarget && renderTarget->needsResolve()) {
flushState->gpu()->resolveRenderTarget(renderTarget, GrGpu::ForExternalIO::kNo);
flushState->gpu()->resolveRenderTarget(renderTarget, resolve.fMSAAResolveRect,
resolve.fProxy->origin(),
GrGpu::ForExternalIO::kNo);
SkASSERT(!renderTarget->needsResolve());
}
}
}
@ -80,6 +85,7 @@ bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) {
GrTexture* texture = resolve.fProxy->peekTexture();
if (texture && texture->texturePriv().mipMapsAreDirty()) {
flushState->gpu()->regenerateMipMapLevels(texture);
SkASSERT(!texture->texturePriv().mipMapsAreDirty());
}
}
}

View File

@ -28,7 +28,7 @@ private:
}
void gatherProxyIntervals(GrResourceAllocator*) const override;
ExpectedOutcome onMakeClosed(const GrCaps&) override {
ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect*) override {
return ExpectedOutcome::kTargetUnchanged;
}
@ -43,6 +43,7 @@ private:
: fProxy(std::move(proxy)), fFlags(flags) {}
sk_sp<GrSurfaceProxy> fProxy;
GrSurfaceProxy::ResolveFlags fFlags;
SkIRect fMSAAResolveRect;
};
SkSTArray<4, Resolve> fResolves;

View File

@ -36,7 +36,7 @@ private:
void handleInternalAllocationFailure() override {}
void gatherProxyIntervals(GrResourceAllocator*) const override;
ExpectedOutcome onMakeClosed(const GrCaps&) override {
ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect*) override {
return ExpectedOutcome::kTargetUnchanged;
}

View File

@ -28,7 +28,7 @@ private:
void handleInternalAllocationFailure() override {}
void gatherProxyIntervals(GrResourceAllocator*) const override;
ExpectedOutcome onMakeClosed(const GrCaps&) override {
ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect*) override {
return ExpectedOutcome::kTargetUnchanged;
}

View File

@ -154,8 +154,8 @@ private:
GrColorType surfaceColorType, GrColorType bufferColorType,
GrGpuBuffer* transferBuffer, size_t offset) override;
void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) override {
}
void onResolveRenderTarget(GrRenderTarget*, const SkIRect&, GrSurfaceOrigin,
ForExternalIO) override {}
bool onRegenerateMipMapLevels(GrTexture*) override;

View File

@ -1957,7 +1957,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
this->flushRenderTargetNoColorWrites(renderTarget);
break;
case GrGLRenderTarget::kCanResolve_ResolveType:
this->onResolveRenderTarget(renderTarget, ForExternalIO::kNo);
SkASSERT(!renderTarget->needsResolve());
// we don't track the state of the READ FBO ID.
this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, renderTarget->textureFBOID());
break;
@ -2281,7 +2281,8 @@ void GrGLGpu::sendIndexedInstancedMeshToGpu(GrPrimitiveType primitiveType,
}
}
void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) {
void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
if (rt->needsResolve()) {
// Some extensions automatically resolves the texture when it is read.
@ -2294,15 +2295,11 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) {
// make sure we go through flushRenderTarget() since we've modified
// the bound DRAW FBO ID.
fHWBoundRenderTargetUniqueID.makeInvalid();
const SkIRect dirtyRect = rt->getResolveRect();
// The dirty rect tracked on the RT is always stored in the native coordinates of the
// surface. Choose kTopLeft so no adjustments are made
static constexpr auto kDirtyRectOrigin = kTopLeft_GrSurfaceOrigin;
if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) {
// Apple's extension uses the scissor as the blit bounds.
GrScissorState scissorState;
scissorState.set(dirtyRect);
this->flushScissor(scissorState, rt->width(), rt->height(), kDirtyRectOrigin);
scissorState.set(resolveRect);
this->flushScissor(scissorState, rt->width(), rt->height(), resolveOrigin);
this->disableWindowRectangles();
GL_CALL(ResolveMultisampleFramebuffer());
} else {
@ -2315,7 +2312,7 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) {
t = target->height();
} else {
auto rect = GrNativeRect::MakeRelativeTo(
kDirtyRectOrigin, rt->height(), dirtyRect);
resolveOrigin, rt->height(), resolveRect);
l = rect.fX;
b = rect.fY;
r = rect.fX + rect.fWidth;
@ -2536,6 +2533,7 @@ static void get_gl_swizzle_values(const GrSwizzle& swizzle, GrGLenum glValues[4]
void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwizzle& swizzle,
GrGLTexture* texture) {
SkASSERT(texture);
SkASSERT(!texture->asRenderTarget() || !texture->asRenderTarget()->needsResolve());
#ifdef SK_DEBUG
if (!this->caps()->npotTextureTileSupport()) {
@ -2547,14 +2545,6 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwiz
}
#endif
// If we created a rt/tex and rendered to it without using a texture and now we're texturing
// from the rt it will still be the last bound texture, but it needs resolving. So keep this
// out of the "last != next" check.
GrGLRenderTarget* texRT = static_cast<GrGLRenderTarget*>(texture->asRenderTarget());
if (texRT) {
this->onResolveRenderTarget(texRT, ForExternalIO::kNo);
}
GrGpuResource::UniqueID textureID = texture->uniqueID();
GrGLenum target = texture->target();
if (fHWTextureUnitBindings[unitIdx].boundID(target) != textureID) {

View File

@ -258,7 +258,8 @@ private:
// PIXEL_UNPACK_BUFFER is unbound.
void unbindCpuToGpuXferBuffer();
void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) override;
void onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO) override;
bool onRegenerateMipMapLevels(GrTexture*) override;

View File

@ -118,7 +118,8 @@ private:
bool onRegenerateMipMapLevels(GrTexture*) override { return true; }
void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO) override {
void onResolveRenderTarget(GrRenderTarget* target, const SkIRect&, GrSurfaceOrigin,
ForExternalIO) override {
target->flagAsResolved();
}

View File

@ -108,10 +108,6 @@ public:
this->didWriteToSurface(surface, origin, bounds);
}
void resolveRenderTargetNoFlush(GrRenderTarget* target) {
this->internalResolveRenderTarget(target, false);
}
private:
GrMtlGpu(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet);
@ -185,11 +181,9 @@ private:
bool onRegenerateMipMapLevels(GrTexture*) override;
void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO forExternalIO) override {
this->internalResolveRenderTarget(target, ForExternalIO::kYes == forExternalIO);
}
void onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO) override;
void internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit);
void resolveTexture(id<MTLTexture> colorTexture, id<MTLTexture> resolveTexture);
void onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,

View File

@ -1053,7 +1053,7 @@ bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, in
mtlTexture = rt->mtlColorTexture();
break;
case GrMtlRenderTarget::kCanResolve_ResolveType:
this->resolveRenderTargetNoFlush(rt);
SkASSERT(!rt->needsResolve());
mtlTexture = rt->mtlResolveTexture();
break;
default:
@ -1188,13 +1188,17 @@ void GrMtlGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
#endif
}
void GrMtlGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
void GrMtlGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect&, GrSurfaceOrigin,
ForExternalIO forExternalIO) {
if (target->needsResolve()) {
this->resolveTexture(static_cast<GrMtlRenderTarget*>(target)->mtlResolveTexture(),
static_cast<GrMtlRenderTarget*>(target)->mtlColorTexture());
target->flagAsResolved();
if (requiresSubmit) {
if (ForExternalIO::kYes == forExternalIO) {
// This resolve is called when we are preparing an msaa surface for external I/O. It is
// called after flushing, so we need to make sure we submit the command buffer after
// doing the resolve so that the resolve actually happens.
this->submitCommandBuffer(kSkip_SyncQueue);
}
}

View File

@ -535,18 +535,6 @@ bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int wi
if (rt->wrapsSecondaryCommandBuffer()) {
return false;
}
// resolve the render target if necessary
switch (rt->getResolveType()) {
case GrVkRenderTarget::kCantResolve_ResolveType:
return false;
case GrVkRenderTarget::kAutoResolves_ResolveType:
break;
case GrVkRenderTarget::kCanResolve_ResolveType:
this->resolveRenderTargetNoFlush(rt);
break;
default:
SK_ABORT("Unknown resolve type");
}
srcImage = rt;
} else {
srcImage = static_cast<GrVkTexture*>(surface->asTexture());
@ -617,21 +605,24 @@ void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect&
fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dstImage, 1, &resolveInfo);
}
void GrVkGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
if (target->needsResolve()) {
SkASSERT(target->numSamples() > 1);
GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
SkASSERT(rt->msaaImage());
void GrVkGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO forExternalIO) {
SkASSERT(target->numSamples() > 1);
GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
SkASSERT(rt->msaaImage());
const SkIRect& srcRect = rt->getResolveRect();
auto nativeResolveRect = GrNativeRect::MakeRelativeTo(
resolveOrigin, target->height(), resolveRect);
this->resolveImage(target, rt, nativeResolveRect.asSkIRect(),
SkIPoint::Make(nativeResolveRect.fX, nativeResolveRect.fY));
this->resolveImage(target, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop));
rt->flagAsResolved();
rt->flagAsResolved();
if (requiresSubmit) {
this->submitCommandBuffer(kSkip_SyncQueue);
}
if (ForExternalIO::kYes == forExternalIO) {
// This resolve is called when we are preparing an msaa surface for external I/O. It is
// called after flushing, so we need to make sure we submit the command buffer after doing
// the resolve so that the resolve actually happens.
this->submitCommandBuffer(kSkip_SyncQueue);
}
}
@ -2232,18 +2223,6 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int
if (rt->wrapsSecondaryCommandBuffer()) {
return false;
}
// resolve the render target if necessary
switch (rt->getResolveType()) {
case GrVkRenderTarget::kCantResolve_ResolveType:
return false;
case GrVkRenderTarget::kAutoResolves_ResolveType:
break;
case GrVkRenderTarget::kCanResolve_ResolveType:
this->resolveRenderTargetNoFlush(rt);
break;
default:
SK_ABORT("Unknown resolve type");
}
image = rt;
} else {
image = static_cast<GrVkTexture*>(surface->asTexture());

View File

@ -119,13 +119,8 @@ public:
bool onRegenerateMipMapLevels(GrTexture* tex) override;
void resolveRenderTargetNoFlush(GrRenderTarget* target) {
this->internalResolveRenderTarget(target, false);
}
void onResolveRenderTarget(GrRenderTarget* target, ForExternalIO forExternalIO) override {
this->internalResolveRenderTarget(target, ForExternalIO::kYes == forExternalIO);
}
void onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
GrSurfaceOrigin resolveOrigin, ForExternalIO) override;
void submitSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer>);
@ -248,8 +243,6 @@ private:
void submitCommandBuffer(SyncQueue sync, GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
void internalResolveRenderTarget(GrRenderTarget*, bool requiresSubmit);
void copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, GrVkImage* dstImage,
GrVkImage* srcImage, const SkIRect& srcRect,
const SkIPoint& dstPoint);