From 26dbe3bdaa22f3708a4928fe9d994fd8dec4ad9c Mon Sep 17 00:00:00 2001 From: Greg Daniel Date: Thu, 3 May 2018 10:35:42 -0400 Subject: Implement GL canCopySurface in GrGLCaps. Bug: skia: Change-Id: Ibd55a5a5e62121f58ef7c5148a54aaad6fdcd243 Reviewed-on: https://skia-review.googlesource.com/125480 Reviewed-by: Brian Salomon Reviewed-by: Robert Phillips Commit-Queue: Greg Daniel --- src/gpu/GrTextureProxyPriv.h | 3 + src/gpu/gl/GrGLCaps.cpp | 185 +++++++++++++++++++++++++++++++++++++++++++ src/gpu/gl/GrGLCaps.h | 18 +++++ src/gpu/gl/GrGLGpu.cpp | 141 ++++++++++----------------------- src/gpu/vk/GrVkCaps.h | 1 - 5 files changed, 246 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/gpu/GrTextureProxyPriv.h b/src/gpu/GrTextureProxyPriv.h index 8f50b90dad..cadd2fde63 100644 --- a/src/gpu/GrTextureProxyPriv.h +++ b/src/gpu/GrTextureProxyPriv.h @@ -35,6 +35,9 @@ public: bool isGLTextureRectangleOrExternal() const { return fTextureProxy->isGLTextureRectangleOrExternal(); } + // We assume that if a texture is not a GL_TEXTURE_RECTANGLE or GL_TEXTURE_EXTERNAL then it is a + // GL_TEXTURE_2D + bool isGLTexture2D() const { return !fTextureProxy->isGLTextureRectangleOrExternal(); } // We only support the clamp wrap mode with gl rectangle or external textures. bool isClampOnly() const { return fTextureProxy->isGLTextureRectangleOrExternal(); } diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 3bd857d53a..3ae321dd9e 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -10,8 +10,10 @@ #include "GrGLContext.h" #include "GrGLRenderTarget.h" #include "GrGLTexture.h" +#include "GrRenderTargetProxyPriv.h" #include "GrShaderCaps.h" #include "GrSurfaceProxyPriv.h" +#include "GrTextureProxyPriv.h" #include "SkJSONWriter.h" #include "SkTSearch.h" #include "SkTSort.h" @@ -2053,6 +2055,189 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, #endif } +bool GrGLCaps::canCopyTexSubImage(GrPixelConfig dstConfig, bool dstHasMSAARenderBuffer, + bool dstIsTextureable, bool dstIsGLTexture2D, + GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, bool srcHasMSAARenderBuffer, + bool srcIsTextureable, bool srcIsGLTexture2D, + GrSurfaceOrigin srcOrigin) const { + // Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage + // and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps + // many drivers would allow it to work, but ANGLE does not. + if (kGLES_GrGLStandard == fStandard && this->bgraIsInternalFormat() && + (kBGRA_8888_GrPixelConfig == dstConfig || kBGRA_8888_GrPixelConfig == srcConfig)) { + return false; + } + + // CopyTexSubImage is invalid or doesn't copy what we want when we have msaa render buffers. + if (dstHasMSAARenderBuffer || srcHasMSAARenderBuffer) { + return false; + } + + // CopyTex(Sub)Image writes to a texture and we have no way of dynamically wrapping a RT in a + // texture. + if (!dstIsTextureable) { + return false; + } + + // Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring + // is required + if (this->canConfigBeFBOColorAttachment(srcConfig) && + (!srcIsTextureable || srcIsGLTexture2D) && + dstIsGLTexture2D && + dstOrigin == srcOrigin) { + return true; + } else { + return false; + } +} + +bool GrGLCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt, + bool dstIsTextureable, bool dstIsGLTexture2D, + GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, int srcSampleCnt, + bool srcIsTextureable, bool srcIsGLTexture2D, + GrSurfaceOrigin srcOrigin, const SkRect& srcBounds, + const SkIRect& srcRect, const SkIPoint& dstPoint) const { + auto blitFramebufferFlags = this->blitFramebufferSupportFlags(); + if (!this->canConfigBeFBOColorAttachment(dstConfig) || + !this->canConfigBeFBOColorAttachment(srcConfig)) { + return false; + } + + if (dstIsTextureable && !dstIsGLTexture2D) { + return false; + } + if (srcIsTextureable && !srcIsGLTexture2D) { + return false; + } + + if (GrGLCaps::kNoSupport_BlitFramebufferFlag & blitFramebufferFlags) { + return false; + } + if (GrGLCaps::kNoScalingOrMirroring_BlitFramebufferFlag & blitFramebufferFlags) { + // We would mirror to compensate for origin changes. Note that copySurface is + // specified such that the src and dst rects are the same. + if (dstOrigin != srcOrigin) { + return false; + } + } + + if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) { + if (srcSampleCnt > 1) { + if (1 == dstSampleCnt) { + return false; + } + if (SkRect::Make(srcRect) != srcBounds) { + return false; + } + } + } + + if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) { + if (dstSampleCnt > 1) { + return false; + } + } + + if (GrGLCaps::kNoFormatConversion_BlitFramebufferFlag & blitFramebufferFlags) { + if (dstConfig != srcConfig) { + return false; + } + } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { + if (srcSampleCnt > 1 && dstConfig != srcConfig) { + return false; + } + } + + if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { + if (srcSampleCnt > 1) { + if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) { + return false; + } + if (dstOrigin != srcOrigin) { + return false; + } + } + } + return true; +} + +bool GrGLCaps::canCopyAsDraw(GrPixelConfig dstConfig, bool srcIsTextureable) const { + return this->canConfigBeFBOColorAttachment(dstConfig) && srcIsTextureable; +} + +static bool has_msaa_render_buffer(const GrSurfaceProxy* surf, const GrGLCaps& glCaps) { + const GrRenderTargetProxy* rt = surf->asRenderTargetProxy(); + if (!rt) { + return false; + } + // A RT has a separate MSAA renderbuffer if: + // 1) It's multisampled + // 2) We're using an extension with separate MSAA renderbuffers + // 3) It's not FBO 0, which is special and always auto-resolves + return rt->numColorSamples() > 1 && + glCaps.usesMSAARenderBuffers() && + !rt->rtPriv().glRTFBOIDIs0(); +} + +bool GrGLCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, + const SkIRect& srcRect, const SkIPoint& dstPoint) const { + GrSurfaceOrigin dstOrigin = dst->origin(); + GrSurfaceOrigin srcOrigin = src->origin(); + + GrPixelConfig dstConfig = dst->config(); + GrPixelConfig srcConfig = src->config(); + + int dstSampleCnt = 0; + int srcSampleCnt = 0; + if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) { + dstSampleCnt = rtProxy->numColorSamples(); + } + if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) { + srcSampleCnt = rtProxy->numColorSamples(); + } + SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy())); + SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy())); + + // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the + // swizzle. + if (this->shaderCaps()->configOutputSwizzle(src->config()) != + this->shaderCaps()->configOutputSwizzle(dst->config())) { + return false; + } + + const GrTextureProxy* dstTex = dst->asTextureProxy(); + const GrTextureProxy* srcTex = src->asTextureProxy(); + + bool dstIsTex2D = dstTex ? dstTex->texPriv().isGLTexture2D() : false; + bool srcIsTex2D = srcTex ? srcTex->texPriv().isGLTexture2D() : false; + + // One of the possible requirements for copy as blit is that the srcRect must match the bounds + // of the src surface. If we have a approx fit surface we can't know for sure what the src + // bounds will be at this time. Thus we assert that if we say we can copy as blit and the src is + // approx that we also can copy as draw. Therefore when it comes time to do the copy we will + // know we will at least be able to do it as a draw. +#ifdef SK_DEBUG + if (this->canCopyAsBlit(dstConfig, dstSampleCnt, SkToBool(dstTex), + dstIsTex2D, dstOrigin, srcConfig, srcSampleCnt, SkToBool(srcTex), + srcIsTex2D, srcOrigin, src->getBoundsRect(), srcRect, dstPoint) && + !src->priv().isExact()) { + SkASSERT(this->canCopyAsDraw(dstConfig, SkToBool(srcTex))); + } +#endif + + return this->canCopyTexSubImage(dstConfig, has_msaa_render_buffer(dst, *this), + SkToBool(dstTex), dstIsTex2D, dstOrigin, + srcConfig, has_msaa_render_buffer(src, *this), + SkToBool(srcTex), srcIsTex2D, srcOrigin) || + this->canCopyAsBlit(dstConfig, dstSampleCnt, SkToBool(dstTex), + dstIsTex2D, dstOrigin, srcConfig, srcSampleCnt, SkToBool(srcTex), + srcIsTex2D, srcOrigin, src->getBoundsRect(), srcRect, + dstPoint) || + this->canCopyAsDraw(dstConfig, SkToBool(srcTex)); +} + bool GrGLCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, GrSurfaceOrigin* origin, bool* rectsMustMatch, bool* disallowSubrect) const { diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index c564cf1d50..76eec3afb0 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -407,6 +407,24 @@ public: : pendingInstanceCount; } + bool canCopyTexSubImage(GrPixelConfig dstConfig, bool dstHasMSAARenderBuffer, + bool dstIsTextureable, bool dstIsGLTexture2D, + GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, bool srcHasMSAARenderBuffer, + bool srcIsTextureable, bool srcIsGLTexture2D, + GrSurfaceOrigin srcOrigin) const; + bool canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt, + bool dstIsTextureable, bool dstIsGLTexture2D, + GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, int srcSampleCnt, + bool srcIsTextureable, bool srcIsGLTexture2D, + GrSurfaceOrigin srcOrigin, const SkRect& srcBounds, + const SkIRect& srcRect, const SkIPoint& dstPoint) const; + bool canCopyAsDraw(GrPixelConfig dstConfig, bool srcIsTextureable) const; + + bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, + const SkIRect& srcRect, const SkIPoint& dstPoint) const override; + bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, GrSurfaceOrigin*, bool* rectsMustMatch, bool* disallowSubrect) const override; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index ba85868ddd..908d367fcd 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -3293,70 +3293,27 @@ static inline bool can_blit_framebuffer_for_copy_surface( const GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint, - const GrGLGpu* gpu) { - auto blitFramebufferFlags = gpu->glCaps().blitFramebufferSupportFlags(); - if (!gpu->glCaps().canConfigBeFBOColorAttachment(dst->config()) || - !gpu->glCaps().canConfigBeFBOColorAttachment(src->config())) { - return false; + const GrGLCaps& caps) { + int dstSampleCnt = 0; + int srcSampleCnt = 0; + if (const GrRenderTarget* rt = dst->asRenderTarget()) { + dstSampleCnt = rt->numColorSamples(); + } + if (const GrRenderTarget* rt = src->asRenderTarget()) { + srcSampleCnt = rt->numColorSamples(); } - // Blits are not allowed between int color buffers and float/fixed color buffers. GrGpu should - // have filtered such cases out. + SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTarget())); + SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTarget())); + const GrGLTexture* dstTex = static_cast(dst->asTexture()); const GrGLTexture* srcTex = static_cast(src->asTexture()); - const GrRenderTarget* dstRT = dst->asRenderTarget(); - const GrRenderTarget* srcRT = src->asRenderTarget(); - if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) { - return false; - } - if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) { - return false; - } - if (GrGLCaps::kNoSupport_BlitFramebufferFlag & blitFramebufferFlags) { - return false; - } - if (GrGLCaps::kNoScalingOrMirroring_BlitFramebufferFlag & blitFramebufferFlags) { - // We would mirror to compensate for origin changes. Note that copySurface is - // specified such that the src and dst rects are the same. - if (dstOrigin != srcOrigin) { - return false; - } - } - if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) { - if (srcRT && srcRT->numColorSamples() > 1) { - if (dstRT && 1 == dstRT->numColorSamples()) { - return false; - } - if (SkRect::Make(srcRect) != srcRT->getBoundsRect()) { - return false; - } - } - } - if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) { - if (dstRT && dstRT->numColorSamples() > 1) { - return false; - } - } - if (GrGLCaps::kNoFormatConversion_BlitFramebufferFlag & blitFramebufferFlags) { - if (dst->config() != src->config()) { - return false; - } - } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { - const GrRenderTarget* srcRT = src->asRenderTarget(); - if (srcRT && srcRT->numColorSamples() > 1 && dst->config() != src->config()) { - return false; - } - } - if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { - if (srcRT && srcRT->numColorSamples() > 1) { - if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) { - return false; - } - if (dstOrigin != srcOrigin) { - return false; - } - } - } - return true; + + bool dstIsGLTexture2D = dstTex ? GR_GL_TEXTURE_2D == dstTex->target() : false; + bool srcIsGLTexture2D = srcTex ? GR_GL_TEXTURE_2D == srcTex->target() : false; + + return caps.canCopyAsBlit(dst->config(), dstSampleCnt, SkToBool(dstTex), dstIsGLTexture2D, + dstOrigin, src->config(), srcSampleCnt, SkToBool(srcTex), + srcIsGLTexture2D, srcOrigin, src->getBoundsRect(), srcRect, dstPoint); } static bool rt_has_msaa_render_buffer(const GrGLRenderTarget* rt, const GrGLCaps& glCaps) { @@ -3369,45 +3326,23 @@ static bool rt_has_msaa_render_buffer(const GrGLRenderTarget* rt, const GrGLCaps static inline bool can_copy_texsubimage(const GrSurface* dst, GrSurfaceOrigin dstOrigin, const GrSurface* src, GrSurfaceOrigin srcOrigin, - const GrGLGpu* gpu) { - // Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage - // and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps - // many drivers would allow it to work, but ANGLE does not. - if (kGLES_GrGLStandard == gpu->glStandard() && gpu->glCaps().bgraIsInternalFormat() && - (kBGRA_8888_GrPixelConfig == dst->config() || kBGRA_8888_GrPixelConfig == src->config())) { - return false; - } + const GrGLCaps& caps) { + const GrGLRenderTarget* dstRT = static_cast(dst->asRenderTarget()); - // If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer) - // then we don't want to copy to the texture but to the MSAA buffer. - if (dstRT && rt_has_msaa_render_buffer(dstRT, gpu->glCaps())) { - return false; - } const GrGLRenderTarget* srcRT = static_cast(src->asRenderTarget()); - // If the src is multisampled (and uses an extension where there is a separate MSAA - // renderbuffer) then it is an invalid operation to call CopyTexSubImage - if (srcRT && rt_has_msaa_render_buffer(srcRT, gpu->glCaps())) { - return false; - } - const GrGLTexture* dstTex = static_cast(dst->asTexture()); - // CopyTex(Sub)Image writes to a texture and we have no way of dynamically wrapping a RT in a - // texture. - if (!dstTex) { - return false; - } - const GrGLTexture* srcTex = static_cast(src->asTexture()); - // Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring - // is required. - if (gpu->glCaps().canConfigBeFBOColorAttachment(src->config()) && - (!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) && dstTex->target() == GR_GL_TEXTURE_2D && - dstOrigin == srcOrigin) { - return true; - } else { - return false; - } + bool dstHasMSAARenderBuffer = dstRT ? rt_has_msaa_render_buffer(dstRT, caps) : false; + bool srcHasMSAARenderBuffer = srcRT ? rt_has_msaa_render_buffer(srcRT, caps) : false; + + bool dstIsGLTexture2D = dstTex ? GR_GL_TEXTURE_2D == dstTex->target() : false; + bool srcIsGLTexture2D = srcTex ? GR_GL_TEXTURE_2D == srcTex->target() : false; + + return caps.canCopyTexSubImage(dst->config(), dstHasMSAARenderBuffer, SkToBool(dstTex), + dstIsGLTexture2D, dstOrigin, src->config(), + srcHasMSAARenderBuffer, SkToBool(srcTex), srcIsGLTexture2D, + srcOrigin); } // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is @@ -3472,24 +3407,24 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, // Don't prefer copying as a draw if the dst doesn't already have a FBO object. // This implicitly handles this->glCaps().useDrawInsteadOfAllRenderTargetWrites(). bool preferCopy = SkToBool(dst->asRenderTarget()); - if (preferCopy && src->asTexture()) { + if (preferCopy && this->glCaps().canCopyAsDraw(dst->config(), SkToBool(src->asTexture()))) { if (this->copySurfaceAsDraw(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint)) { return true; } } - if (can_copy_texsubimage(dst, dstOrigin, src, srcOrigin, this)) { + if (can_copy_texsubimage(dst, dstOrigin, src, srcOrigin, this->glCaps())) { this->copySurfaceAsCopyTexSubImage(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint); return true; } if (can_blit_framebuffer_for_copy_surface(dst, dstOrigin, src, srcOrigin, - srcRect, dstPoint, this)) { + srcRect, dstPoint, this->glCaps())) { return this->copySurfaceAsBlitFramebuffer(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint); } - if (!preferCopy && src->asTexture()) { + if (!preferCopy && this->glCaps().canCopyAsDraw(dst->config(), SkToBool(src->asTexture()))) { if (this->copySurfaceAsDraw(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint)) { return true; } @@ -4012,6 +3947,10 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrGLTexture* srcTex = static_cast(src->asTexture()); int progIdx = TextureToCopyProgramIdx(srcTex); + if (!this->glCaps().canConfigBeFBOColorAttachment(dst->config())) { + return false; + } + if (!fCopyPrograms[progIdx].fProgram) { if (!this->createCopyProgram(srcTex)) { SkDebugf("Failed to create copy program.\n"); @@ -4097,7 +4036,7 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurfaceOrigin dstOr GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint) { - SkASSERT(can_copy_texsubimage(dst, dstOrigin, src, srcOrigin, this)); + SkASSERT(can_copy_texsubimage(dst, dstOrigin, src, srcOrigin, this->glCaps())); GrGLIRect srcVP; this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); GrGLTexture* dstTex = static_cast(dst->asTexture()); @@ -4130,7 +4069,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurfaceOrigin dstOr const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(can_blit_framebuffer_for_copy_surface(dst, dstOrigin, src, srcOrigin, - srcRect, dstPoint, this)); + srcRect, dstPoint, this->glCaps())); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); if (dst == src) { diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h index 69298d7f5e..0d11667b6d 100644 --- a/src/gpu/vk/GrVkCaps.h +++ b/src/gpu/vk/GrVkCaps.h @@ -131,7 +131,6 @@ public: bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const override; - bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, GrSurfaceOrigin*, bool* rectsMustMatch, bool* disallowSubrect) const override; -- cgit v1.2.3