Skip to content

Commit 63bf8cb

Browse files
committed
[WIP] PlatformCore: Revise shader chain handling
1 parent fa3a8a3 commit 63bf8cb

File tree

2 files changed

+135
-60
lines changed

2 files changed

+135
-60
lines changed

src/platform/core/include/platform/device/ogl_video_device.hpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,25 @@ struct OGLVideoDevice : VideoDevice {
3636
GLenum type,
3737
char const* source
3838
) -> std::pair<bool, GLuint>;
39-
39+
4040
auto CompileProgram(
4141
char const* vertex_src,
4242
char const* fragment_src
4343
) -> std::pair<bool, GLuint>;
4444

45+
static constexpr size_t input_index = 0;
46+
static constexpr size_t output_index = 1;
47+
static constexpr size_t history_index = 2;
48+
static constexpr size_t xbrz_output_index = 3;
49+
50+
struct ShaderPass {
51+
GLuint program = 0;
52+
struct {
53+
std::vector<GLuint> inputs = {input_index};
54+
GLuint output = output_index;
55+
} textures = {};
56+
};
57+
4558
int view_x = 0;
4659
int view_y = 0;
4760
int view_width = 1;
@@ -51,9 +64,9 @@ struct OGLVideoDevice : VideoDevice {
5164
GLuint quad_vao;
5265
GLuint quad_vbo;
5366
GLuint fbo;
54-
GLuint texture[4];
55-
std::vector<GLuint> programs;
56-
GLenum texture_filter = GL_NEAREST;
67+
std::array<GLuint, 4> textures = {};
68+
std::vector<ShaderPass> shader_passes = {};
69+
GLint texture_filter = GL_NEAREST;
5770

5871
std::shared_ptr<PlatformConfig> config;
5972
};

src/platform/core/src/device/ogl_video_device.cpp

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ OGLVideoDevice::~OGLVideoDevice() {
4343
glDeleteVertexArrays(1, &quad_vao);
4444
glDeleteBuffers(1, &quad_vbo);
4545
glDeleteFramebuffers(1, &fbo);
46-
glDeleteTextures(3, texture);
46+
glDeleteTextures(4, textures.data());
4747
}
4848

