New system to manage auto-resized framebuffers

This commit is contained in:
Andrei Alexeyev 2019-08-25 02:28:46 +03:00
parent 5d535bb93c
commit 2e9904e83c
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
15 changed files with 430 additions and 218 deletions

View file

@ -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;

View file

@ -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();

View file

@ -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");

View file

@ -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
View 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
View 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

View file

@ -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);

View file

@ -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
View 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, &params);
r_texture_destroy(tex);
params.width = width;
params.height = height;
params.mipmaps = 0; // FIXME
r_framebuffer_attach(fb, r_texture_create(&params), 0, attachment);
}

25
src/util/fbutil.h Normal file
View 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

View file

@ -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, &params);
r_texture_destroy(tex);
params.width = width;
params.height = height;
params.mipmaps = 0; // FIXME
r_framebuffer_attach(fb, r_texture_create(&params), 0, attachment);
}
void render_character_portrait(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
r_state_push();

View file

@ -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

View file

@ -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',

View file

@ -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);

View file

@ -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);
}
}