@@ -43,7 +43,7 @@ OGLVideoDevice::~OGLVideoDevice() {
43
43
glDeleteVertexArrays (1 , &quad_vao);
44
44
glDeleteBuffers (1 , &quad_vbo);
45
45
glDeleteFramebuffers (1 , &fbo);
46
- glDeleteTextures (3 , texture );
46
+ glDeleteTextures (4 , textures. data () );
47
47
}
48
48
49
49
void OGLVideoDevice::Initialize () {
@@ -62,7 +62,7 @@ void OGLVideoDevice::Initialize() {
62
62
63
63
// Create three textures and a framebuffer for postprocessing.
64
64
glGenFramebuffers (1 , &fbo);
65
- glGenTextures (3 , texture );
65
+ glGenTextures (4 , textures. data () );
66
66
67
67
glEnable (GL_FRAMEBUFFER_SRGB);
68
68
@@ -84,11 +84,11 @@ void OGLVideoDevice::ReloadConfig() {
84
84
}
85
85
86
86
void OGLVideoDevice::UpdateTextures () {
87
- const auto texture_format =
88
- config-> video . color == Video::Color::No ? GL_SRGB8_ALPHA8 : GL_RGBA8 ;
87
+ const bool color_correction_active = config-> video . color != Video::Color::No;
88
+ GLint texture_format = color_correction_active ? GL_RGBA8 : GL_SRGB8_ALPHA8 ;
89
89
90
- for (auto & texture_ref : texture ) {
91
- glBindTexture (GL_TEXTURE_2D, texture_ref );
90
+ for (const auto texture : {textures[input_index], textures[output_index]} ) {
91
+ glBindTexture (GL_TEXTURE_2D, texture );
92
92
93
93
glTexImage2D (GL_TEXTURE_2D, 0 , texture_format, gba_screen_width,
94
94
gba_screen_height, 0 , GL_BGRA, GL_UNSIGNED_BYTE, nullptr );
@@ -99,6 +99,33 @@ void OGLVideoDevice::UpdateTextures() {
99
99
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100
100
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101
101
}
102
+
103
+ const bool xbrz_ghosting = config->video .filter == Video::Filter::xBRZ && config->video .lcd_ghosting ;
104
+ const GLsizei texture_width = xbrz_ghosting ? view_width : gba_screen_width;
105
+ const GLsizei texture_height = xbrz_ghosting ? view_height : gba_screen_height;
106
+ const GLint history_texture_format = (!color_correction_active || xbrz_ghosting) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
107
+
108
+ glBindTexture (GL_TEXTURE_2D, textures[history_index]);
109
+
110
+ glTexImage2D (GL_TEXTURE_2D, 0 , history_texture_format, texture_width,
111
+ texture_height, 0 , GL_BGRA, GL_UNSIGNED_BYTE, nullptr );
112
+
113
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_filter);
114
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture_filter);
115
+
116
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
117
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
118
+
119
+ glBindTexture (GL_TEXTURE_2D, textures[xbrz_output_index]);
120
+
121
+ glTexImage2D (GL_TEXTURE_2D, 0 , texture_format, texture_width,
122
+ texture_height, 0 , GL_BGRA, GL_UNSIGNED_BYTE, nullptr );
123
+
124
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_filter);
125
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture_filter);
126
+
127
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
128
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
102
129
}
103
130
104
131
void OGLVideoDevice::CreateShaderPrograms () {
@@ -111,14 +138,14 @@ void OGLVideoDevice::CreateShaderPrograms() {
111
138
case Video::Color::higan: {
112
139
auto [success, program] = CompileProgram (color_higan_vert, color_higan_frag);
113
140
if (success) {
114
- programs .push_back (program);
141
+ shader_passes .push_back ({. program = program} );
115
142
}
116
143
break ;
117
144
}
118
145
case Video::Color::AGB: {
119
146
auto [success, program] = CompileProgram (color_agb_vert, color_agb_frag);
120
147
if (success) {
121
- programs .push_back (program);
148
+ shader_passes .push_back ({. program = program} );
122
149
}
123
150
break ;
124
151
}
@@ -128,7 +155,13 @@ void OGLVideoDevice::CreateShaderPrograms() {
128
155
if (video.lcd_ghosting ) {
129
156
auto [success, program] = CompileProgram (lcd_ghosting_vert, lcd_ghosting_frag);
130
157
if (success) {
131
- programs.push_back (program);
158
+ const GLuint input_texture = video.filter == Video::Filter::xBRZ ? xbrz_output_index : input_index;
159
+ shader_passes.push_back ({
160
+ .program = program,
161
+ .textures = {
162
+ .inputs = {input_texture, history_index}
163
+ }
164
+ });
132
165
}
133
166
}
134
167
@@ -140,8 +173,23 @@ void OGLVideoDevice::CreateShaderPrograms() {
140
173
auto [success1, program1] = CompileProgram (xbrz1_vert, xbrz1_frag);
141
174
142
175
if (success0 && success1) {
143
- programs.push_back (program0);
144
- programs.push_back (program1);
176
+ if (video.lcd_ghosting ) {
177
+ shader_passes.insert (std::prev (shader_passes.end ()),
178
+ {.program = program0});
179
+ shader_passes.insert (
180
+ std::prev (shader_passes.end ()),
181
+ {.program = program1,
182
+ .textures = {.inputs = {output_index, input_index},
183
+ .output = xbrz_output_index}});
184
+ } else {
185
+ shader_passes.push_back ({.program = program0});
186
+ shader_passes.push_back ({
187
+ .program = program1,
188
+ .textures = {
189
+ .inputs = {output_index, input_index}
190
+ }
191
+ });
192
+ }
145
193
} else {
146
194
if (success0) glDeleteProgram (program0);
147
195
if (success1) glDeleteProgram (program1);
@@ -152,7 +200,7 @@ void OGLVideoDevice::CreateShaderPrograms() {
152
200
default : {
153
201
auto [success, program] = CompileProgram (output_vert, output_frag);
154
202
if (success) {
155
- programs .push_back (program);
203
+ shader_passes .push_back ({. program = program} );
156
204
}
157
205
break ;
158
206
}
@@ -163,47 +211,47 @@ void OGLVideoDevice::CreateShaderPrograms() {
163
211
164
212
void OGLVideoDevice::UpdateShaderUniforms () {
165
213
// Set constant shader uniforms.
166
- for (const auto program : programs ) {
167
- glUseProgram (program);
214
+ for (const auto & shader_pass : shader_passes ) {
215
+ glUseProgram (shader_pass. program );
168
216
169
- const auto input_map = glGetUniformLocation (program, " u_input_map" );
217
+ const auto input_map = glGetUniformLocation (shader_pass. program , " u_input_map" );
170
218
if (input_map != -1 ) {
171
219
glUniform1i (input_map, 0 );
172
220
}
173
221
174
- const auto history_map = glGetUniformLocation (program, " u_history_map" );
222
+ const auto history_map = glGetUniformLocation (shader_pass. program , " u_history_map" );
175
223
if (history_map != -1 ) {
176
224
glUniform1i (history_map, 1 );
177
225
}
178
226
179
- const auto info_map = glGetUniformLocation (program, " u_info_map" );
227
+ const auto info_map = glGetUniformLocation (shader_pass. program , " u_info_map" );
180
228
if (info_map != -1 ) {
181
- glUniform1i (info_map, 2 );
229
+ glUniform1i (info_map, 1 );
182
230
}
183
231
184
- const auto output_size = glGetUniformLocation (program, " u_output_size" );
232
+ const auto output_size = glGetUniformLocation (shader_pass. program , " u_output_size" );
185
233
glUniform2f (output_size, view_width, view_height);
186
234
}
187
235
}
188
236
189
237
void OGLVideoDevice::ReleaseShaderPrograms () {
190
- for ( auto program : programs ) {
191
- glDeleteProgram (program);
238
+ for ( const auto & shader_pass : shader_passes ) {
239
+ glDeleteProgram (shader_pass. program );
192
240
}
193
- programs .clear ();
241
+ shader_passes .clear ();
194
242
}
195
243
196
244
auto OGLVideoDevice::CompileShader (
197
245
GLenum type,
198
246
char const * source
199
247
) -> std::pair<bool, GLuint> {
200
248
char const * source_array[] = { source };
201
-
249
+
202
250
auto shader = glCreateShader (type);
203
251
204
252
glShaderSource (shader, 1 , source_array, nullptr );
205
253
glCompileShader (shader);
206
-
254
+
207
255
GLint compiled = 0 ;
208
256
glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
209
257
if (compiled == GL_FALSE) {
@@ -225,7 +273,7 @@ auto OGLVideoDevice::CompileProgram(
225
273
) -> std::pair<bool, GLuint> {
226
274
auto [vert_success, vert_id] = CompileShader (GL_VERTEX_SHADER, vertex_src);
227
275
auto [frag_success, frag_id] = CompileShader (GL_FRAGMENT_SHADER, fragment_src);
228
-
276
+
229
277
if (!vert_success || !frag_success) {
230
278
return std::make_pair<bool , GLuint>(false , 0 );
231
279
} else {
@@ -247,6 +295,7 @@ void OGLVideoDevice::SetViewport(int x, int y, int width, int height) {
247
295
view_width = width;
248
296
view_height = height;
249
297
298
+ UpdateTextures ();
250
299
UpdateShaderUniforms ();
251
300
}
252
301
@@ -255,51 +304,64 @@ void OGLVideoDevice::SetDefaultFBO(GLuint fbo) {
255
304
}
256
305
257
306
void OGLVideoDevice::Draw (u32 * buffer) {
258
- // Bind LCD history map
259
- glActiveTexture (GL_TEXTURE1);
260
- glBindTexture (GL_TEXTURE_2D, texture[2 ]);
261
-
262
307
// Update and bind LCD screen texture
263
308
glActiveTexture (GL_TEXTURE0);
264
- glBindTexture (GL_TEXTURE_2D, texture[ 0 ]);
309
+ glBindTexture (GL_TEXTURE_2D, textures[input_index ]);
265
310
glTexSubImage2D (GL_TEXTURE_2D, 0 , 0 , 0 , gba_screen_width, gba_screen_height,
266
311
GL_BGRA, GL_UNSIGNED_BYTE, buffer);
267
312
268
- glViewport (0 , 0 , gba_screen_width, gba_screen_height);
269
313
glBindVertexArray (quad_vao);
270
- glBindFramebuffer (GL_FRAMEBUFFER , fbo);
314
+ glBindFramebuffer (GL_DRAW_FRAMEBUFFER , fbo);
271
315
272
- for (auto pass_iter = programs.begin (); pass_iter != programs.end (); ++pass_iter) {
273
- glUseProgram (*pass_iter);
274
-
275
- if (pass_iter != programs.begin ()) {
276
- // Swap input and output textures.
277
- std::swap (texture[0 ], texture[1 ]);
278
- }
279
- if (pass_iter == std::prev (programs.end ())) {
280
- // Before rendering to screen, copy the current texture content
281
- // into the history texture for the ghosting effect shader.
282
- if (config->video .filter == Video::Filter::xBRZ) {
283
- glActiveTexture (GL_TEXTURE2);
284
- glBindTexture (GL_TEXTURE_2D, texture[0 ]);
285
- glActiveTexture (GL_TEXTURE0);
286
- glBindTexture (GL_TEXTURE_2D, texture[1 ]);
287
- glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1 ], 0 );
288
- } else {
289
- glBindTexture (GL_TEXTURE_2D, texture[0 ]);
290
- }
291
- glActiveTexture (GL_TEXTURE1);
292
- glReadBuffer (GL_COLOR_ATTACHMENT0);
293
- glCopyTexSubImage2D (GL_TEXTURE_2D, 0 , 0 , 0 , 0 , 0 , gba_screen_width, gba_screen_height);
316
+ for (auto shader_pass = shader_passes.begin (); shader_pass != shader_passes.end (); ++shader_pass) {
317
+ glUseProgram (shader_pass->program );
294
318
319
+ if (shader_pass == std::prev (shader_passes.end ())) {
295
320
glBindFramebuffer (GL_FRAMEBUFFER, default_fbo);
296
321
glViewport (view_x, view_y, view_width, view_height);
297
322
} else {
298
- glBindTexture (GL_TEXTURE_2D, texture[0 ]);
299
- glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1 ], 0 );
323
+ glActiveTexture (GL_TEXTURE0);
324
+ glBindTexture (GL_TEXTURE_2D, textures[shader_pass->textures .output ]);
325
+
326
+ GLint output_width = 0 ;
327
+ GLint output_height = 0 ;
328
+ glGetTexLevelParameteriv (GL_TEXTURE_2D, 0 , GL_TEXTURE_WIDTH, &output_width);
329
+ glGetTexLevelParameteriv (GL_TEXTURE_2D, 0 , GL_TEXTURE_HEIGHT, &output_height);
330
+
331
+ glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[shader_pass->textures .output ], 0 );
332
+
333
+ glViewport (0 , 0 , output_width, output_height);
334
+ }
335
+
336
+ for (size_t i = 0 ; i < shader_pass->textures .inputs .size (); ++i) {
337
+ glActiveTexture (GL_TEXTURE0 + i);
338
+ glBindTexture (GL_TEXTURE_2D, textures[shader_pass->textures .inputs [i]]);
300
339
}
301
340
302
341
glDrawArrays (GL_TRIANGLES, 0 , 6 );
342
+
343
+ std::swap (textures[input_index], textures[output_index]);
344
+ }
345
+
346
+ if (config->video .lcd_ghosting ) {
347
+ GLint copy_area_x = 0 ;
348
+ GLint copy_area_y = 0 ;
349
+ GLsizei copy_area_width = gba_screen_width;
350
+ GLsizei copy_area_height = gba_screen_height;
351
+ if (config->video .filter == Video::Filter::xBRZ) {
352
+ copy_area_x = view_x;
353
+ copy_area_y = view_y;
354
+ copy_area_width = view_width;
355
+ copy_area_height = view_height;
356
+ } else {
357
+ glBindFramebuffer (GL_READ_FRAMEBUFFER, fbo);
358
+ glFramebufferTexture2D (GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[output_index], 0 );
359
+ }
360
+
361
+ glActiveTexture (GL_TEXTURE0);
362
+ glBindTexture (GL_TEXTURE_2D, textures[history_index]);
363
+ glReadBuffer (GL_COLOR_ATTACHMENT0);
364
+ glCopyTexSubImage2D (GL_TEXTURE_2D, 0 , 0 , 0 , copy_area_x, copy_area_y, copy_area_width, copy_area_height);
303
365
}
304
366
}
305
367
0 commit comments