New system to manage auto-resized framebuffers
This commit is contained in:
parent
5d535bb93c
commit
2e9904e83c
15 changed files with 430 additions and 218 deletions
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#define LIST_ALIGN alignas(alignof(max_align_t))
|
||||
#define LIST_ALIGN alignas(16)
|
||||
|
||||
typedef struct ListInterface ListInterface;
|
||||
typedef struct List List;
|
||||
|
|
|
@ -855,6 +855,7 @@ void stage_enter(StageInfo *stage, CallChain next) {
|
|||
|
||||
ent_init();
|
||||
stage_objpools_alloc();
|
||||
stage_draw_pre_init();
|
||||
stage_preload();
|
||||
stage_draw_init();
|
||||
|
||||
|
|
195
src/stagedraw.c
195
src/stagedraw.c
|
@ -14,6 +14,7 @@
|
|||
#include "video.h"
|
||||
#include "resource/postprocess.h"
|
||||
#include "entity.h"
|
||||
#include "util/fbmgr.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define GRAPHS_DEFAULT 1
|
||||
|
@ -23,17 +24,6 @@
|
|||
#define OBJPOOLSTATS_DEFAULT 0
|
||||
#endif
|
||||
|
||||
typedef struct CustomFramebuffer {
|
||||
LIST_INTERFACE(struct CustomFramebuffer);
|
||||
Framebuffer *fb;
|
||||
|
||||
struct {
|
||||
float worst, best;
|
||||
} scale;
|
||||
|
||||
StageFBPair scaling_base;
|
||||
} CustomFramebuffer;
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
ShaderProgram *shader;
|
||||
|
@ -64,11 +54,12 @@ static struct {
|
|||
PostprocessShader *viewport_pp;
|
||||
FBPair fb_pairs[NUM_FBPAIRS];
|
||||
FBPair powersurge_fbpair;
|
||||
CustomFramebuffer *custom_fbs;
|
||||
|
||||
bool framerate_graphs;
|
||||
bool objpool_stats;
|
||||
|
||||
ManagedFramebufferGroup *mfb_group;
|
||||
|
||||
#ifdef DEBUG
|
||||
Sprite dummy;
|
||||
#endif
|
||||
|
@ -125,28 +116,22 @@ static void set_fb_size(StageFBPair fb_id, int *w, int *h, float scale_worst, fl
|
|||
*h = round(VIEWPORT_H * scale);
|
||||
}
|
||||
|
||||
static inline void set_custom_fb_size(CustomFramebuffer *cfb, int *w, int *h) {
|
||||
set_fb_size(cfb->scaling_base, w, h, cfb->scale.worst, cfb->scale.best);
|
||||
typedef struct StageFramebufferResizeParams {
|
||||
struct { float worst, best; } scale;
|
||||
StageFBPair scaling_base;
|
||||
int refs;
|
||||
} StageFramebufferResizeParams;
|
||||
|
||||
static void stage_framebuffer_resize_strategy(void *userdata, IntExtent *out_dimensions, FloatRect *out_viewport) {
|
||||
StageFramebufferResizeParams *rp = userdata;
|
||||
set_fb_size(rp->scaling_base, &out_dimensions->w, &out_dimensions->h, rp->scale.worst, rp->scale.best);
|
||||
*out_viewport = (FloatRect) { 0, 0, out_dimensions->w, out_dimensions->h };
|
||||
}
|
||||
|
||||
static void update_fb_size(StageFBPair fb_id) {
|
||||
int w, h;
|
||||
set_fb_size(fb_id, &w, &h, 1, 1);
|
||||
fbpair_resize_all(stagedraw.fb_pairs + fb_id, w, h);
|
||||
fbpair_viewport(stagedraw.fb_pairs + fb_id, 0, 0, w, h);
|
||||
|
||||
if(fb_id != FBPAIR_FG_AUX && fb_id != FBPAIR_BG_AUX) {
|
||||
for(CustomFramebuffer *cfb = stagedraw.custom_fbs; cfb; cfb = cfb->next) {
|
||||
if(cfb->scaling_base == fb_id) {
|
||||
set_custom_fb_size(cfb, &w, &h);
|
||||
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
fbutil_resize_attachment(cfb->fb, i, w, h);
|
||||
}
|
||||
|
||||
r_framebuffer_viewport(cfb->fb, 0, 0, w, h);
|
||||
}
|
||||
}
|
||||
static void stage_framebuffer_resize_strategy_cleanup(void *userdata) {
|
||||
StageFramebufferResizeParams *rp = userdata;
|
||||
if(--rp->refs <= 0) {
|
||||
free(rp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,31 +141,6 @@ static bool stage_draw_event(SDL_Event *e, void *arg) {
|
|||
}
|
||||
|
||||
switch(TAISEI_EVENT(e->type)) {
|
||||
case TE_VIDEO_MODE_CHANGED: {
|
||||
for(uint i = 0; i < NUM_FBPAIRS; ++i) {
|
||||
update_fb_size(i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TE_CONFIG_UPDATED: {
|
||||
switch(e->user.code) {
|
||||
case CONFIG_POSTPROCESS:
|
||||
case CONFIG_BG_QUALITY:
|
||||
update_fb_size(FBPAIR_BG);
|
||||
update_fb_size(FBPAIR_BG_AUX);
|
||||
// fallthrough
|
||||
|
||||
case CONFIG_FG_QUALITY:
|
||||
update_fb_size(FBPAIR_FG);
|
||||
update_fb_size(FBPAIR_FG_AUX);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TE_FRAME: {
|
||||
fapproach_p(&stagedraw.clear_screen.alpha, stagedraw.clear_screen.target_alpha, 0.01);
|
||||
break;
|
||||
|
@ -190,11 +150,26 @@ static bool stage_draw_event(SDL_Event *e, void *arg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static void stage_draw_fbpair_create(
|
||||
FBPair *pair,
|
||||
int num_attachments,
|
||||
FBAttachmentConfig *attachments,
|
||||
const StageFramebufferResizeParams *resize_params,
|
||||
const char *name
|
||||
) {
|
||||
StageFramebufferResizeParams *rp = memdup(resize_params, sizeof(*resize_params));
|
||||
rp->refs = 2;
|
||||
|
||||
FramebufferConfig fbconf = { 0 };
|
||||
fbconf.attachments = attachments;
|
||||
fbconf.num_attachments = num_attachments;
|
||||
fbconf.resize_strategy.resize_func = stage_framebuffer_resize_strategy;
|
||||
fbconf.resize_strategy.userdata = rp;
|
||||
fbconf.resize_strategy.cleanup_func = stage_framebuffer_resize_strategy_cleanup;
|
||||
fbmgr_group_fbpair_create(stagedraw.mfb_group, name, &fbconf, pair);
|
||||
}
|
||||
|
||||
static void stage_draw_setup_framebuffers(void) {
|
||||
int fg_width, fg_height;
|
||||
int bg_width, bg_height;
|
||||
int fga_width, fga_height;
|
||||
int bga_width, bga_height;
|
||||
FBAttachmentConfig a[2], *a_color, *a_depth;
|
||||
memset(a, 0, sizeof(a));
|
||||
|
||||
|
@ -204,10 +179,10 @@ static void stage_draw_setup_framebuffers(void) {
|
|||
a_color->attachment = FRAMEBUFFER_ATTACH_COLOR0;
|
||||
a_depth->attachment = FRAMEBUFFER_ATTACH_DEPTH;
|
||||
|
||||
set_fb_size(FBPAIR_FG, &fg_width, &fg_height, 1, 1);
|
||||
set_fb_size(FBPAIR_FG_AUX, &fga_width, &fga_height, 1, 1);
|
||||
set_fb_size(FBPAIR_BG, &bg_width, &bg_height, 1, 1);
|
||||
set_fb_size(FBPAIR_BG_AUX, &bga_width, &bga_height, 1, 1);
|
||||
StageFramebufferResizeParams rp_fg = { .scaling_base = FBPAIR_FG, .scale.best = 1, .scale.worst = 1 };
|
||||
StageFramebufferResizeParams rp_fg_aux = { .scaling_base = FBPAIR_FG_AUX, .scale.best = 1, .scale.worst = 1 };
|
||||
StageFramebufferResizeParams rp_bg = { .scaling_base = FBPAIR_BG, .scale.best = 1, .scale.worst = 1 };
|
||||
StageFramebufferResizeParams rp_bg_aux = { .scaling_base = FBPAIR_BG_AUX, .scale.best = 1, .scale.worst = 1 };
|
||||
|
||||
// Set up some parameters shared by all attachments
|
||||
TextureParams tex_common = {
|
||||
|
@ -220,36 +195,23 @@ static void stage_draw_setup_framebuffers(void) {
|
|||
memcpy(&a_color->tex_params, &tex_common, sizeof(tex_common));
|
||||
memcpy(&a_depth->tex_params, &tex_common, sizeof(tex_common));
|
||||
|
||||
a_depth->tex_params.type = TEX_TYPE_DEPTH;
|
||||
|
||||
// Foreground: 1 RGB texture per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGB_16;
|
||||
a_color->tex_params.width = fg_width;
|
||||
a_color->tex_params.height = fg_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_FG, 1, a, "Stage FG");
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_FG, 0, 0, fg_width, fg_height);
|
||||
stage_draw_fbpair_create(stagedraw.fb_pairs + FBPAIR_FG, 1, a, &rp_fg, "Stage FG");
|
||||
|
||||
// Foreground auxiliary: 1 RGBA texture per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGBA;
|
||||
a_color->tex_params.width = fga_width;
|
||||
a_color->tex_params.height = fga_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_FG_AUX, 1, a, "Stage FG AUX");
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_FG_AUX, 0, 0, fga_width, fga_height);
|
||||
a_color->tex_params.type = TEX_TYPE_RGBA_8;
|
||||
stage_draw_fbpair_create(stagedraw.fb_pairs + FBPAIR_FG_AUX, 1, a, &rp_fg_aux, "Stage FG AUX");
|
||||
|
||||
// Background: 1 RGB texture + depth per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGB;
|
||||
a_color->tex_params.width = bg_width;
|
||||
a_color->tex_params.height = bg_height;
|
||||
a_depth->tex_params.type = TEX_TYPE_DEPTH;
|
||||
a_depth->tex_params.width = bg_width;
|
||||
a_depth->tex_params.height = bg_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_BG, 2, a, "Stage BG");
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_BG, 0, 0, bg_width, bg_height);
|
||||
a_color->tex_params.type = TEX_TYPE_RGB_8;
|
||||
stage_draw_fbpair_create(stagedraw.fb_pairs + FBPAIR_BG, 2, a, &rp_bg, "Stage BG");
|
||||
|
||||
// Background auxiliary: 1 RGBA texture per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGBA_8;
|
||||
a_color->tex_params.width = bga_width;
|
||||
a_color->tex_params.height = bga_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_BG_AUX, 1, a, "Stage BG AUX");
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_BG_AUX, 0, 0, bga_width, bga_height);
|
||||
stage_draw_fbpair_create(stagedraw.fb_pairs + FBPAIR_BG_AUX, 1, a, &rp_bg_aux, "Stage BG AUX");
|
||||
|
||||
// CAUTION: should be at least 16-bit, lest the feedback shader do an oopsie!
|
||||
a_color->tex_params.type = TEX_TYPE_RGBA_16;
|
||||
|
@ -257,31 +219,26 @@ static void stage_draw_setup_framebuffers(void) {
|
|||
stagedraw.powersurge_fbpair.back = stage_add_background_framebuffer("Powersurge effect FB 2", 0.125, 0.25, 1, a);
|
||||
}
|
||||
|
||||
static Framebuffer* add_custom_framebuffer(const char *label, StageFBPair fbtype, float scale_worst, float scale_best, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
CustomFramebuffer *cfb = calloc(1, sizeof(*cfb));
|
||||
list_push(&stagedraw.custom_fbs, cfb);
|
||||
static Framebuffer *add_custom_framebuffer(
|
||||
const char *label,
|
||||
StageFBPair fbtype,
|
||||
float scale_worst,
|
||||
float scale_best,
|
||||
uint num_attachments,
|
||||
FBAttachmentConfig attachments[num_attachments]
|
||||
) {
|
||||
StageFramebufferResizeParams rp = { 0 };
|
||||
rp.scaling_base = fbtype;
|
||||
rp.scale.worst = scale_worst;
|
||||
rp.scale.best = scale_best;
|
||||
|
||||
FBAttachmentConfig cfg[num_attachments];
|
||||
memcpy(cfg, attachments, sizeof(cfg));
|
||||
|
||||
int width, height;
|
||||
cfb->scale.worst = scale_worst;
|
||||
cfb->scale.best = scale_best;
|
||||
cfb->scaling_base = fbtype;
|
||||
set_custom_fb_size(cfb, &width, &height);
|
||||
|
||||
for(uint i = 0; i < num_attachments; ++i) {
|
||||
cfg[i].tex_params.width = width;
|
||||
cfg[i].tex_params.height = height;
|
||||
}
|
||||
|
||||
cfb->fb = r_framebuffer_create();
|
||||
r_framebuffer_set_debug_label(cfb->fb, label);
|
||||
fbutil_create_attachments(cfb->fb, num_attachments, cfg);
|
||||
r_framebuffer_viewport(cfb->fb, 0, 0, width, height);
|
||||
r_framebuffer_clear(cfb->fb, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
return cfb->fb;
|
||||
FramebufferConfig fbconf = { 0 };
|
||||
fbconf.attachments = attachments;
|
||||
fbconf.num_attachments = num_attachments;
|
||||
fbconf.resize_strategy.resize_func = stage_framebuffer_resize_strategy;
|
||||
fbconf.resize_strategy.userdata = memdup(&rp, sizeof(rp));
|
||||
fbconf.resize_strategy.cleanup_func = stage_framebuffer_resize_strategy_cleanup;
|
||||
return fbmgr_group_framebuffer_create(stagedraw.mfb_group, label, &fbconf);
|
||||
}
|
||||
|
||||
Framebuffer* stage_add_foreground_framebuffer(const char *label, float scale_worst, float scale_best, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
|
@ -293,19 +250,13 @@ Framebuffer* stage_add_background_framebuffer(const char *label, float scale_wor
|
|||
}
|
||||
|
||||
static void stage_draw_destroy_framebuffers(void) {
|
||||
for(uint i = 0; i < NUM_FBPAIRS; ++i) {
|
||||
fbpair_destroy(stagedraw.fb_pairs + i);
|
||||
}
|
||||
|
||||
for(CustomFramebuffer *cfb = stagedraw.custom_fbs, *next; cfb; cfb = next) {
|
||||
next = cfb->next;
|
||||
fbutil_destroy_attachments(cfb->fb);
|
||||
r_framebuffer_destroy(cfb->fb);
|
||||
free(list_unlink(&stagedraw.custom_fbs, cfb));
|
||||
}
|
||||
fbmgr_group_destroy(stagedraw.mfb_group);
|
||||
stagedraw.mfb_group = NULL;
|
||||
}
|
||||
|
||||
void stage_draw_init(void) {
|
||||
void stage_draw_pre_init(void) {
|
||||
stagedraw.mfb_group = fbmgr_group_create();
|
||||
|
||||
preload_resources(RES_POSTPROCESS, RESF_OPTIONAL,
|
||||
"viewport",
|
||||
NULL);
|
||||
|
@ -364,7 +315,9 @@ void stage_draw_init(void) {
|
|||
"monotiny",
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void stage_draw_init(void) {
|
||||
stagedraw.viewport_pp = get_resource_data(RES_POSTPROCESS, "viewport", RESF_OPTIONAL);
|
||||
stagedraw.hud_text.shader = r_shader_get("text_hud");
|
||||
stagedraw.hud_text.font = get_font("standard");
|
||||
|
|
|
@ -22,6 +22,7 @@ typedef enum StageFBPair {
|
|||
NUM_FBPAIRS,
|
||||
} StageFBPair;
|
||||
|
||||
void stage_draw_pre_init(void);
|
||||
void stage_draw_init(void);
|
||||
void stage_draw_shutdown(void);
|
||||
void stage_draw_hud(void);
|
||||
|
|
176
src/util/fbmgr.c
Normal file
176
src/util/fbmgr.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "fbmgr.h"
|
||||
#include "list.h"
|
||||
#include "events.h"
|
||||
#include "config.h"
|
||||
|
||||
typedef struct ManagedFramebufferData ManagedFramebufferData;
|
||||
|
||||
struct ManagedFramebufferData {
|
||||
LIST_INTERFACE(ManagedFramebufferData);
|
||||
List group_node;
|
||||
FramebufferResizeStrategy resize_strategy;
|
||||
};
|
||||
|
||||
struct ManagedFramebufferGroup {
|
||||
List *members;
|
||||
};
|
||||
|
||||
#define GET_MFB(mfb_data) CASTPTR_ASSUME_ALIGNED((char*)(mfb_data) - offsetof(ManagedFramebuffer, data), ManagedFramebuffer)
|
||||
#define GET_DATA(mfb) CASTPTR_ASSUME_ALIGNED((mfb)->data, ManagedFramebufferData)
|
||||
#define GROUPNODE_TO_DATA(gn) CASTPTR_ASSUME_ALIGNED((char*)(gn) - offsetof(ManagedFramebufferData, group_node), ManagedFramebufferData)
|
||||
|
||||
static ManagedFramebufferData *framebuffers;
|
||||
|
||||
static inline void fbmgr_framebuffer_get_metrics(ManagedFramebuffer *mfb, IntExtent *fb_size, FloatRect *fb_viewport) {
|
||||
ManagedFramebufferData *mfb_data = GET_DATA(mfb);
|
||||
mfb_data->resize_strategy.resize_func(mfb_data->resize_strategy.userdata, fb_size, fb_viewport);
|
||||
}
|
||||
|
||||
static void fbmgr_framebuffer_update(ManagedFramebuffer *mfb) {
|
||||
IntExtent fb_size;
|
||||
FloatRect fb_viewport;
|
||||
Framebuffer *fb = mfb->fb;
|
||||
|
||||
fbmgr_framebuffer_get_metrics(mfb, &fb_size, &fb_viewport);
|
||||
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
fbutil_resize_attachment(fb, i, fb_size.w, fb_size.h);
|
||||
}
|
||||
|
||||
r_framebuffer_viewport_rect(fb, fb_viewport);
|
||||
}
|
||||
|
||||
static void fbmgr_framebuffer_update_all(void) {
|
||||
for(ManagedFramebufferData *d = framebuffers; d; d = d->next) {
|
||||
fbmgr_framebuffer_update(GET_MFB(d));
|
||||
}
|
||||
}
|
||||
|
||||
ManagedFramebuffer *fbmgr_framebuffer_create(const char *name, const FramebufferConfig *cfg) {
|
||||
assert(cfg->resize_strategy.resize_func != NULL);
|
||||
assert(cfg->attachments != NULL);
|
||||
assert(cfg->num_attachments >= 1);
|
||||
|
||||
ManagedFramebuffer *mfb = calloc(1, sizeof(*mfb) + sizeof(ManagedFramebufferData));
|
||||
ManagedFramebufferData *data = GET_DATA(mfb);
|
||||
data->resize_strategy = cfg->resize_strategy;
|
||||
mfb->fb = r_framebuffer_create();
|
||||
r_framebuffer_set_debug_label(mfb->fb, name);
|
||||
|
||||
FBAttachmentConfig ac[cfg->num_attachments];
|
||||
memcpy(ac, cfg->attachments, sizeof(ac));
|
||||
|
||||
IntExtent fb_size;
|
||||
FloatRect fb_viewport;
|
||||
fbmgr_framebuffer_get_metrics(mfb, &fb_size, &fb_viewport);
|
||||
|
||||
for(int i = 0; i < cfg->num_attachments; ++i) {
|
||||
ac[i].tex_params.width = fb_size.w;
|
||||
ac[i].tex_params.height = fb_size.h;
|
||||
}
|
||||
|
||||
fbutil_create_attachments(mfb->fb, cfg->num_attachments, ac);
|
||||
r_framebuffer_viewport_rect(mfb->fb, fb_viewport);
|
||||
r_framebuffer_clear(mfb->fb, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
list_push(&framebuffers, data);
|
||||
return mfb;
|
||||
}
|
||||
|
||||
Framebuffer *fbmgr_framebuffer_disown(ManagedFramebuffer *mfb) {
|
||||
for(ManagedFramebufferData *d = framebuffers; d; d = d->next) {
|
||||
ManagedFramebuffer *m = GET_MFB(d);
|
||||
|
||||
if(m == mfb) {
|
||||
if(d->resize_strategy.cleanup_func) {
|
||||
d->resize_strategy.cleanup_func(d->resize_strategy.userdata);
|
||||
}
|
||||
|
||||
Framebuffer *fb = m->fb;
|
||||
list_unlink(&framebuffers, d);
|
||||
free(m);
|
||||
return fb;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
void fbmgr_framebuffer_destroy(ManagedFramebuffer *mfb) {
|
||||
Framebuffer *fb = fbmgr_framebuffer_disown(mfb);
|
||||
fbutil_destroy_attachments(fb);
|
||||
r_framebuffer_destroy(fb);
|
||||
}
|
||||
|
||||
static bool fbmgr_event(SDL_Event *evt, void *arg) {
|
||||
switch(TAISEI_EVENT(evt->type)) {
|
||||
case TE_VIDEO_MODE_CHANGED:
|
||||
fbmgr_framebuffer_update_all();
|
||||
break;
|
||||
|
||||
case TE_CONFIG_UPDATED:
|
||||
switch(evt->user.code) {
|
||||
case CONFIG_POSTPROCESS:
|
||||
case CONFIG_BG_QUALITY:
|
||||
case CONFIG_FG_QUALITY:
|
||||
fbmgr_framebuffer_update_all();
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void fbmgr_init(void) {
|
||||
events_register_handler(&(EventHandler) {
|
||||
fbmgr_event, NULL, EPRIO_SYSTEM,
|
||||
});
|
||||
}
|
||||
|
||||
void fbmgr_shutdown(void) {
|
||||
events_unregister_handler(fbmgr_event);
|
||||
}
|
||||
|
||||
ManagedFramebufferGroup *fbmgr_group_create(void) {
|
||||
return calloc(1, sizeof(ManagedFramebufferGroup));
|
||||
}
|
||||
|
||||
void fbmgr_group_destroy(ManagedFramebufferGroup *group) {
|
||||
for(List *n = group->members, *next; n; n = next) {
|
||||
next = n->next;
|
||||
ManagedFramebuffer *mfb = GET_MFB(GROUPNODE_TO_DATA(n));
|
||||
fbmgr_framebuffer_destroy(mfb);
|
||||
}
|
||||
|
||||
free(group);
|
||||
}
|
||||
|
||||
Framebuffer *fbmgr_group_framebuffer_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg) {
|
||||
ManagedFramebuffer *mfb = fbmgr_framebuffer_create(name, cfg);
|
||||
ManagedFramebufferData *mfb_data = GET_DATA(mfb);
|
||||
list_push(&group->members, &mfb_data->group_node);
|
||||
return mfb->fb;
|
||||
}
|
||||
|
||||
void fbmgr_group_fbpair_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg, FBPair *fbpair) {
|
||||
char buf[R_DEBUG_LABEL_SIZE];
|
||||
snprintf(buf, sizeof(buf), "%s FB 1", name);
|
||||
fbpair->front = fbmgr_group_framebuffer_create(group, buf, cfg);
|
||||
snprintf(buf, sizeof(buf), "%s FB 2", name);
|
||||
fbpair->back = fbmgr_group_framebuffer_create(group, buf, cfg);
|
||||
}
|
||||
|
63
src/util/fbmgr.h
Normal file
63
src/util/fbmgr.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_util_fbmgr_h
|
||||
#define IGUARD_util_fbmgr_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
#include "fbpair.h"
|
||||
#include "geometry.h"
|
||||
#include "list.h"
|
||||
|
||||
typedef struct FramebufferResizeStrategy {
|
||||
void (*resize_func)(void *userdata, IntExtent *out_dimensions, FloatRect *out_viewport);
|
||||
void (*cleanup_func)(void *userdata);
|
||||
void *userdata;
|
||||
} FramebufferResizeStrategy;
|
||||
|
||||
typedef struct FramebufferConfig {
|
||||
FramebufferResizeStrategy resize_strategy;
|
||||
uint num_attachments;
|
||||
FBAttachmentConfig *attachments;
|
||||
} FramebufferConfig;
|
||||
|
||||
typedef struct ManagedFramebuffer {
|
||||
Framebuffer *fb;
|
||||
LIST_ALIGN char data[];
|
||||
} ManagedFramebuffer;
|
||||
|
||||
|
||||
typedef struct ManagedFramebufferGroup ManagedFramebufferGroup;
|
||||
|
||||
void fbmgr_init(void);
|
||||
void fbmgr_shutdown(void);
|
||||
|
||||
ManagedFramebuffer *fbmgr_framebuffer_create(const char *name, const FramebufferConfig *cfg)
|
||||
attr_returns_allocated attr_nonnull(1, 2);
|
||||
|
||||
void fbmgr_framebuffer_destroy(ManagedFramebuffer *mfb)
|
||||
attr_nonnull(1);
|
||||
|
||||
Framebuffer *fbmgr_framebuffer_disown(ManagedFramebuffer *mfb)
|
||||
attr_returns_allocated attr_nonnull(1);
|
||||
|
||||
ManagedFramebufferGroup *fbmgr_group_create(void)
|
||||
attr_returns_allocated;
|
||||
|
||||
void fbmgr_group_destroy(ManagedFramebufferGroup *group)
|
||||
attr_nonnull(1);
|
||||
|
||||
Framebuffer *fbmgr_group_framebuffer_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg)
|
||||
attr_returns_allocated attr_nonnull(1, 2, 3);
|
||||
|
||||
void fbmgr_group_fbpair_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg, FBPair *fbpair)
|
||||
attr_nonnull(1, 2, 3, 4);
|
||||
|
||||
#endif // IGUARD_util_fbmgr_h
|
|
@ -11,7 +11,6 @@
|
|||
#include "fbpair.h"
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
#include "util/graphics.h"
|
||||
|
||||
static void fbpair_destroy_fb(Framebuffer *fb) {
|
||||
fbutil_destroy_attachments(fb);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
#include "fbutil.h"
|
||||
|
||||
typedef struct FBPair {
|
||||
/*
|
||||
|
@ -26,11 +26,6 @@ typedef struct FBPair {
|
|||
Framebuffer *back;
|
||||
} FBPair;
|
||||
|
||||
typedef struct FBAttachmentConfig {
|
||||
FramebufferAttachment attachment;
|
||||
TextureParams tex_params;
|
||||
} FBAttachmentConfig;
|
||||
|
||||
void fbpair_create(FBPair *pair, uint num_attachments, FBAttachmentConfig attachments[num_attachments], const char *debug_label) attr_nonnull(1, 3);
|
||||
void fbpair_resize(FBPair *pair, FramebufferAttachment attachment, uint width, uint height) attr_nonnull(1);
|
||||
void fbpair_resize_all(FBPair *pair, uint width, uint height) attr_nonnull(1);
|
||||
|
|
71
src/util/fbutil.c
Normal file
71
src/util/fbutil.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "fbutil.h"
|
||||
|
||||
static const char* attachment_name(FramebufferAttachment a) {
|
||||
static const char *map[FRAMEBUFFER_MAX_ATTACHMENTS] = {
|
||||
[FRAMEBUFFER_ATTACH_DEPTH] = "depth",
|
||||
[FRAMEBUFFER_ATTACH_COLOR0] = "color0",
|
||||
[FRAMEBUFFER_ATTACH_COLOR1] = "color1",
|
||||
[FRAMEBUFFER_ATTACH_COLOR2] = "color2",
|
||||
[FRAMEBUFFER_ATTACH_COLOR3] = "color3",
|
||||
};
|
||||
|
||||
assert((uint)a < FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
return map[(uint)a];
|
||||
}
|
||||
|
||||
void fbutil_create_attachments(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
char buf[128];
|
||||
|
||||
for(uint i = 0; i < num_attachments; ++i) {
|
||||
log_debug("%i %i", attachments[i].tex_params.width, attachments[i].tex_params.height);
|
||||
Texture *tex = r_texture_create(&attachments[i].tex_params);
|
||||
snprintf(buf, sizeof(buf), "%s [%s]", r_framebuffer_get_debug_label(fb), attachment_name(attachments[i].attachment));
|
||||
r_texture_set_debug_label(tex, buf);
|
||||
r_framebuffer_attach(fb, tex, 0, attachments[i].attachment);
|
||||
}
|
||||
}
|
||||
|
||||
void fbutil_destroy_attachments(Framebuffer *fb) {
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, i);
|
||||
|
||||
if(tex != NULL) {
|
||||
r_texture_destroy(tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, attachment);
|
||||
|
||||
if(tex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint tw, th;
|
||||
r_texture_get_size(tex, 0, &tw, &th);
|
||||
|
||||
if(tw == width && th == height) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We could render a rescaled version of the old texture contents here
|
||||
|
||||
TextureParams params;
|
||||
r_texture_get_params(tex, ¶ms);
|
||||
r_texture_destroy(tex);
|
||||
params.width = width;
|
||||
params.height = height;
|
||||
params.mipmaps = 0; // FIXME
|
||||
r_framebuffer_attach(fb, r_texture_create(¶ms), 0, attachment);
|
||||
}
|
25
src/util/fbutil.h
Normal file
25
src/util/fbutil.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_util_fbutil_h
|
||||
#define IGUARD_util_fbutil_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
|
||||
typedef struct FBAttachmentConfig {
|
||||
FramebufferAttachment attachment;
|
||||
TextureParams tex_params;
|
||||
} FBAttachmentConfig;
|
||||
|
||||
void fbutil_create_attachments(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]);
|
||||
void fbutil_destroy_attachments(Framebuffer *fb);
|
||||
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height);
|
||||
|
||||
#endif // IGUARD_util_fbutil_h
|
|
@ -189,66 +189,6 @@ void draw_framebuffer_tex(Framebuffer *fb, double width, double height) {
|
|||
draw_framebuffer_attachment(fb, width, height, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
}
|
||||
|
||||
static const char* attachment_name(FramebufferAttachment a) {
|
||||
static const char *map[FRAMEBUFFER_MAX_ATTACHMENTS] = {
|
||||
[FRAMEBUFFER_ATTACH_DEPTH] = "depth",
|
||||
[FRAMEBUFFER_ATTACH_COLOR0] = "color0",
|
||||
[FRAMEBUFFER_ATTACH_COLOR1] = "color1",
|
||||
[FRAMEBUFFER_ATTACH_COLOR2] = "color2",
|
||||
[FRAMEBUFFER_ATTACH_COLOR3] = "color3",
|
||||
};
|
||||
|
||||
assert((uint)a < FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
return map[(uint)a];
|
||||
}
|
||||
|
||||
void fbutil_create_attachments(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
char buf[128];
|
||||
|
||||
for(uint i = 0; i < num_attachments; ++i) {
|
||||
log_debug("%i %i", attachments[i].tex_params.width, attachments[i].tex_params.height);
|
||||
Texture *tex = r_texture_create(&attachments[i].tex_params);
|
||||
snprintf(buf, sizeof(buf), "%s [%s]", r_framebuffer_get_debug_label(fb), attachment_name(attachments[i].attachment));
|
||||
r_texture_set_debug_label(tex, buf);
|
||||
r_framebuffer_attach(fb, tex, 0, attachments[i].attachment);
|
||||
}
|
||||
}
|
||||
|
||||
void fbutil_destroy_attachments(Framebuffer *fb) {
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, i);
|
||||
|
||||
if(tex != NULL) {
|
||||
r_texture_destroy(tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, attachment);
|
||||
|
||||
if(tex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint tw, th;
|
||||
r_texture_get_size(tex, 0, &tw, &th);
|
||||
|
||||
if(tw == width && th == height) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We could render a rescaled version of the old texture contents here
|
||||
|
||||
TextureParams params;
|
||||
r_texture_get_params(tex, ¶ms);
|
||||
r_texture_destroy(tex);
|
||||
params.width = width;
|
||||
params.height = height;
|
||||
params.mipmaps = 0; // FIXME
|
||||
r_framebuffer_attach(fb, r_texture_create(¶ms), 0, attachment);
|
||||
}
|
||||
|
||||
void render_character_portrait(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
|
||||
r_state_push();
|
||||
|
||||
|
|
|
@ -54,10 +54,6 @@ double draw_fraction(double value, Alignment a, double pos_x, double pos_y, Font
|
|||
void draw_framebuffer_tex(Framebuffer *fb, double width, double height);
|
||||
void draw_framebuffer_attachment(Framebuffer *fb, double width, double height, FramebufferAttachment attachment);
|
||||
|
||||
void fbutil_create_attachments(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]);
|
||||
void fbutil_destroy_attachments(Framebuffer *fb);
|
||||
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height);
|
||||
|
||||
void render_character_portrait(Sprite *s_base, Sprite *s_face, Sprite *s_out);
|
||||
|
||||
#endif // IGUARD_util_graphics_h
|
||||
|
|
|
@ -5,7 +5,9 @@ util_src = files(
|
|||
'assert.c',
|
||||
'crap.c',
|
||||
'env.c',
|
||||
'fbmgr.c',
|
||||
'fbpair.c',
|
||||
'fbutil.c',
|
||||
'geometry.c',
|
||||
'graphics.c',
|
||||
'io.c',
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "video.h"
|
||||
#include "renderer/api.h"
|
||||
#include "util/pngcruft.h"
|
||||
#include "util/fbmgr.h"
|
||||
#include "taskmanager.h"
|
||||
#include "video_postprocess.h"
|
||||
|
||||
|
@ -720,12 +721,14 @@ void video_init(void) {
|
|||
}
|
||||
|
||||
void video_post_init(void) {
|
||||
fbmgr_init();
|
||||
v_postprocess = video_postprocess_init();
|
||||
r_framebuffer(video_get_screen_framebuffer());
|
||||
}
|
||||
|
||||
void video_shutdown(void) {
|
||||
video_postprocess_shutdown(v_postprocess);
|
||||
fbmgr_shutdown();
|
||||
events_unregister_handler(video_handle_window_event);
|
||||
events_unregister_handler(video_handle_config_event);
|
||||
SDL_DestroyWindow(video.window);
|
||||
|
|
|
@ -8,26 +8,25 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "events.h"
|
||||
#include "log.h"
|
||||
#include "resource/postprocess.h"
|
||||
#include "util/graphics.h"
|
||||
#include "video.h"
|
||||
#include "video_postprocess.h"
|
||||
#include "util/fbmgr.h"
|
||||
|
||||
struct VideoPostProcess {
|
||||
ManagedFramebufferGroup *mfb_group;
|
||||
FBPair framebuffers;
|
||||
PostprocessShader *pp_pipeline;
|
||||
int frames;
|
||||
};
|
||||
|
||||
static bool video_postprocess_resize_event(SDL_Event *e, void *arg) {
|
||||
VideoPostProcess *vpp = arg;
|
||||
static void video_postprocess_resize_strategy(void *userdata, IntExtent *fb_size, FloatRect *fb_viewport) {
|
||||
float w, h;
|
||||
video_get_viewport_size(&w, &h);
|
||||
fbpair_resize_all(&vpp->framebuffers, w, h);
|
||||
fbpair_viewport(&vpp->framebuffers, 0, 0, w, h);
|
||||
return false;
|
||||
*fb_size = (IntExtent) { w, h };
|
||||
*fb_viewport = (FloatRect) { 0, 0, w, h };
|
||||
}
|
||||
|
||||
VideoPostProcess *video_postprocess_init(void) {
|
||||
|
@ -39,6 +38,7 @@ VideoPostProcess *video_postprocess_init(void) {
|
|||
|
||||
VideoPostProcess *vpp = calloc(1, sizeof(*vpp));
|
||||
vpp->pp_pipeline = pps;
|
||||
vpp->mfb_group = fbmgr_group_create();
|
||||
|
||||
FBAttachmentConfig a = { 0 };
|
||||
a.attachment = FRAMEBUFFER_ATTACH_COLOR0;
|
||||
|
@ -51,31 +51,18 @@ VideoPostProcess *video_postprocess_init(void) {
|
|||
a.tex_params.wrap.s = TEX_WRAP_MIRROR;
|
||||
a.tex_params.wrap.t = TEX_WRAP_MIRROR;
|
||||
|
||||
float w, h;
|
||||
video_get_viewport_size(&w, &h);
|
||||
a.tex_params.width = w;
|
||||
a.tex_params.height = h;
|
||||
|
||||
fbpair_create(&vpp->framebuffers, 1, &a, "Global postprocess");
|
||||
fbpair_viewport(&vpp->framebuffers, 0, 0, w, h);
|
||||
|
||||
r_framebuffer_clear(vpp->framebuffers.back, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
|
||||
r_framebuffer_clear(vpp->framebuffers.front, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
events_register_handler(&(EventHandler) {
|
||||
.proc = video_postprocess_resize_event,
|
||||
.priority = EPRIO_SYSTEM,
|
||||
.arg = vpp,
|
||||
.event_type = MAKE_TAISEI_EVENT(TE_VIDEO_MODE_CHANGED),
|
||||
});
|
||||
FramebufferConfig fbconf = { 0 };
|
||||
fbconf.num_attachments = 1;
|
||||
fbconf.attachments = &a;
|
||||
fbconf.resize_strategy.resize_func = video_postprocess_resize_strategy;
|
||||
|
||||
fbmgr_group_fbpair_create(vpp->mfb_group, "Global postprocess", &fbconf, &vpp->framebuffers);
|
||||
return vpp;
|
||||
}
|
||||
|
||||
void video_postprocess_shutdown(VideoPostProcess *vpp) {
|
||||
if(vpp) {
|
||||
events_unregister_handler(video_postprocess_resize_event);
|
||||
fbpair_destroy(&vpp->framebuffers);
|
||||
fbmgr_group_destroy(vpp->mfb_group);
|
||||
free(vpp);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue