Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rsx: Surface cache improvements 2 [part 2 of 3] #6357

Merged
merged 3 commits into from Aug 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 53 additions & 0 deletions rpcs3/Emu/RSX/Common/TextureUtils.cpp
Expand Up @@ -896,4 +896,57 @@ u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& re
encode |= (remap.second[2] << 12);
encode |= (remap.second[3] << 14);
return encode;
}

std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format format)
{
switch (format)
{
case rsx::surface_color_format::r5g6b5:
return{ CELL_GCM_TEXTURE_R5G6B5, false };

case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
case rsx::surface_color_format::a8r8g8b8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, true }; //verified

case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
case rsx::surface_color_format::a8b8g8r8:
return{ CELL_GCM_TEXTURE_A8R8G8B8, false };

case rsx::surface_color_format::w16z16y16x16:
return{ CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT, true };

case rsx::surface_color_format::w32z32y32x32:
return{ CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT, true };

case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
return{ CELL_GCM_TEXTURE_A1R5G5B5, false };

case rsx::surface_color_format::b8:
return{ CELL_GCM_TEXTURE_B8, false };

case rsx::surface_color_format::g8b8:
return{ CELL_GCM_TEXTURE_G8B8, true };

case rsx::surface_color_format::x32:
return{ CELL_GCM_TEXTURE_X32_FLOAT, true }; //verified
default:
fmt::throw_exception("Unhandled surface format 0x%x", (u32)format);
}
}

std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_depth_format format)
{
switch (format)
{
case rsx::surface_depth_format::z16:
return{ CELL_GCM_TEXTURE_DEPTH16, true };
case rsx::surface_depth_format::z24s8:
return{ CELL_GCM_TEXTURE_DEPTH24_D8, true };
default:
ASSUME(0);
}
}
6 changes: 6 additions & 0 deletions rpcs3/Emu/RSX/Common/TextureUtils.h
Expand Up @@ -146,3 +146,9 @@ u32 get_format_packed_pitch(u32 format, u16 width, bool border = false, bool swi
* Reverse encoding
*/
u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap);

/**
* Get gcm texel layout. Returns <format, byteswapped>
*/
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format format);
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_depth_format format);
149 changes: 96 additions & 53 deletions rpcs3/Emu/RSX/Common/surface_store.h
Expand Up @@ -311,7 +311,7 @@ namespace rsx

if (ignore) continue;

this_address = surface->memory_tag_samples[0].first;
this_address = surface->base_addr;
verify(HERE), this_address;
}

Expand Down Expand Up @@ -363,6 +363,7 @@ namespace rsx
surface_storage_type new_surface_storage;
surface_type old_surface = nullptr;
surface_type new_surface = nullptr;
bool do_intersection_test = true;
bool store = true;

address_range *storage_bounds;
Expand Down Expand Up @@ -404,10 +405,13 @@ namespace rsx
{
// Preserve memory outside the area to be inherited if needed
split_surface_region<depth>(command_list, address, Traits::get(surface), (u16)width, (u16)height, bpp, antialias);
old_surface = Traits::get(surface);
}

old_surface = Traits::get(surface);
// This will be unconditionally moved to invalidated list shortly
Traits::notify_surface_invalidated(surface);
old_surface_storage = std::move(surface);

primary_storage->erase(It);
}
}
Expand All @@ -428,10 +432,9 @@ namespace rsx
new_surface_storage = std::move(surface);
Traits::notify_surface_reused(new_surface_storage);

if (old_surface)
if (old_surface_storage)
{
// Exchange this surface with the invalidated one
Traits::notify_surface_invalidated(old_surface_storage);
surface = std::move(old_surface_storage);
}
else
Expand All @@ -449,10 +452,9 @@ namespace rsx
}

// Check for stale storage
if (old_surface != nullptr && new_surface == nullptr)
if (old_surface_storage)
{
// This was already determined to be invalid and is excluded from testing above
Traits::notify_surface_invalidated(old_surface_storage);
invalidated_resources.push_back(std::move(old_surface_storage));
}

Expand All @@ -463,36 +465,46 @@ namespace rsx
new_surface = Traits::get(new_surface_storage);
}

if (!old_surface)
// Remove and preserve if possible any overlapping/replaced surface from the other pool
auto aliased_surface = secondary_storage->find(address);
if (aliased_surface != secondary_storage->end())
{
// Remove and preserve if possible any overlapping/replaced surface from the other pool
auto aliased_surface = secondary_storage->find(address);
if (aliased_surface != secondary_storage->end())
if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch))
{
if (Traits::surface_is_pitch_compatible(aliased_surface->second, pitch))
auto surface = Traits::get(aliased_surface->second);
split_surface_region<!depth>(command_list, address, surface, (u16)width, (u16)height, bpp, antialias);

if (!old_surface || old_surface->last_use_tag < surface->last_use_tag)
{
old_surface = Traits::get(aliased_surface->second);
split_surface_region<!depth>(command_list, address, old_surface, (u16)width, (u16)height, bpp, antialias);
// TODO: This can leak data outside inherited bounds
old_surface = surface;
}

Traits::notify_surface_invalidated(aliased_surface->second);
invalidated_resources.push_back(std::move(aliased_surface->second));
secondary_storage->erase(aliased_surface);
}
}

