197 lines
5.5 KiB
C
197 lines
5.5 KiB
C
/*
|
|
* 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"
|
|
#include "video.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(ManagedFramebufferData *mfb_data, IntExtent *fb_size, FloatRect *fb_viewport) {
|
|
assume(mfb_data->resize_strategy.resize_func != NULL);
|
|
mfb_data->resize_strategy.resize_func(mfb_data->resize_strategy.userdata, fb_size, fb_viewport);
|
|
}
|
|
|
|
static void fbmgr_framebuffer_update(ManagedFramebufferData *mfb_data) {
|
|
IntExtent fb_size;
|
|
FloatRect fb_viewport;
|
|
Framebuffer *fb = GET_MFB(mfb_data)->fb;
|
|
|
|
if(mfb_data->resize_strategy.resize_func == NULL) {
|
|
return;
|
|
}
|
|
|
|
fbmgr_framebuffer_get_metrics(mfb_data, &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(d);
|
|
}
|
|
}
|
|
|
|
ManagedFramebuffer *fbmgr_framebuffer_create(const char *name, const FramebufferConfig *cfg) {
|
|
assert(cfg->attachments != NULL);
|
|
assert(cfg->num_attachments >= 1);
|
|
|
|
auto mfb = ALLOC_FLEX(ManagedFramebuffer, 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);
|
|
|
|
FloatRect fb_viewport;
|
|
|
|
if(data->resize_strategy.resize_func != NULL) {
|
|
FBAttachmentConfig ac[cfg->num_attachments];
|
|
memcpy(ac, cfg->attachments, sizeof(ac));
|
|
|
|
IntExtent fb_size;
|
|
|
|
fbmgr_framebuffer_get_metrics(data, &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, ARRAY_SIZE(ac), ac);
|
|
} else {
|
|
FBAttachmentConfig *ac = cfg->attachments;
|
|
fb_viewport = (FloatRect) {
|
|
.extent = { ac[0].tex_params.width, ac[0].tex_params.height }
|
|
};
|
|
fbutil_create_attachments(mfb->fb, cfg->num_attachments, cfg->attachments);
|
|
}
|
|
|
|
r_framebuffer_viewport_rect(mfb->fb, fb_viewport);
|
|
r_framebuffer_clear(mfb->fb, BUFFER_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);
|
|
mem_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 ALLOC(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);
|
|
}
|
|
|
|
mem_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);
|
|
}
|
|
|
|
void fbmgr_resize_strategy_screensized(void *ignored, IntExtent *out_dimensions, FloatRect *out_viewport) {
|
|
float w, h;
|
|
video_get_viewport_size(&w, &h);
|
|
*out_dimensions = (IntExtent) { w, h };
|
|
*out_viewport = (FloatRect) { 0, 0, w, h };
|
|
}
|