rsx: Implement mutable ring buffers with grow support

This commit is contained in:
kd-11 2019-11-09 16:14:21 +03:00 committed by kd-11
parent 5f39a594ac
commit f359342721
4 changed files with 69 additions and 10 deletions

View file

@ -10,8 +10,9 @@
* Space between GET and PUT is used by the GPU ; this structure check that this memory is not overwritten.
* User has to update the GET pointer when synchronisation happens.
*/
struct data_heap
class data_heap
{
protected:
/**
* Does alloc cross get position ?
*/
@ -43,6 +44,13 @@ struct data_heap
}
}
// Grow the buffer to hold at least size bytes
virtual bool grow(size_t size)
{
// Stub
return false;
}
size_t m_size;
size_t m_put_pos; // Start of free space
size_t m_min_guard_size; //If an allocation touches the guard region, reset the heap to avoid going over budget
@ -75,15 +83,15 @@ public:
template<int Alignment>
size_t alloc(size_t size)
{
if (!can_alloc<Alignment>(size))
const size_t alloc_size = align(size, Alignment);
const size_t aligned_put_pos = align(m_put_pos, Alignment);
if (!can_alloc<Alignment>(size) && !grow(aligned_put_pos + alloc_size))
{
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d allocated=%d requested=%d guard=%d largest_pool=%d" HERE,
m_name, m_size, m_current_allocated_size, size, m_min_guard_size, m_largest_allocated_pool);
}
size_t alloc_size = align(size, Alignment);
size_t aligned_put_pos = align(m_put_pos, Alignment);
const size_t block_length = (aligned_put_pos - m_put_pos) + alloc_size;
m_current_allocated_size += block_length;
m_largest_allocated_pool = std::max(m_largest_allocated_pool, block_length);

View file

@ -2832,7 +2832,7 @@ void VKGSRender::close_and_submit_command_buffer(VkFence fence, VkSemaphore wait
rsx::g_dma_manager.sync();
// TODO: Better check for shadowed memory
if (m_attrib_ring_info.shadow)
//if (m_attrib_ring_info.shadow)
{
if (m_attrib_ring_info.dirty() ||
m_fragment_env_ring_info.dirty() ||

View file

@ -127,6 +127,51 @@ namespace vk
#endif
}
bool data_heap::grow(size_t size)
{
// Create new heap. All sizes are aligned up by 64M, upto 1GiB
const size_t size_limit = 1024 * 0x100000;
const size_t aligned_new_size = align(m_size + size, 64 * 0x100000);
if (aligned_new_size >= size_limit)
{
// Too large
return false;
}
if (shadow)
{
// Shadowed. Growing this can be messy as it requires double allocation (macOS only)
return false;
}
// Wait for DMA activity to end
rsx::g_dma_manager.sync();
if (mapped)
{
// Force reset mapping
unmap(true);
}
VkBufferUsageFlags usage = heap->info.usage;
const auto device = get_current_renderer();
const auto& memory_map = device->get_memory_mapping();
VkFlags memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
auto memory_index = memory_map.host_visible_coherent;
// Update heap information and reset the allocator
::data_heap::init(aligned_new_size, m_name, m_min_guard_size);
// Discard old heap and create a new one. Old heap will be garbage collected when no longer needed
get_resource_manager()->dispose(heap);
heap = std::make_unique<buffer>(*device, aligned_new_size, memory_index, memory_flags, usage, 0);
return true;
}
memory_type_mapping get_memory_mapping(const vk::physical_device& dev)
{
VkPhysicalDevice pdev = dev;

View file

@ -109,7 +109,7 @@ namespace vk
class image;
struct image_view;
struct buffer;
struct data_heap;
class data_heap;
class mem_allocator_base;
struct memory_type_mapping;
struct gpu_formats_support;
@ -3384,15 +3384,21 @@ public:
};
}
struct data_heap : public ::data_heap
class data_heap : public ::data_heap
{
std::unique_ptr<buffer> heap;
private:
bool mapped = false;
void *_ptr = nullptr;
std::unique_ptr<buffer> shadow;
std::vector<VkBufferCopy> dirty_ranges;
protected:
bool grow(size_t size) override;
public:
std::unique_ptr<buffer> heap;
// NOTE: Some drivers (RADV) use heavyweight OS map/unmap routines that are insanely slow
// Avoid mapping/unmapping to keep these drivers from stalling
// NOTE2: HOST_CACHED flag does not keep the mapped ptr around in the driver either
@ -3402,7 +3408,7 @@ public:
::data_heap::init(size, name, guard);
const auto device = get_current_renderer();
const auto memory_map = device->get_memory_mapping();
const auto& memory_map = device->get_memory_mapping();
VkFlags memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
auto memory_index = memory_map.host_visible_coherent;