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
commit bf234dc668
5 changed files with 115 additions and 44 deletions

View file

@ -186,6 +186,21 @@ namespace rsx
private: private:
//Internal implementation methods and helpers //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 //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) 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 //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 (auto texptr = m_rtts.get_texture_from_render_target_if_applicable(texaddr))
{ {
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d) if (test_framebuffer(texaddr))
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 (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) 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()); return create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height());
} }
else else
{ {
//issue a texture barrier to ensure previous writes are visible //issue a texture barrier to ensure previous writes are visible
insert_texture_barrier(); 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 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); 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 //TODO: Check that this region is not cpu-dirty before doing a copy
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d) if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
@ -1248,5 +1269,36 @@ namespace rsx
{ {
return m_texture_memory_in_use; 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) if (!is_depth)
surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr); surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr);
else else
{
surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr); 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))) const bool dirty_framebuffer = (surface != nullptr && !m_gl_texture_cache.test_framebuffer(texaddr));
return std::make_tuple(true, 0); if (dirty_framebuffer || !surface)
}
if (!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()); auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, 0, 0, tex.pitch());
if (!rsc.surface || rsc.is_depth_surface != is_depth) if (!rsc.surface || rsc.is_depth_surface != is_depth)
return std::make_tuple(false, 0); return std::make_tuple(false, 0);

View file

@ -236,6 +236,8 @@ void GLGSRender::init_buffers(bool skip_reading)
surface_info[i].pitch = 0; surface_info[i].pitch = 0;
} }
} }
m_gl_texture_cache.tag_framebuffer(surface_addresses[i]);
} }
else else
surface_info[i] = {}; surface_info[i] = {};
@ -266,6 +268,8 @@ void GLGSRender::init_buffers(bool skip_reading)
depth_surface_info.pitch = 0; depth_surface_info.pitch = 0;
} }
} }
m_gl_texture_cache.tag_framebuffer(depth_address);
} }
else else
depth_surface_info = {}; depth_surface_info = {};

View file

@ -1819,14 +1819,23 @@ bool VKGSRender::check_program_status()
if (!is_depth) if (!is_depth)
surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr); surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr);
else else
{
surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr); 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); 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); return std::make_tuple(true, surface->native_pitch);
}; };
@ -2284,6 +2293,8 @@ void VKGSRender::prepare_rtts()
//Ignore this buffer (usually set to 64) //Ignore this buffer (usually set to 64)
m_surface_info[index].pitch = 0; 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) 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) if (m_depth_surface_info.pitch <= 64 && clip_width > m_depth_surface_info.pitch)
m_depth_surface_info.pitch = 0; m_depth_surface_info.pitch = 0;
m_texture_cache.tag_framebuffer(zeta_address);
} }
m_draw_buffers_count = static_cast<u32>(draw_buffers.size()); m_draw_buffers_count = static_cast<u32>(draw_buffers.size());

View file

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