void GLGSRender::flip(int buffer) { if (skip_frame) { m_frame->flip(m_context, true); rsx::thread::flip(buffer); if (!skip_frame) { m_draw_calls = 0; m_begin_time = 0; m_draw_time = 0; m_vertex_upload_time = 0; m_textures_upload_time = 0; } return; } u32 buffer_width = display_buffers[buffer].width; u32 buffer_height = display_buffers[buffer].height; u32 buffer_pitch = display_buffers[buffer].pitch; // Calculate blit coordinates coordi aspect_ratio; areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height }); sizei csize(m_frame->client_width(), m_frame->client_height()); sizei new_size = csize; if (!g_cfg.video.stretch_to_display_area) { const double aq = (double)buffer_width / buffer_height; const double rq = (double)new_size.width / new_size.height; const double q = aq / rq; if (q > 1.0) { new_size.height = int(new_size.height / q); aspect_ratio.y = (csize.height - new_size.height) / 2; } else if (q < 1.0) { new_size.width = int(new_size.width * q); aspect_ratio.x = (csize.width - new_size.width) / 2; } } aspect_ratio.size = new_size; // Find the source image rsx::tiled_region buffer_region = get_tiled_address(display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); u32 absolute_address = buffer_region.address + buffer_region.base; gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address); m_flip_fbo.recreate(); m_flip_fbo.bind(); if (render_target_texture) { buffer_width = render_target_texture->width(); buffer_height = render_target_texture->height(); __glcheck m_flip_fbo.color = *render_target_texture; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } else { LOG_WARNING(RSX, "Flip texture was not found in cache. Uploading surface from CPU"); if (!m_flip_tex_color || m_flip_tex_color.size() != sizei{ (int)buffer_width, (int)buffer_height }) { m_flip_tex_color.recreate(gl::texture::target::texture2D); __glcheck m_flip_tex_color.config() .size({ (int)buffer_width, (int)buffer_height }) .type(gl::texture::type::uint_8_8_8_8) .format(gl::texture::format::bgra); m_flip_tex_color.pixel_unpack_settings().aligment(1).row_length(buffer_pitch / 4); } if (buffer_region.tile) { std::unique_ptr<u8[]> temp(new u8[buffer_height * buffer_pitch]); buffer_region.read(temp.get(), buffer_width, buffer_height, buffer_pitch); __glcheck m_flip_tex_color.copy_from(temp.get(), gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } else { __glcheck m_flip_tex_color.copy_from(buffer_region.ptr, gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } m_flip_fbo.color = m_flip_tex_color; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } // Blit source image to the screen // Disable scissor test (affects blit) glDisable(GL_SCISSOR_TEST); gl::screen.clear(gl::buffers::color_depth_stencil); __glcheck m_flip_fbo.blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear); if (g_cfg.video.overlay) { gl::screen.bind(); glViewport(0, 0, m_frame->client_width(), m_frame->client_height()); m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); m_text_printer.print_text(0, 54, m_frame->client_width(), m_frame->client_height(), "textures upload time: " + std::to_string(m_textures_upload_time) + "us"); m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); } m_frame->flip(m_context); rsx::thread::flip(buffer); // Cleanup m_gl_texture_cache.clear_temporary_surfaces(); for (auto &tex : m_rtts.invalidated_resources) tex->remove(); m_rtts.invalidated_resources.clear(); if (g_cfg.video.invalidate_surface_cache_every_frame) m_rtts.invalidate_surface_cache_data(nullptr); m_vertex_cache->purge(); //If we are skipping the next frame, do not reset perf counters if (skip_frame) return; m_draw_calls = 0; m_begin_time = 0; m_draw_time = 0; m_vertex_upload_time = 0; m_textures_upload_time = 0; }
void GLGSRender::read_buffers() { if (!draw_fbo) return; glDisable(GL_STENCIL_TEST); if (g_cfg_rsx_read_color_buffers) { auto color_format = rsx::internals::surface_color_format_to_gl(rsx::method_registers.surface_color()); auto read_color_buffers = [&](int index, int count) { u32 width = rsx::method_registers.surface_clip_width(); u32 height = rsx::method_registers.surface_clip_height(); const std::array<u32, 4> offsets = get_offsets(); const std::array<u32, 4 > locations = get_locations(); const std::array<u32, 4 > pitchs = get_pitchs(); for (int i = index; i < index + count; ++i) { u32 offset = offsets[i]; u32 location = locations[i]; u32 pitch = pitchs[i]; if (!surface_info[i].pitch) continue; rsx::tiled_region color_buffer = get_tiled_address(offset, location & 0xf); u32 texaddr = (u32)((u64)color_buffer.ptr - (u64)vm::base(0)); bool success = m_gl_texture_cache.load_rtt((*std::get<1>(m_rtts.m_bound_render_targets[i])), texaddr, pitch); //Fall back to slower methods if the image could not be fetched from cache. if (!success) { if (!color_buffer.tile) { __glcheck std::get<1>(m_rtts.m_bound_render_targets[i])->copy_from(color_buffer.ptr, color_format.format, color_format.type); } else { u32 range = pitch * height; m_gl_texture_cache.invalidate_range(texaddr, range); std::unique_ptr<u8[]> buffer(new u8[pitch * height]); color_buffer.read(buffer.get(), width, height, pitch); __glcheck std::get<1>(m_rtts.m_bound_render_targets[i])->copy_from(buffer.get(), color_format.format, color_format.type); } } } }; switch (rsx::method_registers.surface_color_target()) { case rsx::surface_target::none: break; case rsx::surface_target::surface_a: read_color_buffers(0, 1); break; case rsx::surface_target::surface_b: read_color_buffers(1, 1); break; case rsx::surface_target::surfaces_a_b: read_color_buffers(0, 2); break; case rsx::surface_target::surfaces_a_b_c: read_color_buffers(0, 3); break; case rsx::surface_target::surfaces_a_b_c_d: read_color_buffers(0, 4); break; } } if (g_cfg_rsx_read_depth_buffer) { //TODO: use pitch u32 pitch = depth_surface_info.pitch; if (!pitch) return; u32 depth_address = rsx::get_address(rsx::method_registers.surface_z_offset(), rsx::method_registers.surface_z_dma()); bool in_cache = m_gl_texture_cache.load_rtt((*std::get<1>(m_rtts.m_bound_depth_stencil)), depth_address, pitch); if (in_cache) return; //Read failed. Fall back to slow s/w path... auto depth_format = rsx::internals::surface_depth_format_to_gl(rsx::method_registers.surface_depth_fmt()); int pixel_size = rsx::internals::get_pixel_size(rsx::method_registers.surface_depth_fmt()); gl::buffer pbo_depth; __glcheck pbo_depth.create(rsx::method_registers.surface_clip_width() * rsx::method_registers.surface_clip_height() * pixel_size); __glcheck pbo_depth.map([&](GLubyte* pixels) { u32 depth_address = rsx::get_address(rsx::method_registers.surface_z_offset(), rsx::method_registers.surface_z_dma()); if (rsx::method_registers.surface_depth_fmt() == rsx::surface_depth_format::z16) { u16 *dst = (u16*)pixels; const be_t<u16>* src = vm::ps3::_ptr<u16>(depth_address); for (int i = 0, end = std::get<1>(m_rtts.m_bound_depth_stencil)->width() * std::get<1>(m_rtts.m_bound_depth_stencil)->height(); i < end; ++i) { dst[i] = src[i]; } } else { u32 *dst = (u32*)pixels; const be_t<u32>* src = vm::ps3::_ptr<u32>(depth_address); for (int i = 0, end = std::get<1>(m_rtts.m_bound_depth_stencil)->width() * std::get<1>(m_rtts.m_bound_depth_stencil)->height(); i < end; ++i) { dst[i] = src[i]; } } }, gl::buffer::access::write); __glcheck std::get<1>(m_rtts.m_bound_depth_stencil)->copy_from(pbo_depth, depth_format.format, depth_format.type); } }
void GLGSRender::flip(int buffer) { u32 buffer_width = gcm_buffers[buffer].width; u32 buffer_height = gcm_buffers[buffer].height; u32 buffer_pitch = gcm_buffers[buffer].pitch; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); u32 absolute_address = buffer_region.address + buffer_region.base; if (0) { LOG_NOTICE(RSX, "flip(%d) -> 0x%x [0x%x]", buffer, absolute_address, rsx::get_address(gcm_buffers[1 - buffer].offset, CELL_GCM_LOCATION_LOCAL)); } gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address); /** * Calling read_buffers will overwrite cached content */ __glcheck m_flip_fbo.recreate(); m_flip_fbo.bind(); auto *flip_fbo = &m_flip_fbo; if (render_target_texture) { __glcheck m_flip_fbo.color = *render_target_texture; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } else if (draw_fbo) { //HACK! it's here, because textures cache isn't implemented correctly! flip_fbo = &draw_fbo; } else { if (!m_flip_tex_color || m_flip_tex_color.size() != sizei{ (int)buffer_width, (int)buffer_height }) { m_flip_tex_color.recreate(gl::texture::target::texture2D); __glcheck m_flip_tex_color.config() .size({ (int)buffer_width, (int)buffer_height }) .type(gl::texture::type::uint_8_8_8_8) .format(gl::texture::format::bgra); m_flip_tex_color.pixel_unpack_settings().aligment(1).row_length(buffer_pitch / 4); } if (buffer_region.tile) { std::unique_ptr<u8[]> temp(new u8[buffer_height * buffer_pitch]); buffer_region.read(temp.get(), buffer_width, buffer_height, buffer_pitch); __glcheck m_flip_tex_color.copy_from(temp.get(), gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } else { __glcheck m_flip_tex_color.copy_from(buffer_region.ptr, gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } m_flip_fbo.color = m_flip_tex_color; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height }); coordi aspect_ratio; if (1) //enable aspect ratio { sizei csize(m_frame->client_width(), m_frame->client_height()); sizei new_size = csize; const double aq = (double)buffer_width / buffer_height; const double rq = (double)new_size.width / new_size.height; const double q = aq / rq; if (q > 1.0) { new_size.height = int(new_size.height / q); aspect_ratio.y = (csize.height - new_size.height) / 2; } else if (q < 1.0) { new_size.width = int(new_size.width * q); aspect_ratio.x = (csize.width - new_size.width) / 2; } aspect_ratio.size = new_size; } else { aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() }; } gl::screen.clear(gl::buffers::color_depth_stencil); __glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical()); if (g_cfg_rsx_overlay) { gl::screen.bind(); glViewport(0, 0, m_frame->client_width(), m_frame->client_height()); m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); m_text_printer.print_text(0, 54, m_frame->client_width(), m_frame->client_height(), "textures upload time: " + std::to_string(m_textures_upload_time) + "us"); m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); } m_frame->flip(m_context); m_draw_calls = 0; m_begin_time = 0; m_draw_time = 0; m_vertex_upload_time = 0; m_textures_upload_time = 0; for (auto &tex : m_rtts.invalidated_resources) { tex->remove(); } m_rtts.invalidated_resources.clear(); }