diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 5caaec9424..39a7f6fea5 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -179,8 +179,10 @@ namespace gl glGenBuffers(1, &pbo_id); - const u32 real_buffer_size = (u32)(rsx::get_resolution_scale() * rsx::get_resolution_scale() * cpu_address_range); + const f32 resolution_scale = rsx::get_resolution_scale(); + const u32 real_buffer_size = (resolution_scale < 1.f)? cpu_address_range: (u32)(resolution_scale * resolution_scale * cpu_address_range); const u32 buffer_size = align(real_buffer_size, 4096); + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id); glBufferStorage(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_MAP_READ_BIT); @@ -202,7 +204,6 @@ namespace gl is_depth = false; vram_texture = 0; - scaled_texture = 0; } void create(const u16 w, const u16 h, const u16 depth, const u16 mipmaps, void*, @@ -275,7 +276,7 @@ namespace gl } u32 target_texture = vram_texture; - if (0)//real_pitch != rsx_pitch || rsx::get_resolution_scale_percent() != 100) + if (real_pitch != rsx_pitch || rsx::get_resolution_scale_percent() != 100) { //Disabled - doesnt work properly yet const u32 real_width = (rsx_pitch * width) / real_pitch; @@ -302,7 +303,6 @@ namespace gl if ((u32)sw != real_width || (u32)sh != real_height || (GLenum)fmt != ifmt) { - LOG_ERROR(RSX, "Incompatible scaling texture found. Deleting..."); glDeleteTextures(1, &scaled_texture); scaled_texture = 0; } @@ -329,11 +329,37 @@ namespace gl glPixelStorei(GL_PACK_ALIGNMENT, 1); glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id); + glGetError(); + if (get_driver_caps().EXT_dsa_supported) glGetTextureImageEXT(target_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr); else glGetTextureImage(target_texture, 0, (GLenum)format, (GLenum)type, pbo_size, nullptr); + if (GLenum err = glGetError()) + { + bool recovered = false; + if (target_texture == scaled_texture) + { + if (get_driver_caps().EXT_dsa_supported) + glGetTextureImageEXT(vram_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr); + else + glGetTextureImage(vram_texture, 0, (GLenum)format, (GLenum)type, pbo_size, nullptr); + + if (!glGetError()) + { + recovered = true; + const u32 min_dimension = cpu_address_range / rsx_pitch; + LOG_WARNING(RSX, "Failed to read back a scaled image, but the original texture can be read back. Consider setting min scalable dimension below or equal to %d", min_dimension); + } + } + + if (!recovered && rsx::get_resolution_scale_percent() != 100) + { + LOG_ERROR(RSX, "Texture readback failed. Disable resolution scaling to get the 'Write Color Buffers' option to work properly"); + } + } + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); m_fence.reset(); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 4ed3a2e159..d0ce583330 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -809,7 +809,7 @@ namespace rsx const auto window_origin = rsx::method_registers.shader_window_origin(); const u32 window_height = rsx::method_registers.shader_window_height(); - const f32 resolution_scale = rsx::get_resolution_scale(); + const f32 resolution_scale = (window_height <= g_cfg.video.min_scalable_dimension)? 1.f : rsx::get_resolution_scale(); const f32 wpos_scale = (window_origin == rsx::window_origin::top) ? (1.f / resolution_scale) : (-1.f / resolution_scale); const f32 wpos_bias = (window_origin == rsx::window_origin::top) ? 0.f : window_height; diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index d9d919c7c3..156bdd0f64 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -209,19 +209,21 @@ namespace rsx return std::make_tuple(x, y, width, height); } - static inline f32 get_resolution_scale() + static inline const f32 get_resolution_scale() { return g_cfg.video.strict_rendering_mode? 1.f : ((f32)g_cfg.video.resolution_scale_percent / 100.f); } - static inline int get_resolution_scale_percent() + static inline const int get_resolution_scale_percent() { return g_cfg.video.strict_rendering_mode ? 100 : g_cfg.video.resolution_scale_percent; } static inline const u16 apply_resolution_scale(u16 value, bool clamp) { - if (clamp) + if (value <= g_cfg.video.min_scalable_dimension) + return value; + else if (clamp) return (u16)std::max((get_resolution_scale_percent() * value) / 100, 1); else return (get_resolution_scale_percent() * value) / 100; @@ -229,9 +231,16 @@ namespace rsx static inline const u16 apply_inverse_resolution_scale(u16 value, bool clamp) { + u16 result = value; + if (clamp) - return (u16)std::max((value * 100) / get_resolution_scale_percent(), 1); + result = (u16)std::max((value * 100) / get_resolution_scale_percent(), 1); else - return (value * 100) / get_resolution_scale_percent(); + result = (value * 100) / get_resolution_scale_percent(); + + if (result <= g_cfg.video.min_scalable_dimension) + return value; + + return result; } } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 68f6f9a0c0..3a7ba3c2ac 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -332,7 +332,8 @@ struct cfg_root : cfg::node cfg::_int<1, 8> consequtive_frames_to_draw{this, "Consecutive Frames To Draw", 1}; cfg::_int<1, 8> consequtive_frames_to_skip{this, "Consecutive Frames To Skip", 1}; cfg::_int<50, 800> resolution_scale_percent{this, "Resolution Scale", 100}; - cfg::_int<0, 16> anisotropic_level_override{this, "Anisotropic Filter Override", 0 }; + cfg::_int<0, 16> anisotropic_level_override{this, "Anisotropic Filter Override", 0}; + cfg::_int<1, 1024> min_scalable_dimension{this, "Minimum Scalable Dimension", 128}; struct node_d3d12 : cfg::node {