Add kRequiresManualMSAAResolve to GrInternalSurfaceFlags
We will use this flag to check whether a proxy needs manual msaa
resolve, and if so, install a render task to do just that when it is
dirty and about to be read from.
For the time being, we are leaving GrRenderTarget::getResovleType in
place. This will allow us to assert that requiresManualMSAAResolve
works as expected. Long term, we plan to delete the former in favor of
the latter.
Bug: skia:
Change-Id: I155fa2a6d876edd339232c7c8208015d5da2c8ee
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/234436
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index ab84d65..2b41fec 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -91,6 +91,8 @@
protected:
void setGLRTFBOIDIs0() {
+ SkASSERT(!this->requiresManualMSAAResolve());
+ SkASSERT(!this->asTexture());
SkASSERT(this->asRenderTarget());
fSurfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
}
@@ -98,6 +100,15 @@
return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0;
}
+ void setRequiresManualMSAAResolve() {
+ SkASSERT(!this->glRTFBOIDis0());
+ SkASSERT(this->asRenderTarget());
+ fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+ }
+ bool requiresManualMSAAResolve() const {
+ return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+ }
+
void setReadOnly() {
SkASSERT(!this->asRenderTarget());
fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 8485817..e41d5ac 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -724,23 +724,36 @@
enum class GrInternalSurfaceFlags {
kNone = 0,
- // Surface-level
// Texture-level
// Means the pixels in the texture are read-only. Cannot also be a GrRenderTarget[Proxy].
kReadOnly = 1 << 0,
- kTextureMask = kReadOnly,
-
// RT-level
// This flag is for use with GL only. It tells us that the internal render target wraps FBO 0.
- kGLRTFBOIDIs0 = 1 << 2,
+ kGLRTFBOIDIs0 = 1 << 1,
- kRenderTargetMask = kGLRTFBOIDIs0,
+ // This means the render target is multisampled, and internally holds a non-msaa texture for
+ // resolving into. The render target resolves itself by blitting into this internal texture.
+ // (asTexture() might or might not return the internal texture, but if it does, we always
+ // resolve the render target before accessing this texture's data.)
+ kRequiresManualMSAAResolve = 1 << 2,
};
+
GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags)
+// 'GR_MAKE_BITFIELD_CLASS_OPS' defines the & operator on GrInternalSurfaceFlags to return bool.
+// We want to find the bitwise & with these masks, so we declare them as ints.
+constexpr static int kGrInternalTextureFlagsMask = static_cast<int>(
+ GrInternalSurfaceFlags::kReadOnly);
+
+constexpr static int kGrInternalRenderTargetFlagsMask = static_cast<int>(
+ GrInternalSurfaceFlags::kGLRTFBOIDIs0 | GrInternalSurfaceFlags::kRequiresManualMSAAResolve);
+
+constexpr static int kGrInternalTextureRenderTargetFlagsMask =
+ kGrInternalTextureFlagsMask | kGrInternalRenderTargetFlagsMask;
+
#ifdef SK_DEBUG
// Takes a pointer to a GrCaps, and will suppress prints if required
#define GrCapsDebugf(caps, ...) if (!(caps)->suppressPrints()) SkDebugf(__VA_ARGS__)
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 970c7a3..91c7e41 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -202,6 +202,11 @@
}
}
SkASSERT(tex->backendFormat() == format);
+ SkASSERT(!tex || GrRenderable::kNo == renderable || tex->asRenderTarget());
+ if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
+ SkASSERT(GrRenderable::kYes == renderable);
+ tex->asRenderTarget()->setRequiresManualMSAAResolve();
+ }
}
return tex;
}
@@ -285,6 +290,9 @@
sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, colorType,
ownership, cacheable);
SkASSERT(!tex || tex->asRenderTarget());
+ if (tex && sampleCnt > 1 && !caps->msaaResolvesAutomatically()) {
+ tex->asRenderTarget()->setRequiresManualMSAAResolve();
+ }
return tex;
}
@@ -317,7 +325,11 @@
return nullptr;
}
- return this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
+ auto rt = this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
+ if (rt && sampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
+ rt->setRequiresManualMSAAResolve();
+ }
+ return rt;
}
sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 683d84c..734b227 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -845,9 +845,9 @@
return sk_sp<GrTextureProxy>((renderable == GrRenderable::kYes)
? new GrTextureRenderTargetProxy(
- std::move(callback), lazyType, format, desc, renderTargetSampleCnt, origin,
- mipMapped, mipMapsStatus, texSwizzle, outSwizzle, fit, budgeted, isProtected,
- surfaceFlags)
+ *this->caps(), std::move(callback), lazyType, format, desc,
+ renderTargetSampleCnt, origin, mipMapped, mipMapsStatus, texSwizzle, outSwizzle,
+ fit, budgeted, isProtected, surfaceFlags)
: new GrTextureProxy(
std::move(callback), lazyType, format, desc, origin, mipMapped, mipMapsStatus,
texSwizzle, fit, budgeted, isProtected, surfaceFlags));
@@ -883,7 +883,7 @@
// actual VkImage to texture from.
SkASSERT(!wrapsVkSecondaryCB);
return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
- std::move(callback), lazyType, format, desc, sampleCnt, origin,
+ *this->caps(), std::move(callback), lazyType, format, desc, sampleCnt, origin,
textureInfo->fMipMapped, mipMapsStatus, texSwizzle, outSwizzle, fit, budgeted,
isProtected, surfaceFlags));
}
@@ -919,7 +919,7 @@
return sk_sp<GrTextureProxy>((GrRenderable::kYes == renderable)
? new GrTextureRenderTargetProxy(
- std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
+ caps, std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
renderTargetSampleCnt, origin, GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated,
texSwizzle, outSwizzle, SkBackingFit::kApprox, SkBudgeted::kYes, isProtected,
surfaceFlags)
diff --git a/src/gpu/GrRenderTarget.h b/src/gpu/GrRenderTarget.h
index 2c330da..7a6f44c 100644
--- a/src/gpu/GrRenderTarget.h
+++ b/src/gpu/GrRenderTarget.h
@@ -26,6 +26,9 @@
*/
class GrRenderTarget : virtual public GrSurface {
public:
+ // Make setRequiresManualMSAAResolve publicly accessible from GrRenderTarget.
+ using GrSurface::setRequiresManualMSAAResolve;
+
virtual bool alwaysClearStencil() const { return false; }
// GrSurface overrides
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index b827e8d..6d831fa 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -7,8 +7,10 @@
#include "src/gpu/GrRenderTargetProxy.h"
+#include "include/gpu/GrContext.h"
#include "src/core/SkMathPriv.h"
#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/GrRenderTargetOpList.h"
#include "src/gpu/GrRenderTargetPriv.h"
@@ -53,6 +55,15 @@
, fSampleCnt(fTarget->asRenderTarget()->numSamples())
, fWrapsVkSecondaryCB(wrapsVkSecondaryCB)
, fOutputSwizzle(outputSwizzle) {
+ // The kRequiresManualMSAAResolve flag better not be set if we are not multisampled or if
+ // MSAA resolve should happen automatically.
+ //
+ // From the other side, we don't know enough about the wrapped surface to assert when
+ // kRequiresManualMSAAResolve *should* be set. e.g., The caller might be wrapping a backend
+ // texture as a render target at this point but we wouldn't know it.
+ SkASSERT(!(this->numSamples() <= 1 ||
+ fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) ||
+ !this->requiresManualMSAAResolve());
}
int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const {
@@ -125,7 +136,7 @@
GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
- SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
- (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
+ SkASSERT(((int)proxyFlags & kGrInternalRenderTargetFlagsMask) ==
+ ((int)surfaceFlags & kGrInternalRenderTargetFlagsMask));
}
#endif
diff --git a/src/gpu/GrRenderTargetProxyPriv.h b/src/gpu/GrRenderTargetProxyPriv.h
index bf2e770..091e4f2 100644
--- a/src/gpu/GrRenderTargetProxyPriv.h
+++ b/src/gpu/GrRenderTargetProxyPriv.h
@@ -16,6 +16,9 @@
class GrRenderTargetProxyPriv {
public:
void setGLRTFBOIDIs0() {
+ // FBO0 should never be wrapped as a texture render target.
+ SkASSERT(!fRenderTargetProxy->requiresManualMSAAResolve());
+ SkASSERT(!fRenderTargetProxy->asTextureProxy());
fRenderTargetProxy->setGLRTFBOIDIs0();
}
diff --git a/src/gpu/GrSurfaceProxy.h b/src/gpu/GrSurfaceProxy.h
index 7a15059..6447396 100644
--- a/src/gpu/GrSurfaceProxy.h
+++ b/src/gpu/GrSurfaceProxy.h
@@ -269,6 +269,16 @@
*/
bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
+ /**
+ * This means surface is a multisampled render target, and internally holds a non-msaa texture
+ * for resolving into. The render target resolves itself by blitting into this internal texture.
+ * (asTexture() might or might not return the internal texture, but if it does, we always
+ * resolve the render target before accessing this texture's data.)
+ */
+ bool requiresManualMSAAResolve() const {
+ return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+ }
+
void setLastRenderTask(GrRenderTask*);
GrRenderTask* getLastRenderTask() { return fLastRenderTask; }
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 5c7d304..85c6f58 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -177,8 +177,8 @@
GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
- SkASSERT((proxyFlags & GrInternalSurfaceFlags::kTextureMask) ==
- (surfaceFlags & GrInternalSurfaceFlags::kTextureMask));
+ SkASSERT(((int)proxyFlags & kGrInternalTextureFlagsMask) ==
+ ((int)surfaceFlags & kGrInternalTextureFlagsMask));
}
#endif
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index 8e91bff..fb54227 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -9,7 +9,9 @@
#include "include/gpu/GrTexture.h"
#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrRenderTarget.h"
+#include "src/gpu/GrRenderTargetProxyPriv.h"
#include "src/gpu/GrSurfacePriv.h"
#include "src/gpu/GrSurfaceProxyPriv.h"
#include "src/gpu/GrTexturePriv.h"
@@ -37,10 +39,13 @@
, GrRenderTargetProxy(caps, format, desc, sampleCnt, origin, texSwizzle, outSwizzle, fit,
budgeted, isProtected, surfaceFlags)
, GrTextureProxy(format, desc, origin, mipMapped, mipMapsStatus, texSwizzle, fit, budgeted,
- isProtected, surfaceFlags) {}
+ isProtected, surfaceFlags) {
+ this->initSurfaceFlags(caps);
+}
// Lazy-callback version
-GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(LazyInstantiateCallback&& callback,
+GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
+ LazyInstantiateCallback&& callback,
LazyInstantiationType lazyType,
const GrBackendFormat& format,
const GrSurfaceDesc& desc,
@@ -62,7 +67,9 @@
texSwizzle, outSwizzle, fit, budgeted, isProtected, surfaceFlags,
WrapsVkSecondaryCB::kNo)
, GrTextureProxy(LazyInstantiateCallback(), lazyType, format, desc, origin, mipMapped,
- mipMapsStatus, texSwizzle, fit, budgeted, isProtected, surfaceFlags) {}
+ mipMapsStatus, texSwizzle, fit, budgeted, isProtected, surfaceFlags) {
+ this->initSurfaceFlags(caps);
+}
// Wrapped version
// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and
@@ -76,6 +83,25 @@
, GrTextureProxy(surf, origin, texSwizzle) {
SkASSERT(surf->asTexture());
SkASSERT(surf->asRenderTarget());
+ SkASSERT(fSurfaceFlags == fTarget->surfacePriv().flags());
+ SkASSERT((this->numSamples() <= 1 ||
+ fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) !=
+ this->requiresManualMSAAResolve());
+}
+
+void GrTextureRenderTargetProxy::initSurfaceFlags(const GrCaps& caps) {
+ // FBO 0 should never be wrapped as a texture render target.
+ SkASSERT(!this->rtPriv().glRTFBOIDIs0());
+ if (this->numSamples() > 1 && !caps.msaaResolvesAutomatically()) {
+ // MSAA texture-render-targets always require manual resolve if we are not using a
+ // multisampled-render-to-texture extension.
+ //
+ // NOTE: This is the only instance where we need to set the manual resolve flag on a proxy.
+ // Any other proxies that require manual resolve (e.g., wrapBackendTextureAsRenderTarget())
+ // will be wrapped, and the wrapped version of the GrSurface constructor will automatically
+ // get the manual resolve flag when copying the target GrSurface's flags.
+ fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+ }
}
size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
@@ -147,10 +173,8 @@
SkASSERT(!(proxyFlags & GrInternalSurfaceFlags::kReadOnly));
SkASSERT(!(surfaceFlags & GrInternalSurfaceFlags::kReadOnly));
- SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
- (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
- SkASSERT((proxyFlags & GrInternalSurfaceFlags::kTextureMask) ==
- (surfaceFlags & GrInternalSurfaceFlags::kTextureMask));
+ SkASSERT(((int)proxyFlags & kGrInternalTextureRenderTargetFlagsMask) ==
+ ((int)surfaceFlags & kGrInternalTextureRenderTargetFlagsMask));
}
#endif
diff --git a/src/gpu/GrTextureRenderTargetProxy.h b/src/gpu/GrTextureRenderTargetProxy.h
index a736793..a31e520 100644
--- a/src/gpu/GrTextureRenderTargetProxy.h
+++ b/src/gpu/GrTextureRenderTargetProxy.h
@@ -34,7 +34,7 @@
SkBackingFit, SkBudgeted, GrProtected, GrInternalSurfaceFlags);
// Lazy-callback version
- GrTextureRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType,
+ GrTextureRenderTargetProxy(const GrCaps&, LazyInstantiateCallback&&, LazyInstantiationType,
const GrBackendFormat&, const GrSurfaceDesc& desc, int sampleCnt,
GrSurfaceOrigin, GrMipMapped, GrMipMapsStatus,
const GrSwizzle& textureSwizzle, const GrSwizzle& outputSwizzle,
@@ -44,6 +44,8 @@
GrTextureRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin, const GrSwizzle& textureSwizzle,
const GrSwizzle& outputSwizzle);
+ void initSurfaceFlags(const GrCaps&);
+
bool instantiate(GrResourceProvider*) override;
sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 1dbaa1e..3f1d016 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -51,10 +51,13 @@
// override of GrRenderTarget
ResolveType getResolveType() const override {
if (this->numSamples() <= 1 || fRTFBOID == fTexFBOID) { // Also catches FBO 0.
+ SkASSERT(!this->requiresManualMSAAResolve());
return kAutoResolves_ResolveType;
} else if (kUnresolvableFBOID == fTexFBOID) {
+ SkASSERT(!this->requiresManualMSAAResolve());
return kCantResolve_ResolveType;
} else {
+ SkASSERT(this->requiresManualMSAAResolve());
return kCanResolve_ResolveType;
}
}
diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h
index e558fa0..abf4c44 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.h
+++ b/src/gpu/mtl/GrMtlRenderTarget.h
@@ -28,8 +28,10 @@
// override of GrRenderTarget
ResolveType getResolveType() const override {
if (this->numSamples() > 1) {
+ SkASSERT(this->requiresManualMSAAResolve());
return kCanResolve_ResolveType;
}
+ SkASSERT(!this->requiresManualMSAAResolve());
return kAutoResolves_ResolveType;
}
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 6341131..2572e65 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -76,8 +76,10 @@
// override of GrRenderTarget
ResolveType getResolveType() const override {
if (this->numSamples() > 1) {
+ SkASSERT(this->requiresManualMSAAResolve());
return kCanResolve_ResolveType;
}
+ SkASSERT(!this->requiresManualMSAAResolve());
return kAutoResolves_ResolveType;
}