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:
Henri Verbeet
2017-07-25 01:56:16 +02:00
parent 1acd3d44b1
commit 605a02274e
4 changed files with 124 additions and 13 deletions

View File

@@ -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;
}