vkd3d: Add code to create, destroy and recycle scratch buffers.
Command lists may need to allocate temporary device memory for certain operations. In order to avoid frequent alloc/free calls, we'll recycle these scratch buffers until a certain threshold. Signed-off-by: Philip Rebohle <philip.rebohle@tu-dortmund.de>
This commit is contained in:
parent
c0b34fdb7b
commit
afb85c79cd
|
@ -1492,6 +1492,10 @@ static ULONG STDMETHODCALLTYPE d3d12_command_allocator_Release(ID3D12CommandAllo
|
|||
vkd3d_free(allocator->command_buffers);
|
||||
VK_CALL(vkDestroyCommandPool(device->vk_device, allocator->vk_command_pool, NULL));
|
||||
|
||||
for (i = 0; i < allocator->scratch_buffer_count; i++)
|
||||
d3d12_device_return_scratch_buffer(device, &allocator->scratch_buffers[i]);
|
||||
|
||||
vkd3d_free(allocator->scratch_buffers);
|
||||
vkd3d_free(allocator);
|
||||
|
||||
d3d12_device_release(device);
|
||||
|
@ -1557,6 +1561,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_Reset(ID3D12CommandAllo
|
|||
struct d3d12_device *device;
|
||||
LONG pending;
|
||||
VkResult vr;
|
||||
size_t i;
|
||||
|
||||
TRACE("iface %p.\n", iface);
|
||||
|
||||
|
@ -1606,6 +1611,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_Reset(ID3D12CommandAllo
|
|||
return hresult_from_vk_result(vr);
|
||||
}
|
||||
|
||||
/* Return scratch buffers to the device */
|
||||
for (i = 0; i < allocator->scratch_buffer_count; i++)
|
||||
d3d12_device_return_scratch_buffer(device, &allocator->scratch_buffers[i]);
|
||||
|
||||
allocator->scratch_buffer_count = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1711,6 +1721,10 @@ static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allo
|
|||
allocator->command_buffers_size = 0;
|
||||
allocator->command_buffer_count = 0;
|
||||
|
||||
allocator->scratch_buffers = NULL;
|
||||
allocator->scratch_buffers_size = 0;
|
||||
allocator->scratch_buffer_count = 0;
|
||||
|
||||
allocator->current_command_list = NULL;
|
||||
|
||||
d3d12_device_add_ref(allocator->device = device);
|
||||
|
@ -1746,6 +1760,62 @@ HRESULT d3d12_command_allocator_create(struct d3d12_device *device,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
struct vkd3d_scratch_allocation
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceSize offset;
|
||||
VkDeviceAddress va;
|
||||
};
|
||||
|
||||
static bool d3d12_command_allocator_allocate_scratch_memory(struct d3d12_command_allocator *allocator,
|
||||
VkDeviceSize size, VkDeviceSize alignment, struct vkd3d_scratch_allocation *allocation)
|
||||
{
|
||||
VkDeviceSize aligned_offset, aligned_size;
|
||||
struct vkd3d_scratch_buffer *scratch;
|
||||
unsigned int i;
|
||||
|
||||
aligned_size = align(size, alignment);
|
||||
|
||||
/* Probe last block first since the others are likely full */
|
||||
for (i = allocator->scratch_buffer_count; i; i--)
|
||||
{
|
||||
scratch = &allocator->scratch_buffers[i - 1];
|
||||
aligned_offset = align(scratch->offset, alignment);
|
||||
|
||||
if (aligned_offset + aligned_size <= scratch->size)
|
||||
{
|
||||
scratch->offset = aligned_offset + aligned_size;
|
||||
|
||||
allocation->buffer = scratch->vk_buffer;
|
||||
allocation->offset = aligned_offset;
|
||||
allocation->va = scratch->va + aligned_offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vkd3d_array_reserve((void**)&allocator->scratch_buffers, &allocator->scratch_buffers_size,
|
||||
allocator->scratch_buffer_count + 1, sizeof(*allocator->scratch_buffers)))
|
||||
{
|
||||
ERR("Failed to allocate scratch buffer.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
scratch = &allocator->scratch_buffers[allocator->scratch_buffer_count];
|
||||
if (FAILED(d3d12_device_get_scratch_buffer(allocator->device, aligned_size, scratch)))
|
||||
{
|
||||
ERR("Failed to create scratch buffer.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
allocator->scratch_buffer_count += 1;
|
||||
scratch->offset = aligned_size;
|
||||
|
||||
allocation->buffer = scratch->vk_buffer;
|
||||
allocation->offset = 0;
|
||||
allocation->va = scratch->va;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ID3D12CommandList */
|
||||
static inline struct d3d12_command_list *impl_from_ID3D12GraphicsCommandList(d3d12_command_list_iface *iface)
|
||||
{
|
||||
|
|
|
@ -2256,6 +2256,98 @@ static void d3d12_remove_device_singleton(LUID luid)
|
|||
}
|
||||
}
|
||||
|
||||
static HRESULT d3d12_device_create_scratch_buffer(struct d3d12_device *device, VkDeviceSize size, struct vkd3d_scratch_buffer *scratch)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||
VkDeviceMemory vk_memory = VK_NULL_HANDLE;
|
||||
VkBuffer vk_buffer = VK_NULL_HANDLE;
|
||||
D3D12_RESOURCE_DESC resource_desc;
|
||||
D3D12_HEAP_PROPERTIES heap_desc;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("device %p, size %llu, scratch %p.\n", device, size, scratch);
|
||||
|
||||
memset(&heap_desc, 0, sizeof(heap_desc));
|
||||
heap_desc.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
|
||||
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resource_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||
resource_desc.Width = size;
|
||||
resource_desc.Height = 1;
|
||||
resource_desc.DepthOrArraySize = 1;
|
||||
resource_desc.MipLevels = 1;
|
||||
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resource_desc.SampleDesc.Count = 1;
|
||||
resource_desc.SampleDesc.Quality = 0;
|
||||
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
if (FAILED(hr = vkd3d_create_buffer(device, &heap_desc, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, &resource_desc, &vk_buffer)))
|
||||
return hr;
|
||||
|
||||
if (FAILED(hr = vkd3d_allocate_buffer_memory(device, vk_buffer, NULL,
|
||||
&heap_desc, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, &vk_memory, NULL, NULL)))
|
||||
{
|
||||
VK_CALL(vkDestroyBuffer(device->vk_device, vk_buffer, NULL));
|
||||
return hr;
|
||||
}
|
||||
|
||||
scratch->vk_buffer = vk_buffer;
|
||||
scratch->vk_memory = vk_memory;
|
||||
scratch->size = size;
|
||||
scratch->offset = 0;
|
||||
scratch->va = device->device_info.buffer_device_address_features.bufferDeviceAddress
|
||||
? vkd3d_get_buffer_device_address(device, vk_buffer) : 0ull;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void d3d12_device_destroy_scratch_buffer(struct d3d12_device *device, const struct vkd3d_scratch_buffer *scratch)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||
|
||||
TRACE("device %p, scratch %p.\n", device, scratch);
|
||||
|
||||
VK_CALL(vkFreeMemory(device->vk_device, scratch->vk_memory, NULL));
|
||||
VK_CALL(vkDestroyBuffer(device->vk_device, scratch->vk_buffer, NULL));
|
||||
}
|
||||
|
||||
HRESULT d3d12_device_get_scratch_buffer(struct d3d12_device *device, VkDeviceSize min_size, struct vkd3d_scratch_buffer *scratch)
|
||||
{
|
||||
if (min_size > VKD3D_SCRATCH_BUFFER_SIZE)
|
||||
return d3d12_device_create_scratch_buffer(device, min_size, scratch);
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
if (device->scratch_buffer_count)
|
||||
{
|
||||
*scratch = device->scratch_buffers[--device->scratch_buffer_count];
|
||||
scratch->offset = 0;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
return d3d12_device_create_scratch_buffer(device, VKD3D_SCRATCH_BUFFER_SIZE, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void d3d12_device_return_scratch_buffer(struct d3d12_device *device, const struct vkd3d_scratch_buffer *scratch)
|
||||
{
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
if (scratch->size == VKD3D_SCRATCH_BUFFER_SIZE && device->scratch_buffer_count < VKD3D_SCRATCH_BUFFER_COUNT)
|
||||
{
|
||||
device->scratch_buffers[device->scratch_buffer_count++] = *scratch;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
d3d12_device_destroy_scratch_buffer(device, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
/* ID3D12Device */
|
||||
static inline struct d3d12_device *impl_from_ID3D12Device(d3d12_device_iface *iface)
|
||||
{
|
||||
|
@ -2301,6 +2393,10 @@ static ULONG STDMETHODCALLTYPE d3d12_device_AddRef(d3d12_device_iface *iface)
|
|||
static void d3d12_device_destroy(struct d3d12_device *device)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < device->scratch_buffer_count; i++)
|
||||
d3d12_device_destroy_scratch_buffer(device, &device->scratch_buffers[i]);
|
||||
|
||||
vkd3d_private_store_destroy(&device->private_store);
|
||||
|
||||
|
|
|
@ -1108,6 +1108,18 @@ enum vkd3d_descriptor_pool_types
|
|||
VKD3D_DESCRIPTOR_POOL_TYPE_COUNT
|
||||
};
|
||||
|
||||
#define VKD3D_SCRATCH_BUFFER_SIZE (1ull << 20)
|
||||
#define VKD3D_SCRATCH_BUFFER_COUNT (32u)
|
||||
|
||||
struct vkd3d_scratch_buffer
|
||||
{
|
||||
VkBuffer vk_buffer;
|
||||
VkDeviceMemory vk_memory;
|
||||
VkDeviceSize size;
|
||||
VkDeviceSize offset;
|
||||
VkDeviceAddress va;
|
||||
};
|
||||
|
||||
/* ID3D12CommandAllocator */
|
||||
struct d3d12_command_allocator
|
||||
{
|
||||
|
@ -1141,6 +1153,10 @@ struct d3d12_command_allocator
|
|||
size_t command_buffers_size;
|
||||
size_t command_buffer_count;
|
||||
|
||||
struct vkd3d_scratch_buffer *scratch_buffers;
|
||||
size_t scratch_buffers_size;
|
||||
size_t scratch_buffer_count;
|
||||
|
||||
LONG outstanding_submissions_count;
|
||||
|
||||
struct d3d12_command_list *current_command_list;
|
||||
|
@ -1955,6 +1971,9 @@ struct d3d12_device
|
|||
struct vkd3d_private_store private_store;
|
||||
struct d3d12_caps d3d12_caps;
|
||||
|
||||
struct vkd3d_scratch_buffer scratch_buffers[VKD3D_SCRATCH_BUFFER_COUNT];
|
||||
size_t scratch_buffer_count;
|
||||
|
||||
HRESULT removed_reason;
|
||||
|
||||
const struct vkd3d_format *depth_stencil_formats;
|
||||
|
@ -1978,6 +1997,9 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
|
|||
const char *message, ...) VKD3D_PRINTF_FUNC(3, 4);
|
||||
struct d3d12_device *unsafe_impl_from_ID3D12Device(d3d12_device_iface *iface);
|
||||
|
||||
HRESULT d3d12_device_get_scratch_buffer(struct d3d12_device *device, VkDeviceSize min_size, struct vkd3d_scratch_buffer *scratch);
|
||||
void d3d12_device_return_scratch_buffer(struct d3d12_device *device, const struct vkd3d_scratch_buffer *scratch);
|
||||
|
||||
static inline HRESULT d3d12_device_query_interface(struct d3d12_device *device, REFIID iid, void **object)
|
||||
{
|
||||
return ID3D12Device6_QueryInterface(&device->ID3D12Device_iface, iid, object);
|
||||
|
|
Loading…
Reference in New Issue