more efficient FBO handling

This commit is contained in:
Andrei Alexeyev 2018-01-03 16:38:42 +02:00
parent a5ebcd692c
commit f8cf13bdf3
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
9 changed files with 107 additions and 91 deletions

View file

@ -12,7 +12,7 @@
#include "global.h"
#include "util.h"
void init_fbo(FBO *fbo, float scale, int type) {
static void init_fbo(FBO *fbo, float scale, int type) {
glGenTextures(1, &fbo->tex);
glBindTexture(GL_TEXTURE_2D, fbo->tex);
@ -45,10 +45,17 @@ void init_fbo(FBO *fbo, float scale, int type) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,fbo->depth, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void reinit_fbo(FBO *fbo, float scale, int type) {
static void delete_fbo(FBO *fbo) {
glDeleteFramebuffers(1, &fbo->fbo);
glDeleteTextures(1, &fbo->depth);
glDeleteTextures(1, &fbo->tex);
}
static void reinit_fbo(FBO *fbo, float scale, int type) {
if(!fbo->scale) {
// fbo was never initialized
init_fbo(fbo, scale, type);
@ -61,10 +68,27 @@ void reinit_fbo(FBO *fbo, float scale, int type) {
}
}
void delete_fbo(FBO *fbo) {
glDeleteFramebuffers(1, &fbo->fbo);
glDeleteTextures(1, &fbo->depth);
glDeleteTextures(1, &fbo->tex);
static void swap_fbos(FBO **fbo1, FBO **fbo2) {
FBO *temp = *fbo1;
*fbo1 = *fbo2;
*fbo2 = temp;
}
void init_fbo_pair(FBOPair *pair, float scale, int type) {
pair->front = pair->_fbopair_private.array + FBO_FRONT;
pair->back = pair->_fbopair_private.array + FBO_BACK;
reinit_fbo(pair->front, scale, type);
reinit_fbo(pair->back, scale, type);
}
void delete_fbo_pair(FBOPair *pair) {
delete_fbo(pair->front);
delete_fbo(pair->back);
}
void swap_fbo_pair(FBOPair *pair) {
swap_fbos(&pair->front, &pair->back);
}
void draw_fbo(FBO *fbo) {
@ -96,9 +120,3 @@ void draw_fbo_viewport(FBO *fbo) {
set_ortho_ex(VIEWPORT_W,VIEWPORT_H);
draw_fbo(fbo);
}
void swap_fbos(FBO **fbo1, FBO **fbo2) {
FBO *temp = *fbo1;
*fbo1 = *fbo2;
*fbo2 = temp;
}

View file

@ -11,7 +11,7 @@
#include "taiseigl.h"
typedef struct {
typedef struct FBO {
GLuint fbo;
GLuint tex;
GLuint depth;
@ -20,9 +20,29 @@ typedef struct {
float scale;
} FBO;
void init_fbo(FBO *fbo, float scale, int type);
void reinit_fbo(FBO *fbo, float scale, int type);
#define FBO_FRONT 0
#define FBO_BACK 1
typedef struct FBOPair {
/*
* Rule of thumb:
* 1. Bind back buffer;
* 2. Draw front buffer;
* 3. Call swap_fbo_pair;
* 4. Rinse, repeat.
*/
FBO *front;
FBO *back;
struct {
FBO array[2];
} _fbopair_private;
} FBOPair;
void init_fbo_pair(FBOPair *pair, float scale, int type);
void delete_fbo_pair(FBOPair *pair);
void swap_fbo_pair(FBOPair *pair);
void draw_fbo(FBO *fbo);
void draw_fbo_viewport(FBO *fbo);
void delete_fbo(FBO *fbo);
void swap_fbos(FBO **fbo1, FBO **fbo2);

View file

@ -247,7 +247,7 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
glUniform1f(u_clr_phase, -1.5 * t/M_PI);
glUniform1f(u_clr_freq, 10.0);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.rgba[0].fbo);
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo_pairs.rgba.front->fbo);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0, 0, 0, 1);
@ -261,10 +261,10 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
}
glBlendEquation(GL_FUNC_ADD);
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo_pairs.fg.back->fbo);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(0);
draw_fbo_viewport(&resources.fbo.rgba[0]);
draw_fbo_viewport(resources.fbo_pairs.rgba.front);
glUseProgram(shader->prog);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

View file

@ -149,33 +149,30 @@ void postprocess_unload(PostprocessShader **list) {
list_foreach(list, delete_shader, NULL);
}
void postprocess(PostprocessShader *ppshaders, FBO **primfbo, FBO **auxfbo, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw) {
void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw) {
if(!ppshaders) {
return;
}
swap_fbos(primfbo, auxfbo);
for(PostprocessShader *pps = ppshaders; pps; pps = pps->next) {
Shader *s = pps->shader;
glBindFramebuffer(GL_FRAMEBUFFER, (*primfbo)->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbos->back->fbo);
glUseProgram(s->prog);
if(prepare) {
prepare(*primfbo, s);
prepare(fbos->back, s);
}
for(PostprocessShaderUniform *u = pps->uniforms; u; u = u->next) {
u->func(u->loc, u->amount, u->values.v);
}
swap_fbos(primfbo, auxfbo);
draw(*primfbo);
glUseProgram(0);
draw(fbos->front);
swap_fbo_pair(fbos);
}
swap_fbos(primfbo, auxfbo);
glUseProgram(0);
}
/*

View file

@ -58,7 +58,7 @@ char* postprocess_path(const char *path);
PostprocessShader* postprocess_load(const char *path, unsigned int flags);
void postprocess_unload(PostprocessShader **list);
void postprocess(PostprocessShader *ppshaders, FBO **primfbo, FBO **auxfbo, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw);
void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw);
/*
* Glue for resources api

View file

@ -477,12 +477,9 @@ void free_resources(bool all) {
delete_vbo(&_vbo);
postprocess_unload(&resources.stage_postprocess);
delete_fbo(&resources.fbo.bg[0]);
delete_fbo(&resources.fbo.bg[1]);
delete_fbo(&resources.fbo.fg[0]);
delete_fbo(&resources.fbo.fg[1]);
delete_fbo(&resources.fbo.rgba[0]);
delete_fbo(&resources.fbo.rgba[1]);
delete_fbo_pair(&resources.fbo_pairs.bg);
delete_fbo_pair(&resources.fbo_pairs.fg);
delete_fbo_pair(&resources.fbo_pairs.rgba);
if(!getenvint("TAISEI_NOASYNC", 0)) {
events_unregister_handler(resource_asyncload_handler);

View file

@ -102,10 +102,10 @@ typedef struct Resources {
PostprocessShader *stage_postprocess;
struct {
FBO bg[2];
FBO fg[2];
FBO rgba[2]; // XXX: do we actually need 2 RGBA FBOs?
} fbo;
FBOPair bg;
FBOPair fg;
FBOPair rgba;
} fbo_pairs;
} Resources;
extern Resources resources;

View file

@ -75,15 +75,15 @@ void stage_draw_preload(void) {
}
}
static void apply_shader_rules(ShaderRule *shaderrules, FBO **fbo0, FBO **fbo1) {
static void apply_shader_rules(ShaderRule *shaderrules, FBOPair *fbos) {
if(!shaderrules) {
return;
}
for(ShaderRule *rule = shaderrules; *rule; ++rule) {
glBindFramebuffer(GL_FRAMEBUFFER, (*fbo1)->fbo);
(*rule)(*fbo0);
swap_fbos(fbo0, fbo1);
glBindFramebuffer(GL_FRAMEBUFFER, fbos->back->fbo);
(*rule)(fbos->front);
swap_fbo_pair(fbos);
}
return;
@ -155,29 +155,24 @@ static void draw_spellbg(int t) {
glPopMatrix();
}
static void apply_bg_shaders(ShaderRule *shaderrules, FBO **fbo0, FBO **fbo1) {
static void apply_bg_shaders(ShaderRule *shaderrules, FBOPair *fbos) {
Boss *b = global.boss;
if(b && b->current && b->current->draw_rule) {
int t = global.frames - b->current->starttime;
FBO *fbo0_orig = *fbo0;
if(t < 4*ATTACK_START_DELAY || b->current->endtime) {
apply_shader_rules(shaderrules, fbo0, fbo1);
apply_shader_rules(shaderrules, fbos);
}
if(*fbo0 == fbo0_orig) {
glBindFramebuffer(GL_FRAMEBUFFER, (*fbo1)->fbo);
draw_fbo_viewport(*fbo0);
swap_fbos(fbo0, fbo1);
}
glBindFramebuffer(GL_FRAMEBUFFER, (*fbo1)->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbos->back->fbo);
draw_fbo_viewport(fbos->front);
draw_spellbg(t);
swap_fbo_pair(fbos);
glBindFramebuffer(GL_FRAMEBUFFER, fbos->back->fbo);
complex pos = b->pos;
float ratio = (float)VIEWPORT_H/VIEWPORT_W;
glBindFramebuffer(GL_FRAMEBUFFER, (*fbo0)->fbo);
if(t<ATTACK_START_DELAY) {
Shader *shader = get_shader("spellcard_intro");
glUseProgram(shader->prog);
@ -213,11 +208,12 @@ static void apply_bg_shaders(ShaderRule *shaderrules, FBO **fbo0, FBO **fbo1) {
glUseProgram(0);
}
draw_fbo_viewport(*fbo1);
draw_fbo_viewport(fbos->front);
swap_fbo_pair(fbos);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(0);
} else {
apply_shader_rules(shaderrules, fbo0, fbo1);
apply_shader_rules(shaderrules, fbos);
}
}
@ -260,9 +256,9 @@ static void apply_zoom_shader(void) {
}
}
static FBO* stage_render_bg(StageInfo *stage) {
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[0].fbo);
float scale = resources.fbo.bg[0].scale;
static void stage_render_bg(StageInfo *stage) {
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo_pairs.bg.back->fbo);
float scale = resources.fbo_pairs.bg.back->scale;
glViewport(0, 0, scale*VIEWPORT_W, scale*VIEWPORT_H);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -272,11 +268,9 @@ static FBO* stage_render_bg(StageInfo *stage) {
stage->procs->draw();
glPopMatrix();
FBO *fbo0 = resources.fbo.bg;
FBO *fbo1 = resources.fbo.bg + 1;
apply_bg_shaders(stage->procs->shader_rules, &fbo0, &fbo1);
return fbo0;
swap_fbo_pair(&resources.fbo_pairs.bg);
apply_bg_shaders(stage->procs->shader_rules, &resources.fbo_pairs.bg);
return;
}
static void stage_draw_objects(void) {
@ -335,7 +329,7 @@ void stage_draw_foreground(void) {
global.shake_view = global.shake_view_fade = 0;
}
}
draw_fbo(&resources.fbo.fg[0]);
draw_fbo(resources.fbo_pairs.fg.front);
glPopMatrix();
set_ortho();
}
@ -348,16 +342,15 @@ void stage_draw_scene(StageInfo *stage) {
#endif
bool draw_bg = !config_get_int(CONFIG_NO_STAGEBG) && !key_nobg;
FBO *fbg = NULL;
if(draw_bg) {
// render the 3D background
fbg = stage_render_bg(stage);
stage_render_bg(stage);
}
// switch to foreground FBO
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
float scale = resources.fbo.fg[0].scale;
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo_pairs.fg.back->fbo);
float scale = resources.fbo_pairs.fg.back->scale;
glViewport(0, 0, scale*VIEWPORT_W, scale*VIEWPORT_H);
set_ortho_ex(VIEWPORT_W,VIEWPORT_H);
@ -368,7 +361,7 @@ void stage_draw_scene(StageInfo *stage) {
}
// draw the 3D background
draw_fbo(fbg);
draw_fbo(resources.fbo_pairs.bg.front);
// disable boss background distortion
glUseProgram(0);
@ -382,35 +375,29 @@ void stage_draw_scene(StageInfo *stage) {
}
// draw the 2D objects
set_ortho_ex(VIEWPORT_W,VIEWPORT_H);
set_ortho_ex(VIEWPORT_W, VIEWPORT_H);
stage_draw_objects();
// apply postprocessing shaders
FBO *fbo0 = resources.fbo.fg, *fbo1 = resources.fbo.fg+1;
// everything drawn, now apply postprocessing
swap_fbo_pair(&resources.fbo_pairs.fg);
// stage postprocessing
apply_shader_rules(global.stage->procs->postprocess_rules, &fbo0, &fbo1);
apply_shader_rules(global.stage->procs->postprocess_rules, &resources.fbo_pairs.fg);
// bomb effects shader if present and player bombing
if(global.frames - global.plr.recovery < 0 && global.plr.mode->procs.bomb_shader) {
ShaderRule rules[] = {global.plr.mode->procs.bomb_shader,0};
apply_shader_rules(rules,&fbo0,&fbo1);
apply_shader_rules(rules, &resources.fbo_pairs.fg);
}
// custom postprocessing
postprocess(
resources.stage_postprocess,
&fbo0,
&fbo1,
&resources.fbo_pairs.fg,
postprocess_prepare,
draw_fbo_viewport
);
// update the primary foreground FBO if needed
if(fbo0 != resources.fbo.fg) {
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
draw_fbo_viewport(fbo0);
}
// switch to main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
video_set_viewport();

View file

@ -176,12 +176,9 @@ static void video_update_quality(void) {
log_debug("q:%f, fg:%f, bg:%f, text:%f", q, fg, bg, text);
reinit_fbo(&resources.fbo.bg[0], bg, GL_RGB);
reinit_fbo(&resources.fbo.bg[1], bg, GL_RGB);
reinit_fbo(&resources.fbo.fg[0], fg, GL_RGB);
reinit_fbo(&resources.fbo.fg[1], fg, GL_RGB);
reinit_fbo(&resources.fbo.rgba[0], fg, GL_RGBA);
reinit_fbo(&resources.fbo.rgba[1], fg, GL_RGBA);
init_fbo_pair(&resources.fbo_pairs.bg, bg, GL_RGB);
init_fbo_pair(&resources.fbo_pairs.fg, fg, GL_RGB);
init_fbo_pair(&resources.fbo_pairs.rgba, fg, GL_RGBA);
reload_fonts(text);
@ -546,7 +543,7 @@ void video_init(void) {
bool fullscreen_available = false;
memset(&video, 0, sizeof(video));
memset(&resources.fbo, 0, sizeof(resources.fbo));
memset(&resources.fbo_pairs, 0, sizeof(resources.fbo_pairs));
video_init_sdl();
log_info("Using driver '%s'", SDL_GetCurrentVideoDriver());