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)
{ {
@ -722,6 +737,8 @@ namespace rsx
//Check for sampleable rtts from previous render passes //Check for sampleable rtts from previous render passes
//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 (test_framebuffer(texaddr))
{ {
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d) 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); LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension);
@ -746,8 +763,11 @@ namespace rsx
return texptr->get_view(); return texptr->get_view();
} }
}
if (auto texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) 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) 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); LOG_ERROR(RSX, "Texture resides in depth buffer memory, but requested type is not 2D (%d)", (u32)extended_dimension);
@ -769,6 +789,7 @@ namespace rsx
return texptr->get_view(); return texptr->get_view();
} }
} }
}
u16 depth = 0; u16 depth = 0;
u16 tex_height = (u16)tex.height(); u16 tex_height = (u16)tex.height();
@ -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;
} }