vkd3d: Implement RTAS object creation.

When building acceleration structures, we need to have an
VkAccelerationStructureKHR object, but the D3D12 API just uses a plain
VA = ID3D12Resource::GetGPUVA() + offset.

For this to work, we need to resolve the VA back to VkBuffer + offset.
The only VkBuffer we can lookup is the original backing memory
allocation in the VA map, and that allocation itself must own a view
map, since we cannot tie the VA to any specific ID3D12Resource.

Since creating an RTAS is not the common path, we allocate the view map
on-demand with CAS.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2021-02-22 14:44:21 +01:00
parent 0fc80d9067
commit 3353ed14de
5 changed files with 163 additions and 8 deletions

View File

@ -279,6 +279,12 @@ static void vkd3d_memory_allocation_free(const struct vkd3d_memory_allocation *a
vkd3d_va_map_free_fake_va(&allocator->va_map, allocation->resource.va, allocation->resource.size);
}
if (allocation->resource.view_map)
{
vkd3d_view_map_destroy(allocation->resource.view_map, device);
vkd3d_free(allocation->resource.view_map);
}
if (allocation->flags & VKD3D_ALLOCATION_FLAG_GLOBAL_BUFFER)
VK_CALL(vkDestroyBuffer(device->vk_device, allocation->resource.vk_buffer, NULL));

View File

@ -585,6 +585,7 @@ static uint32_t vkd3d_view_entry_hash(const void *key)
switch (k->view_type)
{
case VKD3D_VIEW_TYPE_BUFFER:
case VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE:
hash = hash_uint64((uint64_t)k->u.buffer.buffer);
hash = hash_combine(hash, hash_uint64(k->u.buffer.offset));
hash = hash_combine(hash, hash_uint64(k->u.buffer.size));
@ -645,6 +646,7 @@ static bool vkd3d_view_entry_compare(const void *key, const struct hash_map_entr
switch (k->view_type)
{
case VKD3D_VIEW_TYPE_BUFFER:
case VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE:
return k->u.buffer.buffer == e->key.u.buffer.buffer &&
k->u.buffer.format == e->key.u.buffer.format &&
k->u.buffer.offset == e->key.u.buffer.offset &&
@ -753,6 +755,10 @@ struct vkd3d_view *vkd3d_view_map_create_view(struct vkd3d_view_map *view_map,
SUCCEEDED(d3d12_create_sampler(device, &key->u.sampler, &view->vk_sampler));
break;
case VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE:
success = vkd3d_create_acceleration_structure_view(device, &key->u.buffer, &view);
break;
default:
ERR("Unsupported view type %u.\n", key->view_type);
success = false;
@ -2660,6 +2666,9 @@ static void vkd3d_view_destroy(struct vkd3d_view *view, struct d3d12_device *dev
case VKD3D_VIEW_TYPE_SAMPLER:
VK_CALL(vkDestroySampler(device->vk_device, view->vk_sampler, NULL));
break;
case VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE:
VK_CALL(vkDestroyAccelerationStructureKHR(device->vk_device, view->vk_acceleration_structure, NULL));
break;
default:
WARN("Unhandled view type %d.\n", view->type);
}
@ -2947,6 +2956,57 @@ bool vkd3d_create_buffer_view(struct d3d12_device *device, const struct vkd3d_bu
return true;
}
bool vkd3d_create_acceleration_structure_view(struct d3d12_device *device, const struct vkd3d_buffer_view_desc *desc,
struct vkd3d_view **view)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VkAccelerationStructureKHR vk_acceleration_structure;
VkAccelerationStructureCreateInfoKHR create_info;
VkDeviceAddress buffer_address;
VkDeviceAddress rtas_address;
struct vkd3d_view *object;
VkResult vr;
create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
create_info.pNext = NULL;
create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR;
create_info.createFlags = 0;
create_info.deviceAddress = 0;
create_info.buffer = desc->buffer;
create_info.offset = desc->offset;
create_info.size = desc->size;
vr = VK_CALL(vkCreateAccelerationStructureKHR(device->vk_device, &create_info, NULL, &vk_acceleration_structure));
if (vr != VK_SUCCESS)
return false;
if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE)))
{
VK_CALL(vkDestroyAccelerationStructureKHR(device->vk_device, vk_acceleration_structure, NULL));
return false;
}
/* Sanity check. Spec should guarantee this.
* There is a note in the spec for vkGetAccelerationStructureDeviceAddressKHR:
* The acceleration structure device address may be different from the
* buffer device address corresponding to the acceleration structure's
* start offset in its storage buffer for acceleration structure types
* other than VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR. */
buffer_address = vkd3d_get_buffer_device_address(device, desc->buffer) + desc->offset;
rtas_address = vkd3d_get_acceleration_structure_device_address(device, vk_acceleration_structure);
if (buffer_address != rtas_address)
{
FIXME("buffer_address = 0x%"PRIx64", rtas_address = 0x%"PRIx64".\n", buffer_address, rtas_address);
}
object->vk_acceleration_structure = vk_acceleration_structure;
object->format = desc->format;
object->info.buffer.offset = desc->offset;
object->info.buffer.size = desc->size;
*view = object;
return true;
}
#define VKD3D_VIEW_RAW_BUFFER 0x1
static bool vkd3d_create_buffer_view_for_resource(struct d3d12_device *device,
@ -3755,6 +3815,19 @@ VkDeviceAddress vkd3d_get_buffer_device_address(struct d3d12_device *device, VkB
return VK_CALL(vkGetBufferDeviceAddressKHR(device->vk_device, &address_info));
}
VkDeviceAddress vkd3d_get_acceleration_structure_device_address(struct d3d12_device *device,
VkAccelerationStructureKHR vk_acceleration_structure)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VkAccelerationStructureDeviceAddressInfoKHR address_info;
address_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
address_info.pNext = NULL;
address_info.accelerationStructure = vk_acceleration_structure;
return VK_CALL(vkGetAccelerationStructureDeviceAddressKHR(device->vk_device, &address_info));
}
static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_device *device,
struct d3d12_resource *resource, struct d3d12_resource *counter_resource,
const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc)

