From 8f00dd3f30871ded8aa3f3ecbf8e5e1cc9e10339 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 4 Feb 2017 15:30:59 +0100 Subject: [PATCH] Hide glBlitFramebuffer behind fbo_blit --- GPU/GLES/FBO.cpp | 19 +++++++++++++++++++ GPU/GLES/FBO.h | 12 ++++++++++++ GPU/GLES/FramebufferManagerGLES.cpp | 28 ++++------------------------ GPU/GLES/StencilBufferGLES.cpp | 11 +---------- GPU/Vulkan/FramebufferVulkan.cpp | 1 - 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/GPU/GLES/FBO.cpp b/GPU/GLES/FBO.cpp index 00c8ee952c..586f89f8ee 100644 --- a/GPU/GLES/FBO.cpp +++ b/GPU/GLES/FBO.cpp @@ -400,6 +400,25 @@ void fbo_copy_image(FBO *src, int srcLevel, int srcX, int srcY, int srcZ, FBO *d #endif } +void fbo_blit(FBO *src, int srcX1, int srcY1, int srcX2, int srcY2, FBO *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channels, FBBlitFilter linearFilter) { + GLuint bits = 0; + if (channels & FB_COLOR_BIT) + bits |= GL_COLOR_BUFFER_BIT; + if (channels & FB_DEPTH_BIT) + bits |= GL_DEPTH_BUFFER_BIT; + if (channels & FB_STENCIL_BIT) + bits |= GL_STENCIL_BUFFER_BIT; + fbo_bind_as_render_target(dst); + fbo_bind_for_read(src); + if (gl_extensions.GLES3 || gl_extensions.ARB_framebuffer_object) { + glBlitFramebuffer(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, bits, linearFilter == FB_BLIT_LINEAR ? GL_LINEAR : GL_NEAREST); +#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC. + } else if (gl_extensions.NV_framebuffer_blit) { + glBlitFramebufferNV(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, bits, linearFilter == FB_BLIT_LINEAR ? GL_LINEAR : GL_NEAREST); +#endif // defined(USING_GLES2) && defined(__ANDROID__) + } +} + void fbo_bind_color_as_texture(FBO *fbo, int color) { if (fbo) { glBindTexture(GL_TEXTURE_2D, fbo->color_texture); diff --git a/GPU/GLES/FBO.h b/GPU/GLES/FBO.h index 0b308a8b4b..1243c7b5da 100644 --- a/GPU/GLES/FBO.h +++ b/GPU/GLES/FBO.h @@ -33,6 +33,16 @@ enum FBOColorDepth { FBO_5551, }; +enum FBOChannel { + FB_COLOR_BIT = 1, + FB_DEPTH_BIT = 2, + FB_STENCIL_BIT = 4, +}; + +enum FBBlitFilter { + FB_BLIT_NEAREST = 0, + FB_BLIT_LINEAR = 1, +}; // Creates a simple FBO with a RGBA32 color buffer stored in a texture, and // optionally an accompanying Z/stencil buffer. @@ -45,6 +55,8 @@ FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, F void fbo_copy_image(FBO *src, int level, int x, int y, int z, FBO *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth); +void fbo_blit(FBO *src, int srcX1, int srcY1, int srcX2, int srcY2, FBO *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter); + int fbo_standard_z_depth(); int fbo_check_framebuffer_status(FBO *fbo); diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index b445ded9fa..eb54827afc 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -440,6 +440,7 @@ void FramebufferManagerGLES::DrawFramebufferToOutput(const u8 *srcPixels, GEBuff } // x, y, w, h are relative coordinates against destW/destH, which is not very intuitive. +// TODO: This could totally use fbo_blit. void FramebufferManagerGLES::DrawActiveTexture(GLuint texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, GLSLProgram *program, int uvRotation) { float texCoords[8] = { u0,v0, @@ -782,22 +783,10 @@ void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, Virtu int h = std::min(src->renderHeight, dst->renderHeight); if (gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT)) { - // Only use NV if ARB isn't supported. - bool useNV = !gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT); - // Let's only do this if not clearing depth. - fbo_bind_for_read(src->fbo); glstate.scissorTest.force(false); - - if (useNV) { -#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC. - glBlitFramebufferNV(0, 0, w, h, 0, 0, w, h, GL_DEPTH_BUFFER_BIT, GL_NEAREST); -#endif // defined(USING_GLES2) && defined(__ANDROID__) - } else { - glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - // If we set dst->depthUpdated here, our optimization above would be pointless. - + fbo_blit(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, FB_DEPTH_BIT, FB_BLIT_NEAREST); + // WARNING: If we set dst->depthUpdated here, our optimization above would be pointless. glstate.scissorTest.restore(); } } @@ -1303,16 +1292,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, glstate.scissorTest.force(false); if (useBlit) { - fbo_bind_as_render_target(dst->fbo); - fbo_bind_for_read(src->fbo); - if (!useNV) { - glBlitFramebuffer(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } else { -#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC. - glBlitFramebufferNV(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, GL_COLOR_BUFFER_BIT, GL_NEAREST); -#endif // defined(USING_GLES2) && defined(__ANDROID__) - } - + fbo_blit(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, FB_COLOR_BIT, FB_BLIT_NEAREST); fbo_unbind_read(); } else { fbo_bind_as_render_target(dst->fbo); diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 3209c360b1..e7866bfca3 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -171,7 +171,6 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE); bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT); - bool useNV = useBlit && !gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT); // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. @@ -221,15 +220,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe glstate.stencilMask.set(0xFF); if (useBlit) { - fbo_bind_as_render_target(dstBuffer->fbo); - fbo_bind_for_read(blitFBO); - if (!useNV) { - glBlitFramebuffer(0, 0, w, h, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, GL_STENCIL_BUFFER_BIT, GL_NEAREST); - } else { -#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC. - glBlitFramebufferNV(0, 0, w, h, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, GL_STENCIL_BUFFER_BIT, GL_NEAREST); -#endif // defined(USING_GLES2) && defined(__ANDROID__) - } + fbo_blit(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, FB_STENCIL_BIT, FB_BLIT_NEAREST); } RebindFramebuffer(); diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 1b26cecadc..7aa1c00dae 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -1201,7 +1201,6 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX return; } - // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. // In case the src goes outside, we just skip the optimization in that case. const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; const bool sameDepth = dst->colorDepth == src->colorDepth;