From f1ec201dbc6af46fb1b2f6ac57267c2bdd54a0f8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 27 Aug 2014 22:58:11 -0700 Subject: [PATCH] Cache bound fbos, allow unbinding only read. This maintains the currently bound fbos, similar to glstate. So long as these funcs are used, it can prevent duplicate binds. Binding the same buffer twice comes with a performance penalty. --- gfx_es2/fbo.cpp | 94 ++++++++++++++++++++++++++++++------------------- gfx_es2/fbo.h | 2 ++ 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/gfx_es2/fbo.cpp b/gfx_es2/fbo.cpp index bd60a14d0..232ed8577 100644 --- a/gfx_es2/fbo.cpp +++ b/gfx_es2/fbo.cpp @@ -43,6 +43,9 @@ struct FBO { static FBO *g_overriddenBackbuffer; +static GLuint currentDrawHandle_ = 0; +static GLuint currentReadHandle_ = 0; + // On PC, we always use GL_DEPTH24_STENCIL8. // On Android, we try to use what's available. @@ -118,6 +121,9 @@ FBO *fbo_ext_create(int width, int height, int num_color_textures, bool z_stenci // Unbind state we don't need glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glBindTexture(GL_TEXTURE_2D, 0); + + currentDrawHandle_ = fbo->handle; + currentReadHandle_ = fbo->handle; return fbo; } #endif @@ -237,6 +243,9 @@ FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, F // Unbind state we don't need glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); + + currentDrawHandle_ = fbo->handle; + currentReadHandle_ = fbo->handle; return fbo; } @@ -258,6 +267,37 @@ FBO *fbo_create_from_native_fbo(GLuint native_fbo, FBO *fbo) return fbo; } +static GLenum fbo_get_fb_target(bool read, GLuint **cached) { + bool supportsBlit = gl_extensions.FBO_ARB; +#ifdef USING_GLES2 + supportsBlit = supportsBlit && (gl_extensions.GLES3 || gl_extensions.NV_framebuffer_blit); +#endif + + // Note: GL_FRAMEBUFFER_EXT and GL_FRAMEBUFFER have the same value, same with _NV. + if (supportsBlit) { + if (read) { + *cached = ¤tReadHandle_; + return GL_READ_FRAMEBUFFER; + } else { + *cached = ¤tDrawHandle_; + return GL_DRAW_FRAMEBUFFER; + } + } else { + *cached = ¤tDrawHandle_; + return GL_FRAMEBUFFER; + } +} + +static void fbo_bind_fb_target(bool read, GLuint name) { + GLuint *cached; + GLenum target = fbo_get_fb_target(read, &cached); + + if (*cached != name) { + glBindFramebuffer(target, name); + *cached = name; + } +} + void fbo_unbind() { if (g_overriddenBackbuffer) { fbo_bind_as_render_target(g_overriddenBackbuffer); @@ -275,6 +315,9 @@ void fbo_unbind() { #ifdef IOS bindDefaultFBO(); #endif + + currentDrawHandle_ = 0; + currentReadHandle_ = 0; } void fbo_override_backbuffer(FBO *fbo) { @@ -282,48 +325,24 @@ void fbo_override_backbuffer(FBO *fbo) { } void fbo_bind_as_render_target(FBO *fbo) { - if (gl_extensions.FBO_ARB) { -#ifndef USING_GLES2 - if (true) { -#else - if (gl_extensions.GLES3) { -#endif - // GL_DRAW_FRAMEBUFFER is actually the same value as GL_FRAMEBUFFER so this is a bit redundant. - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle); - } else { - // This will collide with bind_for_read - but there's nothing in ES 2.0 - // that actually separate them anyway of course, so doesn't matter. - glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); - } - }else{ -#ifndef USING_GLES2 - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle); -#endif - } + // Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing + // in ES 2.0 that actually separate them anyway of course, so doesn't matter. + fbo_bind_fb_target(false, fbo->handle); // Always restore viewport after render target binding glstate.viewport.restore(); } +void fbo_unbind_render_target() { + fbo_unbind(); +} + // For GL_EXT_FRAMEBUFFER_BLIT and similar. void fbo_bind_for_read(FBO *fbo) { - if (gl_extensions.FBO_ARB) { -#ifndef USING_GLES2 - if (true) { -#else - if (gl_extensions.GLES3 || gl_extensions.NV_framebuffer_blit) { -#endif - // GL_READ_FRAMEBUFFER is defined to the same value as GL_READ_FRAMEBUFFER_NV. - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle); - } else { - // This will collide with bind_as_render_target - but there's nothing in ES 2.0 - // that actually separate them anyway of course, so doesn't matter. - glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); - } - } else { -#ifndef USING_GLES2 - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle); -#endif - } + fbo_bind_fb_target(true, fbo->handle); +} + +void fbo_unbind_read() { + fbo_bind_fb_target(true, 0); } void fbo_bind_color_as_texture(FBO *fbo, int color) { @@ -358,6 +377,9 @@ void fbo_destroy(FBO *fbo) { #endif } + currentDrawHandle_ = 0; + currentReadHandle_ = 0; + glDeleteTextures(1, &fbo->color_texture); delete fbo; } diff --git a/gfx_es2/fbo.h b/gfx_es2/fbo.h index 70e4e9279..9fd942617 100644 --- a/gfx_es2/fbo.h +++ b/gfx_es2/fbo.h @@ -36,6 +36,8 @@ void fbo_bind_as_render_target(FBO *fbo); void fbo_bind_color_as_texture(FBO *fbo, int color); void fbo_bind_for_read(FBO *fbo); void fbo_unbind(); +void fbo_unbind_render_target(); +void fbo_unbind_read(); void fbo_destroy(FBO *fbo); void fbo_get_dimensions(FBO *fbo, int *w, int *h);