diff --git a/gfx/gl.c b/gfx/gl.c index eefe474cad..18182a84a1 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -249,20 +249,21 @@ static void gl_shader_set_params(unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_count, - const struct gl_tex_info *info) + const struct gl_tex_info *info, + const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt) { #ifdef HAVE_CG gl_cg_set_params(width, height, tex_width, tex_height, out_width, out_height, - frame_count, info); + frame_count, info, fbo_info, fbo_info_cnt); #endif #ifdef HAVE_XML gl_glsl_set_params(width, height, tex_width, tex_height, out_width, out_height, - frame_count, info); + frame_count, info, fbo_info, fbo_info_cnt); #endif } @@ -774,12 +775,14 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei struct gl_tex_info tex_info = { .tex = gl->texture, .input_size = {width, height}, - .tex_size = {gl->tex_w, gl->tex_h}, - .coord = gl->tex_coords + .tex_size = {gl->tex_w, gl->tex_h} }; + struct gl_tex_info fbo_tex_info[MAX_SHADERS]; + unsigned fbo_tex_info_cnt = 0; glClear(GL_COLOR_BUFFER_BIT); - gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl->vp_width, gl->vp_height, gl->frame_count, &tex_info); + gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl->vp_width, gl->vp_height, gl->frame_count, + &tex_info, fbo_tex_info, fbo_tex_info_cnt); if (width != gl->last_width || height != gl->last_height) // Res change. need to clear out texture. { @@ -802,10 +805,10 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei gl->tex_coords[4] = x; gl->tex_coords[6] = x; gl->tex_coords[7] = y; - - //SSNES_LOG("Setting last rect: %ux%u\n", width, height); } + memcpy(tex_info.coord, gl->tex_coords, sizeof(gl->tex_coords)); + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, gl->texture_type, @@ -822,12 +825,14 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei // It's kinda handy ... :) const struct gl_fbo_rect *prev_rect; const struct gl_fbo_rect *rect; + struct gl_tex_info *fbo_info; // Calculate viewports, texture coordinates etc, and render all passes from FBOs, to another FBO. for (int i = 1; i < gl->fbo_pass; i++) { prev_rect = &gl->fbo_rect[i - 1]; rect = &gl->fbo_rect[i]; + fbo_info = &fbo_tex_info[i - 1]; GLfloat xamt = (GLfloat)prev_rect->img_width / prev_rect->width; GLfloat yamt = (GLfloat)prev_rect->img_height / prev_rect->height; @@ -837,6 +842,13 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei gl->fbo_tex_coords[5] = yamt; gl->fbo_tex_coords[6] = xamt; + fbo_info->tex = gl->fbo_texture[i - 1]; + fbo_info->input_size[0] = prev_rect->img_width; + fbo_info->input_size[1] = prev_rect->img_height; + fbo_info->tex_size[0] = prev_rect->width; + fbo_info->tex_size[1] = prev_rect->height; + memcpy(fbo_info->coord, gl->fbo_tex_coords, sizeof(gl->fbo_tex_coords)); + pglBindFramebuffer(GL_FRAMEBUFFER, gl->fbo[i]); gl_shader_use(i + 1); glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i - 1]); @@ -845,8 +857,14 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei // Render to FBO with certain size. set_viewport(gl, rect->img_width, rect->img_height, true); - gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, gl->vp_width, gl->vp_height, gl->frame_count, &tex_info); + gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, + prev_rect->width, prev_rect->height, + gl->vp_width, gl->vp_height, gl->frame_count, + &tex_info, fbo_tex_info, fbo_tex_info_cnt); + glDrawArrays(GL_QUADS, 0, 4); + + fbo_tex_info_cnt++; } // Render our last FBO texture directly to screen. @@ -863,11 +881,16 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei pglBindFramebuffer(GL_FRAMEBUFFER, 0); gl_shader_use(gl->fbo_pass + 1); + glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[gl->fbo_pass - 1]); + glClear(GL_COLOR_BUFFER_BIT); gl->render_to_tex = false; set_viewport(gl, gl->win_width, gl->win_height, false); - gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, gl->vp_width, gl->vp_height, gl->frame_count, &tex_info); - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[gl->fbo_pass - 1]); + gl_shader_set_params(prev_rect->img_width, prev_rect->img_height, + prev_rect->width, prev_rect->height, + gl->vp_width, gl->vp_height, gl->frame_count, + &tex_info, fbo_tex_info, fbo_tex_info_cnt); + glDrawArrays(GL_QUADS, 0, 4); glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords); diff --git a/gfx/gl_common.h b/gfx/gl_common.h index 39a71afbd6..9ff0225ac7 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -103,7 +103,7 @@ struct gl_tex_info GLuint tex; float input_size[2]; float tex_size[2]; - const float *coord; + float coord[8]; }; // Windows ... <_< diff --git a/gfx/shader_cg.c b/gfx/shader_cg.c index f75ca25c05..7086740344 100644 --- a/gfx/shader_cg.c +++ b/gfx/shader_cg.c @@ -94,9 +94,14 @@ void gl_cg_set_params(unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_count, - const struct gl_tex_info *info) + const struct gl_tex_info *info, + const struct gl_tex_info *fbo_info, + unsigned fbo_info_cnt) { (void)info; + (void)fbo_info; + (void)fbo_info_cnt; + if (cg_active) { cgGLSetParameter2f(prg[active_index].vid_size_f, width, height); @@ -277,11 +282,12 @@ static bool load_preset(const char *path) } cg_shader_num = shaders; - if (shaders > MAX_SHADERS) + if (shaders > MAX_SHADERS - 1) { - SSNES_WARN("Too many shaders ... Capping shader amount to %d.\n", MAX_SHADERS); - cg_shader_num = shaders = MAX_SHADERS; + SSNES_WARN("Too many shaders ... Capping shader amount to %d.\n", MAX_SHADERS - 1); + cg_shader_num = shaders = MAX_SHADERS - 1; } + prg[shaders] = prg[0]; // Check filter params. for (unsigned i = 0; i < shaders; i++) diff --git a/gfx/shader_cg.h b/gfx/shader_cg.h index 47c4d26059..306f65f17b 100644 --- a/gfx/shader_cg.h +++ b/gfx/shader_cg.h @@ -32,7 +32,8 @@ void gl_cg_set_params(unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_count, - const struct gl_tex_info *info); + const struct gl_tex_info *info, + const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt); void gl_cg_use(unsigned index); diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c index ab960edeae..e9001f0d96 100644 --- a/gfx/shader_glsl.c +++ b/gfx/shader_glsl.c @@ -713,7 +713,8 @@ void gl_glsl_set_params(unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_count, - const struct gl_tex_info *info) + const struct gl_tex_info *info, + const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt) { if (glsl_enable && gl_program[active_index] > 0) { @@ -743,6 +744,7 @@ void gl_glsl_set_params(unsigned width, unsigned height, // Set original texture unless we're in first pass (pointless). if (active_index > 1) { + // Bind original texture. pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1); glBindTexture(GL_TEXTURE_2D, info->tex); @@ -762,14 +764,59 @@ void gl_glsl_set_params(unsigned width, unsigned height, pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, info->coord); } - pglActiveTexture(GL_TEXTURE0); + GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 2; + + // Bind new texture in the chain. + if (fbo_info_cnt > 0) + { + pglActiveTexture(base_tex + fbo_info_cnt - 1); + glBindTexture(GL_TEXTURE_2D, fbo_info[fbo_info_cnt - 1].tex); + } + + // Bind FBO textures. + for (unsigned i = 0; i < fbo_info_cnt; i++) + { + char attrib_buf[64]; + + snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexture", i + 1); + location = pglGetUniformLocation(gl_program[active_index], attrib_buf); + pglUniform1i(location, base_tex + i); + + snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTextureSize", i + 1); + location = pglGetUniformLocation(gl_program[active_index], attrib_buf); + pglUniform2fv(location, 1, fbo_info[i].tex_size); + + snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uInputSize", i + 1); + location = pglGetUniformLocation(gl_program[active_index], attrib_buf); + pglUniform2fv(location, 1, fbo_info[i].input_size); + + snprintf(attrib_buf, sizeof(attrib_buf), "rubyPass%uTexCoord", i + 1); + location = pglGetAttribLocation(gl_program[active_index], attrib_buf); + if (location >= 0) + { + pglEnableVertexAttribArray(location); + pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, fbo_info[i].coord); + } + } } else { + // First pass, so unbind everything to avoid collitions. pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1); glBindTexture(GL_TEXTURE_2D, 0); - pglActiveTexture(GL_TEXTURE0); + + GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 2; + // Unbind any lurking FBO passes. + // Rendering to a texture that is bound to a texture unit + // sounds very shaky ... ;) + for (int i = 0; i < gl_num_programs; i++) + { + pglActiveTexture(GL_TEXTURE0 + base_tex + i); + glBindTexture(GL_TEXTURE_2D, 0); + } } + + pglActiveTexture(GL_TEXTURE0); } } diff --git a/gfx/shader_glsl.h b/gfx/shader_glsl.h index 1aabd658ce..d0d85ead8b 100644 --- a/gfx/shader_glsl.h +++ b/gfx/shader_glsl.h @@ -32,7 +32,8 @@ void gl_glsl_set_params(unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_counter, - const struct gl_tex_info *info); + const struct gl_tex_info *info, + const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt); void gl_glsl_use(unsigned index);