mirror of https://github.com/RPCS3/rpcs3.git
vulkan: Avoid cache miss whenever possible if WCB is enabled
This commit is contained in:
parent
a7c28f5827
commit
a24780fe5e
|
@ -1953,8 +1953,19 @@ void VKGSRender::prepare_rtts()
|
||||||
(*m_device), &*m_current_command_buffer, m_optimal_tiling_supported_formats, m_memory_type_mapping);
|
(*m_device), &*m_current_command_buffer, m_optimal_tiling_supported_formats, m_memory_type_mapping);
|
||||||
|
|
||||||
//Reset framebuffer information
|
//Reset framebuffer information
|
||||||
|
VkFormat old_format = VK_FORMAT_UNDEFINED;
|
||||||
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
|
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
|
||||||
{
|
{
|
||||||
|
//Flush old address if we keep missing it
|
||||||
|
if (m_surface_info[i].pitch && g_cfg.video.write_color_buffers)
|
||||||
|
{
|
||||||
|
if (old_format == VK_FORMAT_UNDEFINED)
|
||||||
|
old_format = vk::get_compatible_surface_format(m_surface_info[i].color_format).first;
|
||||||
|
|
||||||
|
m_texture_cache.flush_if_cache_miss_likely(old_format, m_surface_info[i].address, m_surface_info[i].pitch * m_surface_info[i].height,
|
||||||
|
*m_current_command_buffer, m_memory_type_mapping, m_swap_chain->get_present_queue());
|
||||||
|
}
|
||||||
|
|
||||||
m_surface_info[i].address = m_surface_info[i].pitch = 0;
|
m_surface_info[i].address = m_surface_info[i].pitch = 0;
|
||||||
m_surface_info[i].width = clip_width;
|
m_surface_info[i].width = clip_width;
|
||||||
m_surface_info[i].height = clip_height;
|
m_surface_info[i].height = clip_height;
|
||||||
|
|
|
@ -118,6 +118,11 @@ namespace vk
|
||||||
return managed_texture;
|
return managed_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkFormat get_format()
|
||||||
|
{
|
||||||
|
return vram_texture->info.format;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_flushable() const
|
bool is_flushable() const
|
||||||
{
|
{
|
||||||
//This section is active and can be flushed to cpu
|
//This section is active and can be flushed to cpu
|
||||||
|
@ -221,15 +226,19 @@ namespace vk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush(vk::render_device& dev, vk::command_buffer& cmd, u32 heap_index, VkQueue submit_queue)
|
bool flush(vk::render_device& dev, vk::command_buffer& cmd, u32 heap_index, VkQueue submit_queue)
|
||||||
{
|
{
|
||||||
if (m_device == nullptr)
|
if (m_device == nullptr)
|
||||||
m_device = &dev;
|
m_device = &dev;
|
||||||
|
|
||||||
|
// Return false if a flush occured 'late', i.e we had a miss
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
if (!synchronized)
|
if (!synchronized)
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base);
|
LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base);
|
||||||
copy_texture(cmd, heap_index, submit_queue, true);
|
copy_texture(cmd, heap_index, submit_queue, true);
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protect(utils::protection::rw);
|
protect(utils::protection::rw);
|
||||||
|
@ -271,6 +280,8 @@ namespace vk
|
||||||
|
|
||||||
dma_buffer->unmap();
|
dma_buffer->unmap();
|
||||||
//Its highly likely that this surface will be reused, so we just leave resources in place
|
//Its highly likely that this surface will be reused, so we just leave resources in place
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_synchronized() const
|
bool is_synchronized() const
|
||||||
|
@ -287,6 +298,16 @@ namespace vk
|
||||||
std::vector<std::unique_ptr<vk::image_view> > m_temporary_image_view;
|
std::vector<std::unique_ptr<vk::image_view> > m_temporary_image_view;
|
||||||
std::vector<std::unique_ptr<vk::image>> m_dirty_textures;
|
std::vector<std::unique_ptr<vk::image>> m_dirty_textures;
|
||||||
|
|
||||||
|
// Keep track of cache misses to pre-emptively flush some addresses
|
||||||
|
struct framebuffer_memory_characteristics
|
||||||
|
{
|
||||||
|
u32 misses;
|
||||||
|
u32 block_size;
|
||||||
|
VkFormat format;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<u32, framebuffer_memory_characteristics> m_cache_miss_statistics_table;
|
||||||
|
|
||||||
cached_texture_section& find_cached_texture(u32 rsx_address, u32 rsx_size, bool confirm_dimensions = false, u16 width = 0, u16 height = 0, u16 mipmaps = 0)
|
cached_texture_section& find_cached_texture(u32 rsx_address, u32 rsx_size, bool confirm_dimensions = false, u16 width = 0, u16 height = 0, u16 mipmaps = 0)
|
||||||
{
|
{
|
||||||
for (auto &tex : m_cache)
|
for (auto &tex : m_cache)
|
||||||
|
@ -676,7 +697,13 @@ namespace vk
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Map basic host_visible memory without coherent constraint
|
//TODO: Map basic host_visible memory without coherent constraint
|
||||||
tex.flush(dev, cmd, memory_types.host_visible_coherent, submit_queue);
|
if (!tex.flush(dev, cmd, memory_types.host_visible_coherent, submit_queue))
|
||||||
|
{
|
||||||
|
//Missed address, note this
|
||||||
|
//TODO: Lower severity when successful to keep the cache from overworking
|
||||||
|
record_cache_miss(tex);
|
||||||
|
}
|
||||||
|
|
||||||
response = true;
|
response = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,5 +754,59 @@ namespace vk
|
||||||
m_dirty_textures.clear();
|
m_dirty_textures.clear();
|
||||||
m_temporary_image_view.clear();
|
m_temporary_image_view.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void record_cache_miss(cached_texture_section &tex)
|
||||||
|
{
|
||||||
|
const u32 memory_address = tex.get_section_base();
|
||||||
|
const u32 memory_size = tex.get_section_size();
|
||||||
|
const VkFormat fmt = tex.get_format();
|
||||||
|
|
||||||
|
auto It = m_cache_miss_statistics_table.find(memory_address);
|
||||||
|
if (It == m_cache_miss_statistics_table.end())
|
||||||
|
{
|
||||||
|
m_cache_miss_statistics_table[memory_address] = { 1, memory_size, fmt };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &value = It->second;
|
||||||
|
if (value.format != fmt || value.block_size != memory_size)
|
||||||
|
{
|
||||||
|
m_cache_miss_statistics_table[memory_address] = { 1, memory_size, fmt };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value.misses++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_if_cache_miss_likely(const VkFormat fmt, const u32 memory_address, const u32 memory_size, vk::command_buffer& cmd, vk::memory_type_mapping& memory_types, VkQueue submit_queue)
|
||||||
|
{
|
||||||
|
auto It = m_cache_miss_statistics_table.find(memory_address);
|
||||||
|
if (It == m_cache_miss_statistics_table.end())
|
||||||
|
{
|
||||||
|
m_cache_miss_statistics_table[memory_address] = { 0, memory_size, fmt };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = It->second;
|
||||||
|
|
||||||
|
if (value.format != fmt || value.block_size != memory_size)
|
||||||
|
{
|
||||||
|
//Reset since the data has changed
|
||||||
|
//TODO: Keep track of all this information together
|
||||||
|
m_cache_miss_statistics_table[memory_address] = { 0, memory_size, fmt };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Properly synchronized - no miss
|
||||||
|
if (!value.misses) return;
|
||||||
|
|
||||||
|
//Auto flush if this address keeps missing (not properly synchronized)
|
||||||
|
if (value.misses > 16)
|
||||||
|
{
|
||||||
|
//TODO: Determine better way of getting threshold
|
||||||
|
LOG_ERROR(RSX, "Flushing memory at 0x%X -> Cache miss avoided", memory_address);
|
||||||
|
flush_memory_to_cache(memory_address, memory_size, cmd, memory_types, submit_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue