vulkan: Avoid cache miss whenever possible if WCB is enabled

This commit is contained in:
kd-11 2017-07-23 16:34:17 +03:00
parent a7c28f5827
commit a24780fe5e
2 changed files with 94 additions and 2 deletions

View File

@ -1953,8 +1953,19 @@ void VKGSRender::prepare_rtts()
(*m_device), &*m_current_command_buffer, m_optimal_tiling_supported_formats, m_memory_type_mapping);
//Reset framebuffer information
VkFormat old_format = VK_FORMAT_UNDEFINED;
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].width = clip_width;
m_surface_info[i].height = clip_height;

View File

@ -118,6 +118,11 @@ namespace vk
return managed_texture;
}
VkFormat get_format()
{
return vram_texture->info.format;
}
bool is_flushable() const
{
//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)
m_device = &dev;
// Return false if a flush occured 'late', i.e we had a miss
bool result = true;
if (!synchronized)
{
LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base);
copy_texture(cmd, heap_index, submit_queue, true);
result = false;
}
protect(utils::protection::rw);
@ -271,6 +280,8 @@ namespace vk
dma_buffer->unmap();
//Its highly likely that this surface will be reused, so we just leave resources in place
return result;
}
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>> 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)
{
for (auto &tex : m_cache)
@ -676,7 +697,13 @@ namespace vk
}
//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;
}
}
@ -727,5 +754,59 @@ namespace vk
m_dirty_textures.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);
}
}
};
}