View File

@ -92,16 +92,16 @@ static void vkd3d_va_map_cleanup_tree(struct vkd3d_va_tree *tree)
}
}
static const struct vkd3d_unique_resource *vkd3d_va_map_find_small_entry(struct vkd3d_va_map *va_map,
static struct vkd3d_unique_resource *vkd3d_va_map_find_small_entry(struct vkd3d_va_map *va_map,
VkDeviceAddress va, size_t *index)
{
const struct vkd3d_unique_resource *resource = NULL;
struct vkd3d_unique_resource *resource = NULL;
size_t hi = va_map->small_entries_count;
size_t lo = 0;
while (lo < hi)
{
const struct vkd3d_unique_resource *r;
struct vkd3d_unique_resource *r;
size_t i = lo + (hi - lo) / 2;
r = va_map->small_entries[i];
@ -123,7 +123,7 @@ static const struct vkd3d_unique_resource *vkd3d_va_map_find_small_entry(struct
return resource;
}
void vkd3d_va_map_insert(struct vkd3d_va_map *va_map, const struct vkd3d_unique_resource *resource)
void vkd3d_va_map_insert(struct vkd3d_va_map *va_map, struct vkd3d_unique_resource *resource)
{
VkDeviceAddress block_va, min_va, max_va;
struct vkd3d_va_block *block;
@ -219,10 +219,10 @@ void vkd3d_va_map_remove(struct vkd3d_va_map *va_map, const struct vkd3d_unique_
}
}
const struct vkd3d_unique_resource *vkd3d_va_map_deref(struct vkd3d_va_map *va_map, VkDeviceAddress va)
static struct vkd3d_unique_resource *vkd3d_va_map_deref_mutable(struct vkd3d_va_map *va_map, VkDeviceAddress va)
{
const struct vkd3d_va_block *block = vkd3d_va_map_find_block(va_map, va);
const struct vkd3d_unique_resource *resource = NULL;
struct vkd3d_unique_resource *resource = NULL;
if (block)
{
@ -242,6 +242,64 @@ const struct vkd3d_unique_resource *vkd3d_va_map_deref(struct vkd3d_va_map *va_m
return resource;
}
const struct vkd3d_unique_resource *vkd3d_va_map_deref(struct vkd3d_va_map *va_map, VkDeviceAddress va)
{
return vkd3d_va_map_deref_mutable(va_map, va);
}
VkAccelerationStructureKHR vkd3d_va_map_place_acceleration_structure(struct vkd3d_va_map *va_map,
struct d3d12_device *device,
VkDeviceAddress va)
{
struct vkd3d_unique_resource *resource;
struct vkd3d_view_map *old_view_map;
struct vkd3d_view_map *view_map;
const struct vkd3d_view *view;
struct vkd3d_view_key key;
resource = vkd3d_va_map_deref_mutable(va_map, va);
if (!resource || !resource->va)
return VK_NULL_HANDLE;
view_map = vkd3d_atomic_ptr_load_explicit(&resource->view_map, vkd3d_memory_order_acquire);
if (!view_map)
{
/* This is the first time we attempt to place an AS on top of this allocation, so
* CAS in a pointer. */
view_map = vkd3d_malloc(sizeof(*view_map));
if (!view_map)
return VK_NULL_HANDLE;
if (FAILED(vkd3d_view_map_init(view_map)))
{
vkd3d_free(view_map);
return VK_NULL_HANDLE;
}
/* Need to release in case other RTASes are placed at the same time, so they observe
* the initialized view map, and need to acquire if some other thread placed it. */
old_view_map = vkd3d_atomic_ptr_compare_exchange(&resource->view_map, NULL, view_map,
vkd3d_memory_order_release, vkd3d_memory_order_acquire);
if (old_view_map)
{
vkd3d_view_map_destroy(view_map, device);
vkd3d_free(view_map);
view_map = old_view_map;
}
}
key.view_type = VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE;
key.u.buffer.buffer = resource->vk_buffer;
key.u.buffer.offset = va - resource->va;
key.u.buffer.size = resource->size - key.u.buffer.offset;
key.u.buffer.format = NULL;
view = vkd3d_view_map_create_view(view_map, device, &key);
if (!view)
return VK_NULL_HANDLE;
return view->vk_acceleration_structure;
}
#define VKD3D_FAKE_VA_ALIGNMENT (65536)
VkDeviceAddress vkd3d_va_map_alloc_fake_va(struct vkd3d_va_map *va_map, VkDeviceSize size)

View File

@ -297,14 +297,17 @@ struct vkd3d_va_map
pthread_mutex_t mutex;
const struct vkd3d_unique_resource **small_entries;
struct vkd3d_unique_resource **small_entries;
size_t small_entries_size;
size_t small_entries_count;
};
void vkd3d_va_map_insert(struct vkd3d_va_map *va_map, const struct vkd3d_unique_resource *resource);
void vkd3d_va_map_insert(struct vkd3d_va_map *va_map, struct vkd3d_unique_resource *resource);
void vkd3d_va_map_remove(struct vkd3d_va_map *va_map, const struct vkd3d_unique_resource *resource);
const struct vkd3d_unique_resource *vkd3d_va_map_deref(struct vkd3d_va_map *va_map, VkDeviceAddress va);
VkAccelerationStructureKHR vkd3d_va_map_place_acceleration_structure(struct vkd3d_va_map *va_map,
struct d3d12_device *device,
VkDeviceAddress va);
VkDeviceAddress vkd3d_va_map_alloc_fake_va(struct vkd3d_va_map *va_map, VkDeviceSize size);
void vkd3d_va_map_free_fake_va(struct vkd3d_va_map *va_map, VkDeviceAddress va, VkDeviceSize size);
void vkd3d_va_map_init(struct vkd3d_va_map *va_map);
@ -494,6 +497,8 @@ struct vkd3d_allocate_resource_memory_info
void *host_ptr;
};
struct vkd3d_view_map;
struct vkd3d_unique_resource
{
union
@ -504,6 +509,10 @@ struct vkd3d_unique_resource
uint64_t cookie;
VkDeviceAddress va;
VkDeviceSize size;
/* This is used to handle views when we cannot bind it to a
* specific ID3D12Resource, i.e. RTAS. Only allocated as needed. */
struct vkd3d_view_map *view_map;
};
struct vkd3d_memory_allocation
@ -759,6 +768,7 @@ enum vkd3d_view_type
VKD3D_VIEW_TYPE_BUFFER,
VKD3D_VIEW_TYPE_IMAGE,
VKD3D_VIEW_TYPE_SAMPLER,
VKD3D_VIEW_TYPE_ACCELERATION_STRUCTURE
};
struct vkd3d_view
@ -772,6 +782,7 @@ struct vkd3d_view
VkBufferView vk_buffer_view;
VkImageView vk_image_view;
VkSampler vk_sampler;
VkAccelerationStructureKHR vk_acceleration_structure;
};
const struct vkd3d_format *format;
union
@ -819,6 +830,8 @@ struct vkd3d_texture_view_desc
bool vkd3d_create_buffer_view(struct d3d12_device *device,
const struct vkd3d_buffer_view_desc *desc, struct vkd3d_view **view);
bool vkd3d_create_acceleration_structure_view(struct d3d12_device *device,
const struct vkd3d_buffer_view_desc *desc, struct vkd3d_view **view);
bool vkd3d_create_texture_view(struct d3d12_device *device,
const struct vkd3d_texture_view_desc *desc, struct vkd3d_view **view);
@ -2603,6 +2616,8 @@ static inline unsigned int d3d12_resource_desc_get_sub_resource_count(const D3D1
}
VkDeviceAddress vkd3d_get_buffer_device_address(struct d3d12_device *device, VkBuffer vk_buffer);
VkDeviceAddress vkd3d_get_acceleration_structure_device_address(struct d3d12_device *device,
VkAccelerationStructureKHR vk_acceleration_structure);
static inline VkDeviceAddress d3d12_resource_get_va(const struct d3d12_resource *resource, VkDeviceSize offset)
{

View File

@ -207,6 +207,9 @@ VK_DEVICE_EXT_PFN(vkCmdTraceRaysIndirectKHR)
/* VK_KHR_acceleration_structure */
VK_DEVICE_EXT_PFN(vkGetAccelerationStructureBuildSizesKHR)
VK_DEVICE_EXT_PFN(vkCreateAccelerationStructureKHR)
VK_DEVICE_EXT_PFN(vkDestroyAccelerationStructureKHR)
VK_DEVICE_EXT_PFN(vkGetAccelerationStructureDeviceAddressKHR)
/* VK_KHR_fragment_shading_rate */
VK_INSTANCE_PFN(vkGetPhysicalDeviceFragmentShadingRatesKHR)