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