mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-09-12 18:50:22 -07:00
libs/vkd3d: Allocate GPU virtual addresses for resources.
Direct3D 12 resources, buffers in particular, are bound to the pipeline by their GPU virtual address. In Vulkan, these addresses are not visible to the application. We previously handled this by returning the VkBuffer handle as virtual address, but this can't work when the application binds anything other than the resource's base GPU VA. Instead, we allocate ranges of GPU address space and associate resources with it. This uses the (naive) approach of simply allocating subsequent ranges, and never reclaiming them. Eventually we'll have to revisit that.
This commit is contained in:
@@ -480,6 +480,75 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
|
||||
size_t size, void *ptr)
|
||||
{
|
||||
D3D12_GPU_VIRTUAL_ADDRESS ceiling = ~(D3D12_GPU_VIRTUAL_ADDRESS)0;
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!vkd3d_array_reserve((void **)&allocator->allocations, &allocator->allocations_size,
|
||||
allocator->allocation_count + 1, sizeof(*allocator->allocations)))
|
||||
return 0;
|
||||
|
||||
if (size > ceiling || ceiling - size < allocator->floor)
|
||||
return 0;
|
||||
|
||||
allocation = &allocator->allocations[allocator->allocation_count++];
|
||||
allocation->base = allocator->floor;
|
||||
allocation->size = size;
|
||||
allocation->ptr = ptr;
|
||||
|
||||
allocator->floor += size;
|
||||
|
||||
return allocation->base;
|
||||
}
|
||||
|
||||
static int vkd3d_gpu_va_allocation_compare(const void *k, const void *e)
|
||||
{
|
||||
const struct vkd3d_gpu_va_allocation *allocation = e;
|
||||
const D3D12_GPU_VIRTUAL_ADDRESS *address = k;
|
||||
|
||||
if (*address < allocation->base)
|
||||
return -1;
|
||||
if (*address - allocation->base >= allocation->size)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address)
|
||||
{
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!(allocation = bsearch(&address, allocator->allocations, allocator->allocation_count,
|
||||
sizeof(*allocation), vkd3d_gpu_va_allocation_compare)))
|
||||
return NULL;
|
||||
|
||||
return allocation->ptr;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address)
|
||||
{
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!(allocation = bsearch(&address, allocator->allocations, allocator->allocation_count,
|
||||
sizeof(*allocation), vkd3d_gpu_va_allocation_compare)))
|
||||
return;
|
||||
|
||||
if (allocation->base == address)
|
||||
allocation->ptr = NULL;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_init(struct vkd3d_gpu_va_allocator *allocator)
|
||||
{
|
||||
memset(allocator, 0, sizeof(*allocator));
|
||||
allocator->floor = 0x1000;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_cleanup(struct vkd3d_gpu_va_allocator *allocator)
|
||||
{
|
||||
vkd3d_free(allocator->allocations);
|
||||
}
|
||||
|
||||
/* ID3D12Device */
|
||||
static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface)
|
||||
{
|
||||
@@ -527,6 +596,7 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||
|
||||
vkd3d_gpu_va_allocator_cleanup(&device->gpu_va_allocator);
|
||||
vkd3d_fence_worker_stop(&device->fence_worker);
|
||||
VK_CALL(vkDestroyDevice(device->vk_device, NULL));
|
||||
vkd3d_instance_destroy(&device->vkd3d_instance);
|
||||
@@ -1270,6 +1340,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
|
||||
return hr;
|
||||
}
|
||||
|
||||
vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user