mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
rsx: Implement memory tags for strict mode to validate render target memory
This commit is contained in:
parent
11bd65c2b5
commit
bf234dc668
5 changed files with 115 additions and 44 deletions
|
@ -186,6 +186,21 @@ namespace rsx
|
|||
private:
|
||||
//Internal implementation methods and helpers
|
||||
|
||||
utils::protection get_memory_protection(u32 address)
|
||||
{
|
||||
auto found = m_cache.find(get_block_address(address));
|
||||
if (found != m_cache.end())
|
||||
{
|
||||
for (const auto &tex : found->second.data)
|
||||
{
|
||||
if (tex.is_locked() && tex.overlaps(address, false))
|
||||
return tex.get_protection();
|
||||
}
|
||||
}
|
||||
|
||||
return utils::protection::rw;
|
||||
}
|
||||
|
||||
//Get intersecting set - Returns all objects intersecting a given range and their owning blocks
|
||||
std::vector<std::pair<section_storage_type*, ranged_storage*>> get_intersecting_set(u32 address, u32 range, bool check_whole_size)
|
||||
{
|
||||
|
@ -723,50 +738,56 @@ namespace rsx
|
|||
//TODO: When framebuffer Y compression is properly handled, this section can be removed. A more accurate framebuffer storage check exists below this block
|
||||
if (auto texptr = m_rtts.get_texture_from_render_target_if_applicable(texaddr))
|
||||
{
|
||||
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
|
||||
LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension);
|
||||
|
||||
for (const auto& tex : m_rtts.m_bound_render_targets)
|
||||
if (test_framebuffer(texaddr))
|
||||
{
|
||||
if (std::get<0>(tex) == texaddr)
|
||||
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
|
||||
LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension);
|
||||
|
||||
for (const auto& tex : m_rtts.m_bound_render_targets)
|
||||
{
|
||||
if (std::get<0>(tex) == texaddr)
|
||||
{
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
{
|
||||
LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr);
|
||||
return create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height());
|
||||
}
|
||||
else
|
||||
{
|
||||
//issue a texture barrier to ensure previous writes are visible
|
||||
insert_texture_barrier();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return texptr->get_view();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr))
|
||||
{
|
||||
if (test_framebuffer(texaddr))
|
||||
{
|
||||
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
|
||||
LOG_ERROR(RSX, "Texture resides in depth buffer memory, but requested type is not 2D (%d)", (u32)extended_dimension);
|
||||
|
||||
if (texaddr == std::get<0>(m_rtts.m_bound_depth_stencil))
|
||||
{
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
{
|
||||
LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr);
|
||||
LOG_WARNING(RSX, "Attempting to sample a currently bound depth surface @ 0x%x", texaddr);
|
||||
return create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height());
|
||||
}
|
||||
else
|
||||
{
|
||||
//issue a texture barrier to ensure previous writes are visible
|
||||
insert_texture_barrier();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return texptr->get_view();
|
||||
}
|
||||
|
||||
return texptr->get_view();
|
||||
}
|
||||
|
||||
if (auto texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr))
|
||||
{
|
||||
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
|
||||
LOG_ERROR(RSX, "Texture resides in depth buffer memory, but requested type is not 2D (%d)", (u32)extended_dimension);
|
||||
|
||||
if (texaddr == std::get<0>(m_rtts.m_bound_depth_stencil))
|
||||
{
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
{
|
||||
LOG_WARNING(RSX, "Attempting to sample a currently bound depth surface @ 0x%x", texaddr);
|
||||
return create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height());
|
||||
}
|
||||
else
|
||||
{
|
||||
//issue a texture barrier to ensure previous writes are visible
|
||||
insert_texture_barrier();
|
||||
}
|
||||
}
|
||||
|
||||
return texptr->get_view();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -810,7 +831,7 @@ namespace rsx
|
|||
const u32 internal_width = (const u32)(tex_width * internal_scale);
|
||||
|
||||
const auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, internal_width, tex_height, tex_pitch, true);
|
||||
if (rsc.surface)
|
||||
if (rsc.surface && test_framebuffer(texaddr))
|
||||
{
|
||||
//TODO: Check that this region is not cpu-dirty before doing a copy
|
||||
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
|
||||
|
@ -1248,5 +1269,36 @@ namespace rsx
|
|||
{
|
||||
return m_texture_memory_in_use;
|
||||
}
|
||||
|
||||
void tag_framebuffer(u32 texaddr)
|
||||
{
|
||||
if (!g_cfg.video.strict_rendering_mode)
|
||||
return;
|
||||
|
||||
switch (get_memory_protection(texaddr))
|
||||
{
|
||||
case utils::protection::no:
|
||||
return;
|
||||
case utils::protection::ro:
|
||||
LOG_ERROR(RSX, "Framebuffer memory occupied by regular texture!");
|
||||
return;
|
||||
}
|
||||
|
||||
vm::ps3::write32(texaddr, texaddr);
|
||||
}
|
||||
|
||||
bool test_framebuffer(u32 texaddr)
|
||||
{
|
||||
if (!g_cfg.video.strict_rendering_mode)
|
||||
return true;
|
||||
|
||||
if (g_cfg.video.write_color_buffers || g_cfg.video.write_depth_buffer)
|
||||
{
|
||||
if (get_memory_protection(texaddr) == utils::protection::no)
|
||||
return true;
|
||||
}
|
||||
|
||||
return vm::ps3::read32(texaddr) == texaddr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -947,15 +947,17 @@ bool GLGSRender::check_program_state()
|
|||
if (!is_depth)
|
||||
surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr);
|
||||
else
|
||||
{
|
||||
surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr);
|
||||
|
||||
if (!surface && m_gl_texture_cache.is_depth_texture(texaddr, (u32)get_texture_size(tex)))
|
||||
return std::make_tuple(true, 0);
|
||||
}
|
||||
|
||||
if (!surface)
|
||||
const bool dirty_framebuffer = (surface != nullptr && !m_gl_texture_cache.test_framebuffer(texaddr));
|
||||
if (dirty_framebuffer || !surface)
|
||||
{
|
||||
if (is_depth && m_gl_texture_cache.is_depth_texture(texaddr, (u32)get_texture_size(tex)))
|
||||
return std::make_tuple(true, 0);
|
||||
|
||||
if (dirty_framebuffer)
|
||||
return std::make_tuple(false, 0);
|
||||
|
||||
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);
|
||||
|
|
|
@ -224,7 +224,7 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
|
||||
//Verify pitch given is correct if pitch <= 64 (especially 64)
|
||||
if (pitchs[i] <= 64)
|
||||
{
|
||||
{
|
||||
const u16 native_pitch = std::get<1>(m_rtts.m_bound_render_targets[i])->get_native_pitch();
|
||||
if (native_pitch > pitchs[i])
|
||||
{
|
||||
|
@ -236,6 +236,8 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
surface_info[i].pitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_gl_texture_cache.tag_framebuffer(surface_addresses[i]);
|
||||
}
|
||||
else
|
||||
surface_info[i] = {};
|
||||
|
@ -266,6 +268,8 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
depth_surface_info.pitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_gl_texture_cache.tag_framebuffer(depth_address);
|
||||
}
|
||||
else
|
||||
depth_surface_info = {};
|
||||
|
|
|
@ -1819,14 +1819,23 @@ bool VKGSRender::check_program_status()
|
|||
if (!is_depth)
|
||||
surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr);
|
||||
else
|
||||
{
|
||||
surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr);
|
||||
|
||||
if (!surface && m_texture_cache.is_depth_texture(texaddr, (u32)get_texture_size(tex)))
|
||||
const bool dirty_framebuffer = (surface != nullptr && !m_texture_cache.test_framebuffer(texaddr));
|
||||
if (dirty_framebuffer || !surface)
|
||||
{
|
||||
if (is_depth && m_texture_cache.is_depth_texture(texaddr, (u32)get_texture_size(tex)))
|
||||
return std::make_tuple(true, 0);
|
||||
}
|
||||
|
||||
if (!surface) return std::make_tuple(false, 0);
|
||||
if (dirty_framebuffer)
|
||||
return std::make_tuple(false, 0);
|
||||
|
||||
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->native_pitch);
|
||||
};
|
||||
|
@ -2284,6 +2293,8 @@ void VKGSRender::prepare_rtts()
|
|||
//Ignore this buffer (usually set to 64)
|
||||
m_surface_info[index].pitch = 0;
|
||||
}
|
||||
|
||||
m_texture_cache.tag_framebuffer(surface_addresses[index]);
|
||||
}
|
||||
|
||||
if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0)
|
||||
|
@ -2297,6 +2308,8 @@ void VKGSRender::prepare_rtts()
|
|||
|
||||
if (m_depth_surface_info.pitch <= 64 && clip_width > m_depth_surface_info.pitch)
|
||||
m_depth_surface_info.pitch = 0;
|
||||
|
||||
m_texture_cache.tag_framebuffer(zeta_address);
|
||||
}
|
||||
|
||||
m_draw_buffers_count = static_cast<u32>(draw_buffers.size());
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace rsx
|
|||
return std::make_pair(min, max);
|
||||
}
|
||||
|
||||
utils::protection get_protection()
|
||||
utils::protection get_protection() const
|
||||
{
|
||||
return protection;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue