Rework GL fbo blit limitations as finer grained flags.

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3480
BUG=skia:5804

Change-Id: Idd86f96a92420ec98c7cf07962f4857e0b81b9c6
Reviewed-on: https://skia-review.googlesource.com/3480
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2016-10-14 16:18:33 -04:00 committed by Skia Commit-Bot
parent 273f7d4915
commit e5e7eb1478
3 changed files with 97 additions and 72 deletions

View File

@ -52,7 +52,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fRGBAToBGRAReadbackConversionsAreSlow = false;
fDoManualMipmapping = false;
fBlitFramebufferSupport = kNone_BlitFramebufferSupport;
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
fShaderCaps.reset(new GrGLSLCaps(contextOptions));
@ -919,8 +919,6 @@ bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig,
}
void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
fMSFBOType = kNone_MSFBOType;
if (kGL_GrGLStandard != ctxInfo.standard()) {
// We prefer the EXT/IMG extension over ES3 MSAA because we've observed
// ES3 driver bugs on at least one device with a tiled GPU (N10).
@ -940,24 +938,28 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa
// Above determined the preferred MSAA approach, now decide whether glBlitFramebuffer
// is available.
if (ctxInfo.version() >= GR_GL_VER(3, 0)) {
fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
fBlitFramebufferFlags = kNoFormatConversionForMSAASrc_BlitFramebufferFlag |
kRectsMustMatchForMSAASrc_BlitFramebufferFlag;
} else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
// The CHROMIUM extension uses the ANGLE version of glBlitFramebuffer and includes its
// limitations.
fBlitFramebufferSupport = kNoScalingNoMirroring_BlitFramebufferSupport;
fBlitFramebufferFlags = kNoScalingOrMirroring_BlitFramebufferFlag |
kResolveMustBeFull_BlitFrambufferFlag |
kNoMSAADst_BlitFramebufferFlag |
kNoFormatConversion_BlitFramebufferFlag;
}
} else {
if (fUsesMixedSamples) {
fMSFBOType = kMixedSamples_MSFBOType;
fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
fBlitFramebufferFlags = 0;
} else if (ctxInfo.version() >= GR_GL_VER(3,0) ||
ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
fMSFBOType = kStandard_MSFBOType;
fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
fBlitFramebufferFlags = 0;
} else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") &&
ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
fMSFBOType = kEXT_MSFBOType;
fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
fBlitFramebufferFlags = 0;
}
}
}

View File

