diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 360bc10987..09b4d2aaf8 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -692,6 +692,15 @@ bool GLGSRender::load_program() else surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr); + if (!surface) + { + auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, 0, 0, tex.pitch()); + if (!rsc.surface || rsc.is_depth_surface != is_depth) + return std::make_tuple(false, 0); + + surface = rsc.surface; + } + return std::make_tuple(true, surface->get_native_pitch()); }; diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index 814dbf0d1d..761bbfa0f3 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -298,11 +298,12 @@ struct surface_subresource bool is_bound = false; bool is_depth_surface = false; + bool is_clipped = false; surface_subresource() {} - surface_subresource(gl::render_target *src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth) - : surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth) + surface_subresource(gl::render_target *src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false) + : surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped) {} }; @@ -361,7 +362,7 @@ private: } public: - surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch, bool scale_to_fit =false) + surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch, bool scale_to_fit =false, bool crop=false) { gl::render_target *surface = nullptr; bool is_subslice = false; @@ -390,18 +391,18 @@ public: return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, false), false }; else { - if (scale_to_fit) //Forcefully fit the requested region by clipping and scaling + if (crop) //Forcefully fit the requested region by clipping and scaling { u16 remaining_width = dims.first - x_offset; u16 remaining_height = dims.second - y_offset; - return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, false), false }; + return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, false), false, true }; } if (dims.first >= requested_width && dims.second >= requested_height) { LOG_WARNING(RSX, "Overlapping surface exceeds bounds; returning full surface region"); - return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, false), false }; + return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, false), false, true }; } } } @@ -430,18 +431,18 @@ public: return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, true), true }; else { - if (scale_to_fit) //Forcefully fit the requested region by clipping and scaling + if (crop) //Forcefully fit the requested region by clipping and scaling { u16 remaining_width = dims.first - x_offset; u16 remaining_height = dims.second - y_offset; - return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, false), false }; + return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, true), true, true }; } if (dims.first >= requested_width && dims.second >= requested_height) { LOG_WARNING(RSX, "Overlapping depth surface exceeds bounds; returning full surface region"); - return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, true), true }; + return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, true), true, true }; } } } diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index d264592578..edcebcb546 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -754,7 +754,11 @@ namespace gl * a bound render target. We can bypass the expensive download in this case */ - surface_subresource rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, tex.width(), tex.height(), tex.pitch(), true); + const u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + const f32 internal_scale = (f32)tex.pitch() / (tex.width() * get_format_block_size_in_bytes(format)); + const u32 internal_width = tex.width() * internal_scale; + + const surface_subresource rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, internal_width, tex.height(), tex.pitch(), true); if (rsc.surface) { //Check that this region is not cpu-dirty before doing a copy @@ -782,8 +786,6 @@ namespace gl } else { - const u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - GLenum src_format = (GLenum)rsc.surface->get_internal_format(); GLenum dst_format = std::get<0>(get_format_type(format)); @@ -1075,7 +1077,7 @@ namespace gl const u32 dst_address = (u32)((u64)dst.pixels - (u64)vm::base(0)); //Check if src/dst are parts of render targets - surface_subresource src_subres = m_rtts.get_surface_subresource_if_applicable(src_address, src.width, src.slice_h, src.pitch, true); + surface_subresource src_subres = m_rtts.get_surface_subresource_if_applicable(src_address, src.width, src.slice_h, src.pitch, true, true); src_is_render_target = src_subres.surface != nullptr; float scale_x = (f32)dst.width / src.width; @@ -1147,7 +1149,7 @@ namespace gl source_texture = src_subres.surface->id(); } - surface_subresource dst_subres = m_rtts.get_surface_subresource_if_applicable(dst_address, dst.width, dst.clip_height, dst.pitch, true); + surface_subresource dst_subres = m_rtts.get_surface_subresource_if_applicable(dst_address, dst.width, dst.clip_height, dst.pitch, true, true); dst_is_render_target = dst_subres.surface != nullptr; if (!dst_is_render_target)