vkd3d: Recycle command pools.
Elden Ring in particular spam frees and allocates command pools despite this being a very bad idea. Add a simple 8-entry cache which seems to take care of it. Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
parent
4b07535909
commit
54fbadcc94
|
@ -1587,7 +1587,31 @@ static ULONG STDMETHODCALLTYPE d3d12_command_allocator_Release(ID3D12CommandAllo
|
|||
vkd3d_free(allocator->framebuffers);
|
||||
vkd3d_free(allocator->passes);
|
||||
|
||||
/* All command buffers are implicitly freed when a pool is destroyed. */
|
||||
if (pthread_mutex_lock(&device->mutex) == 0)
|
||||
{
|
||||
if (device->cached_command_allocator_count < ARRAY_SIZE(device->cached_command_allocators))
|
||||
{
|
||||
/* Recycle the pool. Some games spam free/allocate pools,
|
||||
* even if it completely goes against the point of the API. */
|
||||
|
||||
/* Have to free command buffers here if we're going to recycle,
|
||||
* otherwise DestroyCommandPool takes care of it. */
|
||||
VK_CALL(vkFreeCommandBuffers(device->vk_device, allocator->vk_command_pool,
|
||||
allocator->command_buffer_count, allocator->command_buffers));
|
||||
VK_CALL(vkResetCommandPool(device->vk_device, allocator->vk_command_pool, 0));
|
||||
|
||||
device->cached_command_allocators[device->cached_command_allocator_count].vk_command_pool =
|
||||
allocator->vk_command_pool;
|
||||
device->cached_command_allocators[device->cached_command_allocator_count].vk_family_index =
|
||||
allocator->vk_family_index;
|
||||
device->cached_command_allocator_count++;
|
||||
allocator->vk_command_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
}
|
||||
|
||||
/* Command buffers are implicitly freed when destroying the pool. */
|
||||
vkd3d_free(allocator->command_buffers);
|
||||
VK_CALL(vkDestroyCommandPool(device->vk_device, allocator->vk_command_pool, NULL));
|
||||
|
||||
|
@ -1796,6 +1820,7 @@ static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allo
|
|||
VkCommandPoolCreateInfo command_pool_info;
|
||||
VkResult vr;
|
||||
HRESULT hr;
|
||||
size_t i;
|
||||
|
||||
if (FAILED(hr = vkd3d_private_store_init(&allocator->private_store)))
|
||||
return hr;
|
||||
|
@ -1815,12 +1840,34 @@ static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allo
|
|||
command_pool_info.flags = 0;
|
||||
command_pool_info.queueFamilyIndex = queue_family->vk_family_index;
|
||||
|
||||
if ((vr = VK_CALL(vkCreateCommandPool(device->vk_device, &command_pool_info, NULL,
|
||||
&allocator->vk_command_pool))) < 0)
|
||||
allocator->vk_command_pool = VK_NULL_HANDLE;
|
||||
allocator->vk_family_index = queue_family->vk_family_index;
|
||||
|
||||
/* Try to recycle command allocators. Some games spam free/allocate pools. */
|
||||
if (pthread_mutex_lock(&device->mutex) == 0)
|
||||
{
|
||||
WARN("Failed to create Vulkan command pool, vr %d.\n", vr);
|
||||
vkd3d_private_store_destroy(&allocator->private_store);
|
||||
return hresult_from_vk_result(vr);
|
||||
for (i = 0; i < device->cached_command_allocator_count; i++)
|
||||
{
|
||||
if (device->cached_command_allocators[i].vk_family_index == queue_family->vk_family_index)
|
||||
{
|
||||
allocator->vk_command_pool = device->cached_command_allocators[i].vk_command_pool;
|
||||
device->cached_command_allocators[i] =
|
||||
device->cached_command_allocators[--device->cached_command_allocator_count];
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
}
|
||||
|
||||
if (allocator->vk_command_pool == VK_NULL_HANDLE)
|
||||
{
|
||||
if ((vr = VK_CALL(vkCreateCommandPool(device->vk_device, &command_pool_info, NULL,
|
||||
&allocator->vk_command_pool))) < 0)
|
||||
{
|
||||
WARN("Failed to create Vulkan command pool, vr %d.\n", vr);
|
||||
vkd3d_private_store_destroy(&allocator->private_store);
|
||||
return hresult_from_vk_result(vr);
|
||||
}
|
||||
}
|
||||
|
||||
memset(allocator->descriptor_pool_caches, 0, sizeof(allocator->descriptor_pool_caches));
|
||||
|
|
|
@ -2717,6 +2717,9 @@ static void d3d12_device_destroy(struct d3d12_device *device)
|
|||
for (i = 0; i < device->query_pool_count; i++)
|
||||
d3d12_device_destroy_query_pool(device, &device->query_pools[i]);
|
||||
|
||||
for (i = 0; i < device->cached_command_allocator_count; i++)
|
||||
VK_CALL(vkDestroyCommandPool(device->vk_device, device->cached_command_allocators[i].vk_command_pool, NULL));
|
||||
|
||||
vkd3d_free(device->descriptor_heap_gpu_vas);
|
||||
|
||||
vkd3d_private_store_destroy(&device->private_store);
|
||||
|
|
|
@ -1773,6 +1773,7 @@ struct d3d12_command_allocator
|
|||
|
||||
D3D12_COMMAND_LIST_TYPE type;
|
||||
VkQueueFlags vk_queue_flags;
|
||||
uint32_t vk_family_index;
|
||||
|
||||
VkCommandPool vk_command_pool;
|
||||
|
||||
|
@ -2881,6 +2882,13 @@ struct vkd3d_queue_family_info
|
|||
VkQueueFlags vk_queue_flags;
|
||||
};
|
||||
|
||||
#define VKD3D_CACHED_COMMAND_ALLOCATOR_COUNT 8
|
||||
struct vkd3d_cached_command_allocator
|
||||
{
|
||||
VkCommandPool vk_command_pool;
|
||||
uint32_t vk_family_index;
|
||||
};
|
||||
|
||||
/* ID3D12Device */
|
||||
typedef ID3D12Device9 d3d12_device_iface;
|
||||
|
||||
|
@ -2931,6 +2939,9 @@ struct d3d12_device
|
|||
struct vkd3d_query_pool query_pools[VKD3D_VIRTUAL_QUERY_POOL_COUNT];
|
||||
size_t query_pool_count;
|
||||
|
||||
struct vkd3d_cached_command_allocator cached_command_allocators[VKD3D_CACHED_COMMAND_ALLOCATOR_COUNT];
|
||||
size_t cached_command_allocator_count;
|
||||
|
||||
uint32_t *descriptor_heap_gpu_vas;
|
||||
size_t descriptor_heap_gpu_va_count;
|
||||
size_t descriptor_heap_gpu_va_size;
|
||||
|
|
Loading…
Reference in New Issue