@ -73,19 +73,14 @@ public:
kLast_MSFBOType = kMixedSamples_MSFBOType
};
enum BlitFramebufferSupport {
kNone_BlitFramebufferSupport,
/**
* ANGLE exposes a limited blit framebuffer extension that does not allow for stretching
* or mirroring.
*/
kNoScalingNoMirroring_BlitFramebufferSupport,
/**
* ES3 has restricted support when the src is MSAA: src rect == dst rect, dst format == src
* format.
*/
kRectsAndFormatsMatchForMSAASrc_BlitFramebufferSupport,
kFull_BlitFramebufferSupport
enum BlitFramebufferFlags {
kNoSupport_BlitFramebufferFlag = 1 << 0,
kNoScalingOrMirroring_BlitFramebufferFlag = 1 << 1,
kResolveMustBeFull_BlitFrambufferFlag = 1 << 2,
kNoMSAADst_BlitFramebufferFlag = 1 << 3,
kNoFormatConversion_BlitFramebufferFlag = 1 << 4,
kNoFormatConversionForMSAASrc_BlitFramebufferFlag = 1 << 5,
kRectsMustMatchForMSAASrc_BlitFramebufferFlag = 1 << 6,
};
enum InvalidateFBType {
@ -235,7 +230,7 @@ public:
/**
* What functionality is supported by glBlitFramebuffer.
*/
BlitFramebufferSupport blitFramebufferSupport() const { return fBlitFramebufferSupport; }
uint32_t blitFramebufferSupportFlags() const { return fBlitFramebufferFlags; }
/**
* Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and
@ -419,7 +414,7 @@ private:
bool fRGBAToBGRAReadbackConversionsAreSlow : 1;
bool fDoManualMipmapping : 1;
BlitFramebufferSupport fBlitFramebufferSupport;
uint32_t fBlitFramebufferFlags;
/** Number type of the components (with out considering number of bits.) */
enum FormatType {

View File

@ -2921,18 +2921,27 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) {
this->disableWindowRectangles();
GL_CALL(ResolveMultisampleFramebuffer());
} else {
GrGLIRect r;
r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
dirtyRect.width(), dirtyRect.height(), target->origin());
int right = r.fLeft + r.fWidth;
int top = r.fBottom + r.fHeight;
int l, b, r, t;
if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag &
this->glCaps().blitFramebufferSupportFlags()) {
l = 0;
b = 0;
r = target->width();
t = target->height();
} else {
GrGLIRect rect;
rect.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
dirtyRect.width(), dirtyRect.height(), target->origin());
l = rect.fLeft;
b = rect.fBottom;
r = rect.fLeft + rect.fWidth;
t = rect.fBottom + rect.fHeight;
}
// BlitFrameBuffer respects the scissor, so disable it.
this->disableScissor();
this->disableWindowRectangles();
GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
r.fLeft, r.fBottom, right, top,
GL_CALL(BlitFramebuffer(l, b, r, t, l, b, r, t,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
}
}
@ -3472,45 +3481,64 @@ void GrGLGpu::setScratchTextureUnit() {
fHWBoundTextureUniqueIDs[lastUnitIdx] = SK_InvalidUniqueID;
}
// Determines whether glBlitFramebuffer could be used between src and dst.
static inline bool can_blit_framebuffer(const GrSurface* dst,
const GrSurface* src,
const GrGLGpu* gpu) {
if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) &&
gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0)) {
switch (gpu->glCaps().blitFramebufferSupport()) {
case GrGLCaps::kNone_BlitFramebufferSupport:
return false;
case GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport:
// Our copy surface doesn't support scaling so just check for mirroring.
if (dst->origin() != src->origin()) {
return false;
}
break;
// ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't
// match or the rects are not the same (not just the same size but have the same
// edges).
case GrGLCaps::kRectsAndFormatsMatchForMSAASrc_BlitFramebufferSupport:
if ((src->desc().fSampleCnt > 0 || src->config() != dst->config())) {
return false;
}
break;
case GrGLCaps::kFull_BlitFramebufferSupport:
return true;
}
const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) {
return false;
}
const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(dst->asTexture());
if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) {
return false;
}
return true;
} else {
// Determines whether glBlitFramebuffer could be used between src and dst by onCopySurface.
static inline bool can_blit_framebuffer_for_copy_surface(const GrSurface* dst,
const GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint,
const GrGLGpu* gpu) {
auto blitFramebufferFlags = gpu->glCaps().blitFramebufferSupportFlags();
if (!gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) ||
!gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0)) {
return false;
}
const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(dst->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 (dst->origin() != src->origin()) {
return false;
}
}
if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) {
if (srcRT && srcRT->numColorSamples() && dstRT && !dstRT->numColorSamples()) {
return false;
}
}
if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) {
if (dstRT && dstRT->numColorSamples() > 0) {
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() && dst->config() != src->config()) {
return false;
}
}
if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) {
if (srcRT && srcRT->numColorSamples() &&
(dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop)) {
return false;
}
}
return true;
}
static inline bool can_copy_texsubimage(const GrSurface* dst,
@ -3627,8 +3655,8 @@ bool GrGLGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc)
// creation. It isn't clear that avoiding temporary fbo creation is actually optimal.
GrSurfaceOrigin originForBlitFramebuffer = kDefault_GrSurfaceOrigin;
if (this->glCaps().blitFramebufferSupport() ==
GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport) {
if (this->glCaps().blitFramebufferSupportFlags() &
GrGLCaps::kNoScalingOrMirroring_BlitFramebufferFlag) {
originForBlitFramebuffer = src->origin();
}
@ -3689,7 +3717,7 @@ bool GrGLGpu::onCopySurface(GrSurface* dst,
return true;
}
if (can_blit_framebuffer(dst, src, this)) {
if (can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this)) {
return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint);
}
@ -4279,7 +4307,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
SkASSERT(can_blit_framebuffer(dst, src, this));
SkASSERT(can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this));
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height());
if (dst == src) {