bool do_intersection_test = true;
Traits::notify_surface_invalidated(aliased_surface->second);
invalidated_resources.push_back(std::move(aliased_surface->second));
secondary_storage->erase(aliased_surface);
}

// Check if old_surface is 'new' and hopefully avoid intersection
if (old_surface && old_surface->last_use_tag >= write_tag)
if (old_surface)
{
const auto new_area = new_surface->get_normalized_memory_area();
const auto old_area = old_surface->get_normalized_memory_area();

if (new_area.x2 <= old_area.x2 && new_area.y2 <= old_area.y2)
if (old_surface->last_use_tag < new_surface->last_use_tag)
{
do_intersection_test = false;
new_surface->set_old_contents(old_surface);
// Can happen if aliasing occurs; a probable condition due to memory splitting
// This is highly unlikely but is possible in theory
old_surface = nullptr;
}
else if (old_surface->last_use_tag >= write_tag)
{
const auto new_area = new_surface->get_normalized_memory_area();
const auto old_area = old_surface->get_normalized_memory_area();

if (new_area.x2 <= old_area.x2 && new_area.y2 <= old_area.y2)
{
do_intersection_test = false;
new_surface->set_old_contents(old_surface);
}
}
}

Expand All @@ -507,7 +519,7 @@ namespace rsx
(*primary_storage)[address] = std::move(new_surface_storage);
}

verify(HERE), new_surface->get_spp() == get_format_sample_count(antialias);
verify(HERE), !old_surface_storage, new_surface->get_spp() == get_format_sample_count(antialias);
return new_surface;
}

Expand Down Expand Up @@ -704,7 +716,7 @@ namespace rsx
}

template <typename commandbuffer_type>
std::vector<surface_overlap_info> get_merged_texture_memory_region(commandbuffer_type& cmd, u32 texaddr, u32 required_width, u32 required_height, u32 required_pitch, u8 required_bpp)
std::vector<surface_overlap_info> get_merged_texture_memory_region(commandbuffer_type& cmd, u32 texaddr, u32 required_width, u32 required_height, u32 required_pitch, u8 required_bpp, rsx::surface_access access)
{
std::vector<surface_overlap_info> result;
std::vector<std::pair<u32, bool>> dirty;
Expand All @@ -727,12 +739,6 @@ namespace rsx
if ((this_address + texture_size) <= texaddr)
continue;

if (surface->read_barrier(cmd); !surface->test())
{
dirty.emplace_back(this_address, is_depth);
continue;
}

surface_overlap_info info;
info.surface = surface;
info.base_address = this_address;
Expand Down Expand Up @@ -777,6 +783,13 @@ namespace rsx
info.height = std::min<u32>(required_height, normalized_surface_height - info.src_y);
}

// Delay this as much as possible to avoid side-effects of spamming barrier
if (surface->memory_barrier(cmd, access); !surface->test())
{
dirty.emplace_back(this_address, is_depth);
continue;
}

info.is_clipped = (info.width < required_width || info.height < required_height);

if (auto surface_bpp = surface->get_bpp(); UNLIKELY(surface_bpp != required_bpp))
Expand Down Expand Up @@ -831,22 +844,25 @@ namespace rsx
return result;
}

void on_write(u32 address = 0)
void on_write(bool color, bool z, u32 address = 0)
{
if (!address)
{
if (write_tag == cache_tag)
{
if (m_invalidate_on_write)
{
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
if (color)
{
m_bound_render_targets[i].second->on_invalidate_children();
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{
m_bound_render_targets[i].second->on_invalidate_children();
}
}

if (m_bound_depth_stencil.first)
if (z && m_bound_depth_stencil.first)
{
m_bound_depth_stencil.second->on_invalidate_children();
}
Expand All @@ -860,33 +876,39 @@ namespace rsx
}

// Tag all available surfaces
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
if (color)
{
m_bound_render_targets[i].second->on_write(write_tag);
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{
m_bound_render_targets[i].second->on_write(write_tag);
}
}

if (m_bound_depth_stencil.first)
if (z && m_bound_depth_stencil.first)
{
m_bound_depth_stencil.second->on_write(write_tag);
}
}
else
{
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
if (color)
{
if (m_bound_render_targets[i].first != address)
for (int i = m_bound_render_targets_config.first, count = 0;
count < m_bound_render_targets_config.second;
++i, ++count)
{
continue;
}
if (m_bound_render_targets[i].first != address)
{
continue;
}

m_bound_render_targets[i].second->on_write(write_tag);
m_bound_render_targets[i].second->on_write(write_tag);
}
}

if (m_bound_depth_stencil.first == address)
if (z && m_bound_depth_stencil.first == address)
{
m_bound_depth_stencil.second->on_write(write_tag);
}
Expand Down Expand Up @@ -922,5 +944,26 @@ namespace rsx
rtt = std::make_pair(0, nullptr);
}
}

void invalidate_range(const rsx::address_range& range)
{
for (auto &rtt : m_render_targets_storage)
{
if (range.overlaps(rtt.second->get_memory_range()))
{
rtt.second->clear_rw_barrier();
rtt.second->state_flags |= rsx::surface_state_flags::erase_bkgnd;
}
}

for (auto &ds : m_depth_stencil_storage)
{
if (range.overlaps(ds.second->get_memory_range()))
{
ds.second->clear_rw_barrier();
ds.second->state_flags |= rsx::surface_state_flags::erase_bkgnd;
}
}
}
};
}