1 /*
2 * This software is licensed under the terms of the MIT License.
3 * See COPYING for further information.
4 * ---
5 * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6 * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7 */
8
9 #include "taisei.h"
10
11 #include "fbmgr.h"
12 #include "list.h"
13 #include "events.h"
14 #include "config.h"
15
16 typedef struct ManagedFramebufferData ManagedFramebufferData;
17
18 struct ManagedFramebufferData {
19 LIST_INTERFACE(ManagedFramebufferData);
20 List group_node;
21 FramebufferResizeStrategy resize_strategy;
22 };
23
24 struct ManagedFramebufferGroup {
25 List *members;
26 };
27
28 #define GET_MFB(mfb_data) CASTPTR_ASSUME_ALIGNED((char*)(mfb_data) - offsetof(ManagedFramebuffer, data), ManagedFramebuffer)
29 #define GET_DATA(mfb) CASTPTR_ASSUME_ALIGNED(&(mfb)->data, ManagedFramebufferData)
30 #define GROUPNODE_TO_DATA(gn) CASTPTR_ASSUME_ALIGNED((char*)(gn) - offsetof(ManagedFramebufferData, group_node), ManagedFramebufferData)
31
32 static ManagedFramebufferData *framebuffers;
33
fbmgr_framebuffer_get_metrics(ManagedFramebuffer * mfb,IntExtent * fb_size,FloatRect * fb_viewport)34 static inline void fbmgr_framebuffer_get_metrics(ManagedFramebuffer *mfb, IntExtent *fb_size, FloatRect *fb_viewport) {
35 ManagedFramebufferData *mfb_data = GET_DATA(mfb);
36 mfb_data->resize_strategy.resize_func(mfb_data->resize_strategy.userdata, fb_size, fb_viewport);
37 }
38
fbmgr_framebuffer_update(ManagedFramebuffer * mfb)39 static void fbmgr_framebuffer_update(ManagedFramebuffer *mfb) {
40 IntExtent fb_size;
41 FloatRect fb_viewport;
42 Framebuffer *fb = mfb->fb;
43
44 fbmgr_framebuffer_get_metrics(mfb, &fb_size, &fb_viewport);
45
46 for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
47 fbutil_resize_attachment(fb, i, fb_size.w, fb_size.h);
48 }
49
50 r_framebuffer_viewport_rect(fb, fb_viewport);
51 }
52
fbmgr_framebuffer_update_all(void)53 static void fbmgr_framebuffer_update_all(void) {
54 for(ManagedFramebufferData *d = framebuffers; d; d = d->next) {
55 fbmgr_framebuffer_update(GET_MFB(d));
56 }
57 }
58
fbmgr_framebuffer_create(const char * name,const FramebufferConfig * cfg)59 ManagedFramebuffer *fbmgr_framebuffer_create(const char *name, const FramebufferConfig *cfg) {
60 assert(cfg->resize_strategy.resize_func != NULL);
61 assert(cfg->attachments != NULL);
62 assert(cfg->num_attachments >= 1);
63
64 ManagedFramebuffer *mfb = calloc(1, sizeof(*mfb) + sizeof(ManagedFramebufferData));
65 ManagedFramebufferData *data = GET_DATA(mfb);
66 data->resize_strategy = cfg->resize_strategy;
67 mfb->fb = r_framebuffer_create();
68 r_framebuffer_set_debug_label(mfb->fb, name);
69
70 FBAttachmentConfig ac[cfg->num_attachments];
71 memcpy(ac, cfg->attachments, sizeof(ac));
72
73 IntExtent fb_size;
74 FloatRect fb_viewport;
75 fbmgr_framebuffer_get_metrics(mfb, &fb_size, &fb_viewport);
76
77 for(int i = 0; i < cfg->num_attachments; ++i) {
78 ac[i].tex_params.width = fb_size.w;
79 ac[i].tex_params.height = fb_size.h;
80 }
81
82 fbutil_create_attachments(mfb->fb, cfg->num_attachments, ac);
83 r_framebuffer_viewport_rect(mfb->fb, fb_viewport);
84 r_framebuffer_clear(mfb->fb, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
85
86 list_push(&framebuffers, data);
87 return mfb;
88 }
89
fbmgr_framebuffer_disown(ManagedFramebuffer * mfb)90 Framebuffer *fbmgr_framebuffer_disown(ManagedFramebuffer *mfb) {
91 for(ManagedFramebufferData *d = framebuffers; d; d = d->next) {
92 ManagedFramebuffer *m = GET_MFB(d);
93
94 if(m == mfb) {
95 if(d->resize_strategy.cleanup_func) {
96 d->resize_strategy.cleanup_func(d->resize_strategy.userdata);
97 }
98
99 Framebuffer *fb = m->fb;
100 list_unlink(&framebuffers, d);
101 free(m);
102 return fb;
103 }
104 }
105
106 UNREACHABLE;
107 }
108
fbmgr_framebuffer_destroy(ManagedFramebuffer * mfb)109 void fbmgr_framebuffer_destroy(ManagedFramebuffer *mfb) {
110 Framebuffer *fb = fbmgr_framebuffer_disown(mfb);
111 fbutil_destroy_attachments(fb);
112 r_framebuffer_destroy(fb);
113 }
114
fbmgr_event(SDL_Event * evt,void * arg)115 static bool fbmgr_event(SDL_Event *evt, void *arg) {
116 switch(TAISEI_EVENT(evt->type)) {
117 case TE_VIDEO_MODE_CHANGED:
118 fbmgr_framebuffer_update_all();
119 break;
120
121 case TE_CONFIG_UPDATED:
122 switch(evt->user.code) {
123 case CONFIG_POSTPROCESS:
124 case CONFIG_BG_QUALITY:
125 case CONFIG_FG_QUALITY:
126 fbmgr_framebuffer_update_all();
127 break;
128
129 default: break;
130 }
131
132 break;
133 }
134
135 return false;
136 }
137
fbmgr_init(void)138 void fbmgr_init(void) {
139 events_register_handler(&(EventHandler) {
140 fbmgr_event, NULL, EPRIO_SYSTEM,
141 });
142 }
143
fbmgr_shutdown(void)144 void fbmgr_shutdown(void) {
145 events_unregister_handler(fbmgr_event);
146 }
147
fbmgr_group_create(void)148 ManagedFramebufferGroup *fbmgr_group_create(void) {
149 return calloc(1, sizeof(ManagedFramebufferGroup));
150 }
151
fbmgr_group_destroy(ManagedFramebufferGroup * group)152 void fbmgr_group_destroy(ManagedFramebufferGroup *group) {
153 for(List *n = group->members, *next; n; n = next) {
154 next = n->next;
155 ManagedFramebuffer *mfb = GET_MFB(GROUPNODE_TO_DATA(n));
156 fbmgr_framebuffer_destroy(mfb);
157 }
158
159 free(group);
160 }
161
fbmgr_group_framebuffer_create(ManagedFramebufferGroup * group,const char * name,const FramebufferConfig * cfg)162 Framebuffer *fbmgr_group_framebuffer_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg) {
163 ManagedFramebuffer *mfb = fbmgr_framebuffer_create(name, cfg);
164 ManagedFramebufferData *mfb_data = GET_DATA(mfb);
165 list_push(&group->members, &mfb_data->group_node);
166 return mfb->fb;
167 }
168
fbmgr_group_fbpair_create(ManagedFramebufferGroup * group,const char * name,const FramebufferConfig * cfg,FBPair * fbpair)169 void fbmgr_group_fbpair_create(ManagedFramebufferGroup *group, const char *name, const FramebufferConfig *cfg, FBPair *fbpair) {
170 char buf[R_DEBUG_LABEL_SIZE];
171 snprintf(buf, sizeof(buf), "%s FB 1", name);
172 fbpair->front = fbmgr_group_framebuffer_create(group, buf, cfg);
173 snprintf(buf, sizeof(buf), "%s FB 2", name);
174 fbpair->back = fbmgr_group_framebuffer_create(group, buf, cfg);
175 }
176
177