4949
void OGLVideoDevice::Initialize() {
@@ -62,7 +62,7 @@ void OGLVideoDevice::Initialize() {
6262

6363
// Create three textures and a framebuffer for postprocessing.
6464
glGenFramebuffers(1, &fbo);
65-
glGenTextures(3, texture);
65+
glGenTextures(4, textures.data());
6666

6767
glEnable(GL_FRAMEBUFFER_SRGB);
6868

@@ -84,11 +84,11 @@ void OGLVideoDevice::ReloadConfig() {
8484
}
8585

8686
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;
8989

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

9393
glTexImage2D(GL_TEXTURE_2D, 0, texture_format, gba_screen_width,
9494
gba_screen_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
@@ -99,6 +99,33 @@ void OGLVideoDevice::UpdateTextures() {
9999
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100100
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101101
}
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);
102129
}
103130

104131
void OGLVideoDevice::CreateShaderPrograms() {
@@ -111,14 +138,14 @@ void OGLVideoDevice::CreateShaderPrograms() {
111138
case Video::Color::higan: {
112139
auto [success, program] = CompileProgram(color_higan_vert, color_higan_frag);
113140
if(success) {
114-
programs.push_back(program);
141+
shader_passes.push_back({.program = program});
115142
}
116143
break;
117144
}
118145
case Video::Color::AGB: {
119146
auto [success, program] = CompileProgram(color_agb_vert, color_agb_frag);
120147
if(success) {
121-
programs.push_back(program);
148+
shader_passes.push_back({.program = program});
122149
}
123150
break;
124151
}
@@ -128,7 +155,13 @@ void OGLVideoDevice::CreateShaderPrograms() {
128155
if(video.lcd_ghosting) {
129156
auto [success, program] = CompileProgram(lcd_ghosting_vert, lcd_ghosting_frag);
130157
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+
});
132165
}
133166
}
134167

@@ -140,8 +173,23 @@ void OGLVideoDevice::CreateShaderPrograms() {
140173
auto [success1, program1] = CompileProgram(xbrz1_vert, xbrz1_frag);
141174

142175
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+
}
145193
} else {
146194
if(success0) glDeleteProgram(program0);
147195
if(success1) glDeleteProgram(program1);
@@ -152,7 +200,7 @@ void OGLVideoDevice::CreateShaderPrograms() {
152200
default: {
153201
auto [success, program] = CompileProgram(output_vert, output_frag);
154202
if(success) {
155-
programs.push_back(program);
203+
shader_passes.push_back({.program = program});
156204
}
157205
break;
158206
}
@@ -163,47 +211,47 @@ void OGLVideoDevice::CreateShaderPrograms() {
163211

164212
void OGLVideoDevice::UpdateShaderUniforms() {
165213
// 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);
168216

169-
const auto input_map = glGetUniformLocation(program, "u_input_map");
217+
const auto input_map = glGetUniformLocation(shader_pass.program, "u_input_map");
170218
if(input_map != -1) {
171219
glUniform1i(input_map, 0);
172220
}
173221

174-
const auto history_map = glGetUniformLocation(program, "u_history_map");
222+
const auto history_map = glGetUniformLocation(shader_pass.program, "u_history_map");
175223
if(history_map != -1) {
176224
glUniform1i(history_map, 1);
177225
}
178226

179-
const auto info_map = glGetUniformLocation(program, "u_info_map");
227+
const auto info_map = glGetUniformLocation(shader_pass.program, "u_info_map");
180228
if(info_map != -1) {
181-
glUniform1i(info_map, 2);
229+
glUniform1i(info_map, 1);
182230
}
183231

184-
const auto output_size = glGetUniformLocation(program, "u_output_size");
232+
const auto output_size = glGetUniformLocation(shader_pass.program, "u_output_size");
185233
glUniform2f(output_size, view_width, view_height);
186234
}
187235
}
188236

189237
void OGLVideoDevice::ReleaseShaderPrograms() {
190-
for(auto program : programs) {
191-
glDeleteProgram(program);
238+
for (const auto& shader_pass : shader_passes) {
239+
glDeleteProgram(shader_pass.program);
192240
}
193-
programs.clear();
241+
shader_passes.clear();
194242
}
195243

196244
auto OGLVideoDevice::CompileShader(
197245
GLenum type,
198246
char const* source
199247
) -> std::pair<bool, GLuint> {
200248
char const* source_array[] = { source };
201-
249+
202250
auto shader = glCreateShader(type);
203251

204252
glShaderSource(shader, 1, source_array, nullptr);
205253
glCompileShader(shader);
206-
254+
207255
GLint compiled = 0;
208256
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
209257
if(compiled == GL_FALSE) {
@@ -225,7 +273,7 @@ auto OGLVideoDevice::CompileProgram(
225273
) -> std::pair<bool, GLuint> {
226274
auto [vert_success, vert_id] = CompileShader(GL_VERTEX_SHADER, vertex_src);
227275
auto [frag_success, frag_id] = CompileShader(GL_FRAGMENT_SHADER, fragment_src);
228-
276+
229277
if(!vert_success || !frag_success) {
230278
return std::make_pair<bool, GLuint>(false, 0);
231279
} else {
@@ -247,6 +295,7 @@ void OGLVideoDevice::SetViewport(int x, int y, int width, int height) {
247295
view_width = width;
248296
view_height = height;
249297

298+
UpdateTextures();
250299
UpdateShaderUniforms();
251300
}
252301

@@ -255,51 +304,64 @@ void OGLVideoDevice::SetDefaultFBO(GLuint fbo) {
255304
}
256305

257306
void OGLVideoDevice::Draw(u32* buffer) {
258-
// Bind LCD history map
259-
glActiveTexture(GL_TEXTURE1);
260-
glBindTexture(GL_TEXTURE_2D, texture[2]);
261-
262307
// Update and bind LCD screen texture
263308
glActiveTexture(GL_TEXTURE0);
264-
glBindTexture(GL_TEXTURE_2D, texture[0]);
309+
glBindTexture(GL_TEXTURE_2D, textures[input_index]);
265310
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gba_screen_width, gba_screen_height,
266311
GL_BGRA, GL_UNSIGNED_BYTE, buffer);
267312

268-
glViewport(0, 0, gba_screen_width, gba_screen_height);
269313
glBindVertexArray(quad_vao);
270-
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
314+
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
271315

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

319+
if (shader_pass == std::prev(shader_passes.end())) {
295320
glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
296321
glViewport(view_x, view_y, view_width, view_height);
297322
} 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]]);
300339
}
301340

302341
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);
303365
}
304366
}
305367

0 commit comments

Comments
 (0)