diff --git a/ps3/main.c b/ps3/main.c index a7209217b9..a13ce550ff 100644 --- a/ps3/main.c +++ b/ps3/main.c @@ -67,6 +67,7 @@ char DEFAULT_SHADER_FILE[MAX_PATH_LENGTH]; char DEFAULT_MENU_SHADER_FILE[MAX_PATH_LENGTH]; char SYS_CONFIG_FILE[MAX_PATH_LENGTH]; char MULTIMAN_GAME_TO_BOOT[MAX_PATH_LENGTH]; +static bool frame_advance_disabled = true; int ssnes_main(int argc, char *argv[]); @@ -329,6 +330,7 @@ static void ingame_menu(void) { if(CTRL_CIRCLE(state)) { + frame_advance_disabled = true; ingame_menu_item = 0; g_console.ingame_menu_enable = false; mode_switch = MODE_EMULATION; @@ -479,6 +481,10 @@ static void ingame_menu(void) case MENU_ITEM_FRAME_ADVANCE: if(CTRL_CROSS(state) || CTRL_R2(state) || CTRL_L2(state)) { + frame_advance_disabled = false; + ingame_menu_item = MENU_ITEM_FRAME_ADVANCE; + g_console.ingame_menu_enable = false; + mode_switch = MODE_EMULATION; } ingame_menu_reset_entry_colors (ingame_menu_item); strcpy(comment, "Press 'CROSS', 'L2' or 'R2' button to step one frame.\nNOTE: Pressing the button rapidly will advance the frame more slowly\nand prevent buttons from being input."); @@ -501,6 +507,7 @@ static void ingame_menu(void) case MENU_ITEM_RETURN_TO_GAME: if(CTRL_CROSS(button_was_pressed)) { + frame_advance_disabled = true; ingame_menu_item = 0; g_console.ingame_menu_enable = false; mode_switch = MODE_EMULATION; @@ -660,6 +667,7 @@ static void ingame_menu(void) int main(int argc, char *argv[]) { + // Initialize 6 SPUs but reserve 1 SPU as a raw SPU for PSGL sys_spu_initialize(6, 1); @@ -714,9 +722,17 @@ int main(int argc, char *argv[]) begin_loop: if(mode_switch == MODE_EMULATION) { + bool repeat = false; + if(ingame_menu_item != 0) + g_console.ingame_menu_enable = true; + g_extern.is_paused = false; input_ps3.poll(NULL); - while(ssnes_main_iterate()); + + do{ + repeat = ssnes_main_iterate(); + }while(repeat && frame_advance_disabled); + g_extern.is_paused = true; if(g_console.ingame_menu_enable) ingame_menu(); diff --git a/ps3/ps3_video_psgl.c b/ps3/ps3_video_psgl.c index 28ee4f888e..cc90bd6db6 100644 --- a/ps3/ps3_video_psgl.c +++ b/ps3/ps3_video_psgl.c @@ -219,6 +219,47 @@ static void gl_shader_scale(unsigned index, struct gl_fbo_scale *scale) gl_cg_shader_scale(index, scale); } +static void gl_create_fbo_textures(gl_t *gl) +{ + glGenTextures(gl->fbo_pass, gl->fbo_texture); + + GLuint base_filt = g_settings.video.second_pass_smooth ? GL_LINEAR : GL_NEAREST; + for (int i = 0; i < gl->fbo_pass; i++) + { + glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + GLuint filter_type = base_filt; + bool smooth; + if (gl_shader_filter_type(i + 2, &smooth)) + filter_type = smooth ? GL_LINEAR : GL_NEAREST; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type); + + glTexImage2D(GL_TEXTURE_2D, + 0, GL_ARGB_SCE, gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, GL_ARGB_SCE, + GL_UNSIGNED_INT_8_8_8_8, NULL); + } + + glBindTexture(GL_TEXTURE_2D, 0); +} + +static void gl_deinit_fbo(gl_t *gl) +{ + if (gl->fbo_inited) + { + glDeleteTextures(gl->fbo_pass, gl->fbo_texture); + glDeleteFramebuffersOES(gl->fbo_pass, gl->fbo); + memset(gl->fbo_texture, 0, sizeof(gl->fbo_texture)); + memset(gl->fbo, 0, sizeof(gl->fbo)); + gl->fbo_inited = false; + gl->render_to_tex = false; + gl->fbo_pass = 0; + } +} + // Horribly long and complex FBO init :D static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height) { @@ -349,29 +390,7 @@ static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height) SSNES_LOG("Creating FBO %d @ %ux%u\n", i, gl->fbo_rect[i].width, gl->fbo_rect[i].height); } - glGenTextures(gl->fbo_pass, gl->fbo_texture); - - GLuint base_filt = g_settings.video.second_pass_smooth ? GL_LINEAR : GL_NEAREST; - for (int i = 0; i < gl->fbo_pass; i++) - { - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - GLuint filter_type = base_filt; - bool smooth; - if (gl_shader_filter_type(i + 2, &smooth)) - filter_type = smooth ? GL_LINEAR : GL_NEAREST; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type); - - glTexImage2D(GL_TEXTURE_2D, - 0, GL_ARGB_SCE, gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, GL_ARGB_SCE, - GL_UNSIGNED_INT_8_8_8_8, NULL); - } - - glBindTexture(GL_TEXTURE_2D, 0); + gl_create_fbo_textures(gl); glGenFramebuffersOES(gl->fbo_pass, gl->fbo); for (int i = 0; i < gl->fbo_pass; i++) @@ -394,6 +413,67 @@ error: SSNES_ERR("Failed to set up frame buffer objects. Multi-pass shading will not work.\n"); } +static inline void gl_compute_fbo_geometry(gl_t *gl, unsigned width, unsigned height, + unsigned vp_width, unsigned vp_height) +{ + unsigned last_width = width; + unsigned last_height = height; + unsigned last_max_width = gl->tex_w; + unsigned last_max_height = gl->tex_h; + // Calculate viewports for FBOs. + for (int i = 0; i < gl->fbo_pass; i++) + { + switch (gl->fbo_scale[i].type_x) + { + case SSNES_SCALE_INPUT: + gl->fbo_rect[i].img_width = last_width * gl->fbo_scale[i].scale_x; + gl->fbo_rect[i].max_img_width = last_max_width * gl->fbo_scale[i].scale_x; + break; + + case SSNES_SCALE_ABSOLUTE: + gl->fbo_rect[i].img_width = gl->fbo_rect[i].max_img_width = gl->fbo_scale[i].abs_x; + break; + + case SSNES_SCALE_VIEWPORT: + gl->fbo_rect[i].img_width = gl->fbo_rect[i].max_img_width = gl->fbo_scale[i].scale_x * gl->vp_out_width; + break; + + default: + break; + } + + switch (gl->fbo_scale[i].type_y) + { + case SSNES_SCALE_INPUT: + gl->fbo_rect[i].img_height = last_height * gl->fbo_scale[i].scale_y; + gl->fbo_rect[i].max_img_height = last_max_height * gl->fbo_scale[i].scale_y; + break; + + case SSNES_SCALE_ABSOLUTE: + gl->fbo_rect[i].img_height = gl->fbo_rect[i].max_img_height = gl->fbo_scale[i].abs_y; + break; + + case SSNES_SCALE_VIEWPORT: + gl->fbo_rect[i].img_height = gl->fbo_rect[i].max_img_height = gl->fbo_scale[i].scale_y * gl->vp_out_height; + break; + + default: + break; + } + + last_width = gl->fbo_rect[i].img_width; + last_height = gl->fbo_rect[i].img_height; + last_max_width = gl->fbo_rect[i].max_img_width; + last_max_height = gl->fbo_rect[i].max_img_height; + } +} + +#define gl_start_frame_fbo(gl) \ + glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); \ + glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[0]); \ + gl->render_to_tex = true; \ + set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true); + static inline unsigned get_alignment(unsigned pitch) { if (pitch & 1) @@ -533,61 +613,8 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei // Render to texture in first pass. if (gl->fbo_inited) { - unsigned last_width = width; - unsigned last_height = height; - unsigned last_max_width = gl->tex_w; - unsigned last_max_height = gl->tex_h; - // Calculate viewports for FBOs. - for (int i = 0; i < gl->fbo_pass; i++) - { - switch (gl->fbo_scale[i].type_x) - { - case SSNES_SCALE_INPUT: - gl->fbo_rect[i].img_width = last_width * gl->fbo_scale[i].scale_x; - gl->fbo_rect[i].max_img_width = last_max_width * gl->fbo_scale[i].scale_x; - break; - - case SSNES_SCALE_ABSOLUTE: - gl->fbo_rect[i].img_width = gl->fbo_rect[i].max_img_width = gl->fbo_scale[i].abs_x; - break; - - case SSNES_SCALE_VIEWPORT: - gl->fbo_rect[i].img_width = gl->fbo_rect[i].max_img_width = gl->fbo_scale[i].scale_x * gl->vp_out_width; - break; - - default: - break; - } - - switch (gl->fbo_scale[i].type_y) - { - case SSNES_SCALE_INPUT: - gl->fbo_rect[i].img_height = last_height * gl->fbo_scale[i].scale_y; - gl->fbo_rect[i].max_img_height = last_max_height * gl->fbo_scale[i].scale_y; - break; - - case SSNES_SCALE_ABSOLUTE: - gl->fbo_rect[i].img_height = gl->fbo_rect[i].max_img_height = gl->fbo_scale[i].abs_y; - break; - - case SSNES_SCALE_VIEWPORT: - gl->fbo_rect[i].img_height = gl->fbo_rect[i].max_img_height = gl->fbo_scale[i].scale_y * gl->vp_out_height; - break; - - default: - break; - } - - last_width = gl->fbo_rect[i].img_width; - last_height = gl->fbo_rect[i].img_height; - last_max_width = gl->fbo_rect[i].max_img_width; - last_max_height = gl->fbo_rect[i].max_img_height; - } - - glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[0]); - gl->render_to_tex = true; - set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true); + gl_compute_fbo_geometry(gl, width, height, gl->vp_out_width, gl->vp_out_height); + gl_start_frame_fbo(gl); } @@ -653,76 +680,79 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei if (gl->fbo_inited) { - // Render the rest of our passes. - glTexCoordPointer(2, GL_FLOAT, 0, gl->fbo_tex_coords); - - // 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++) + if (gl->fbo_inited) { - prev_rect = &gl->fbo_rect[i - 1]; - rect = &gl->fbo_rect[i]; - fbo_info = &fbo_tex_info[i - 1]; + // Render the rest of our passes. + glTexCoordPointer(2, GL_FLOAT, 0, gl->fbo_tex_coords); + // 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; + + set_texture_coords(gl->fbo_tex_coords, xamt, yamt); + + 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)); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[i]); + gl_cg_use(i + 1); + glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i - 1]); + + glClear(GL_COLOR_BUFFER_BIT); + + // 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, g_frame_count, + &tex_info, gl->prev_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. + prev_rect = &gl->fbo_rect[gl->fbo_pass - 1]; GLfloat xamt = (GLfloat)prev_rect->img_width / prev_rect->width; GLfloat yamt = (GLfloat)prev_rect->img_height / prev_rect->height; set_texture_coords(gl->fbo_tex_coords, xamt, yamt); - 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)); + // Render our FBO texture to back buffer. + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + gl_cg_use(gl->fbo_pass + 1); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[i]); - gl_cg_use(i + 1); - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i - 1]); + glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[gl->fbo_pass - 1]); glClear(GL_COLOR_BUFFER_BIT); - - // Render to FBO with certain size. - set_viewport(gl, rect->img_width, rect->img_height, true); + 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, g_frame_count, &tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); + glVertexPointer(2, GL_FLOAT, 0, vertex_ptr); glDrawArrays(GL_QUADS, 0, 4); - fbo_tex_info_cnt++; + glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords); } - - // Render our last FBO texture directly to screen. - prev_rect = &gl->fbo_rect[gl->fbo_pass - 1]; - GLfloat xamt = (GLfloat)prev_rect->img_width / prev_rect->width; - GLfloat yamt = (GLfloat)prev_rect->img_height / prev_rect->height; - - set_texture_coords(gl->fbo_tex_coords, xamt, yamt); - - // Render our FBO texture to back buffer. - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - gl_cg_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, g_frame_count, - &tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); - - glVertexPointer(2, GL_FLOAT, 0, vertex_ptr); - glDrawArrays(GL_QUADS, 0, 4); - - glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords); } memmove(gl->prev_info + 1, gl->prev_info, sizeof(tex_info) * (TEXTURES - 1)); @@ -741,7 +771,7 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei return true; } -void ps3graphics_reinit_fbos(void) +static void gl_update_resize(void) { gl_t * gl = g_gl;