Implement support for framebufferOnly render targets.
This reflects Dawn and Metal functionality.
Implement a FramebufferOnly flag on GrSurface and GrBackendRenderTarget.
Forward the state from GrBackendRenderTarget to GrSurface.
Check the GrSurface flag in GrGpu::readPixels() and GrGpu::writePixels()
and early-return.
Change-Id: I27d3c9c912b366791bfd0e1db49638d8925742f3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/262802
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index 1254f88..8531340 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -49,6 +49,7 @@
GrBackendRenderTarget() {}
bool isValid() const { return false; }
+ bool isFramebufferOnly() const { return false; }
};
#else
@@ -371,6 +372,7 @@
int sampleCnt() const { return fSampleCnt; }
int stencilBits() const { return fStencilBits; }
GrBackendApi backend() const {return fBackend; }
+ bool isFramebufferOnly() const { return fFramebufferOnly; }
// If the backend API is GL, copies a snapshot of the GrGLFramebufferInfo struct into the passed
// in pointer and returns true. Otherwise returns false if the backend API is not GL.
@@ -427,6 +429,7 @@
void cleanup();
bool fIsValid;
+ bool fFramebufferOnly = false;
int fWidth; //<! width in pixels
int fHeight; //<! height in pixels
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index cd0d456..791ca36 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -81,9 +81,18 @@
*/
bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
+ bool framebufferOnly() const {
+ return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
+ }
+
// Returns true if we are working with protected content.
bool isProtected() const { return fIsProtected == GrProtected::kYes; }
+ void setFramebufferOnly() {
+ SkASSERT(this->asRenderTarget());
+ fSurfaceFlags |= GrInternalSurfaceFlags::kFramebufferOnly;
+ }
+
protected:
void setGLRTFBOIDIs0() {
SkASSERT(!this->requiresManualMSAAResolve());
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 73733e1..0e91874 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -701,6 +701,10 @@
// (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,
+
+ // This means the pixels in the render target are write-only. This is used for Dawn and Metal
+ // swap chain targets which can be rendered to, but not read or copied.
+ kFramebufferOnly = 1 << 3,
};
GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags)
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 3986afd..f45b457 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -665,6 +665,7 @@
int stencilBits,
const GrDawnImageInfo& dawnInfo)
: fIsValid(true)
+ , fFramebufferOnly(true)
, fWidth(width)
, fHeight(height)
, fSampleCnt(sampleCnt)
@@ -715,6 +716,7 @@
int sampleCnt,
const GrMtlTextureInfo& mtlInfo)
: fIsValid(true)
+ , fFramebufferOnly(false) // TODO: set this from mtlInfo.fTexture->framebufferOnly
, fWidth(width)
, fHeight(height)
, fSampleCnt(SkTMax(1, sampleCnt))
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 0356651..3c0e808 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -380,7 +380,11 @@
return nullptr;
}
- return this->onWrapBackendRenderTarget(backendRT, colorType);
+ sk_sp<GrRenderTarget> rt = this->onWrapBackendRenderTarget(backendRT, colorType);
+ if (backendRT.isFramebufferOnly()) {
+ rt->setFramebufferOnly();
+ }
+ return rt;
}
sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& backendTex,
@@ -432,6 +436,7 @@
const SkIPoint& dstPoint) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
SkASSERT(dst && src);
+ SkASSERT(!src->framebufferOnly());
if (dst->readOnly()) {
return false;
@@ -447,6 +452,7 @@
size_t rowBytes) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
SkASSERT(surface);
+ SkASSERT(!surface->framebufferOnly());
SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
auto subRect = SkIRect::MakeXYWH(left, top, width, height);
@@ -480,6 +486,7 @@
const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
SkASSERT(surface);
+ SkASSERT(!surface->framebufferOnly());
SkASSERT(this->caps()->isFormatTexturableAndUploadable(surfaceColorType,
surface->backendFormat()));
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 69d10da..bab4d1db 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1688,6 +1688,10 @@
callback(context, nullptr);
return;
}
+ if (this->asRenderTargetProxy()->framebufferOnly()) {
+ callback(context, nullptr);
+ return;
+ }
auto dstCT = SkColorTypeToGrColorType(info.colorType());
if (dstCT == GrColorType::kUnknown) {
callback(context, nullptr);
@@ -1933,6 +1937,10 @@
callback(context, nullptr);
return;
}
+ if (this->asRenderTargetProxy()->framebufferOnly()) {
+ callback(context, nullptr);
+ return;
+ }
if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
callback(context, nullptr);
return;
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index f41d168..dc4860b 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -157,6 +157,10 @@
GrSurfaceProxy* srcProxy = this->asSurfaceProxy();
+ if (srcProxy->framebufferOnly()) {
+ return false;
+ }
+
// MDB TODO: delay this instantiation until later in the method
if (!srcProxy->instantiate(direct->priv().resourceProvider())) {
return false;
@@ -315,6 +319,11 @@
}
GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
+
+ if (dstProxy->framebufferOnly()) {
+ return false;
+ }
+
if (!dstProxy->instantiate(direct->priv().resourceProvider())) {
return false;
}
@@ -484,6 +493,10 @@
SkASSERT(src->textureSwizzle() == this->asSurfaceProxy()->textureSwizzle());
SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
+ if (this->asSurfaceProxy()->framebufferOnly()) {
+ return false;
+ }
+
if (!caps->canCopySurface(this->asSurfaceProxy(), src, srcRect, dstPoint)) {
return false;
}
@@ -508,6 +521,10 @@
return nullptr;
}
+ if (this->asSurfaceProxy()->framebufferOnly()) {
+ return nullptr;
+ }
+
// We rescale by drawing and don't currently support drawing to a kUnpremul destination.
if (info.alphaType() == kUnpremul_SkAlphaType) {
return nullptr;
diff --git a/src/gpu/GrSurfaceProxy.h b/src/gpu/GrSurfaceProxy.h
index 79ac4b4..f9f2197 100644
--- a/src/gpu/GrSurfaceProxy.h
+++ b/src/gpu/GrSurfaceProxy.h
@@ -245,6 +245,9 @@
* assignment in GrResourceAllocator.
*/
bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
+ bool framebufferOnly() const {
+ return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
+ }
/**
* This means surface is a multisampled render target, and internally holds a non-msaa texture
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index a6b0e9e..6b5d3f0 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -32,7 +32,9 @@
, fMipMapped(mipMapped)
, fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus))
, fProxyProvider(nullptr)
- , fDeferredUploader(nullptr) {}
+ , fDeferredUploader(nullptr) {
+ SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
+}
// Lazy-callback version
GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback,
@@ -52,7 +54,9 @@
, fMipMapped(mipMapped)
, fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus))
, fProxyProvider(nullptr)
- , fDeferredUploader(nullptr) {}
+ , fDeferredUploader(nullptr) {
+ SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
+}
// Wrapped version
GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf,