rsx: Implement memory tags for strict mode to validate render target memory

This commit is contained in:
kd-11 2017-10-26 16:20:09 +03:00
parent 11bd65c2b5
commit bf234dc668
5 changed files with 115 additions and 44 deletions

View file

@ -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;
}
};
}

View file

@ -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);

View file

@ -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 = {};

View file

@ -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());

View file

@ -239,7 +239,7 @@ namespace rsx
return std::make_pair(min, max);
}
utils::protection get_protection()
utils::protection get_protection() const
{
return protection;
}