From 2afe25c0c81d7fac83ac0f9ab63c00f3817869a6 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Mon, 22 Feb 2021 13:38:56 +0100 Subject: [PATCH] vkd3d: Implement GetRaytracingAccelerationStructurePrebuildInfo. Signed-off-by: Hans-Kristian Arntzen --- libs/vkd3d/acceleration_structure.c | 179 ++++++++++++++++++++++++++++ libs/vkd3d/device.c | 38 +++++- libs/vkd3d/meson.build | 1 + libs/vkd3d/vkd3d_private.h | 23 ++++ libs/vkd3d/vulkan_procs.h | 3 + 5 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 libs/vkd3d/acceleration_structure.c diff --git a/libs/vkd3d/acceleration_structure.c b/libs/vkd3d/acceleration_structure.c new file mode 100644 index 00000000..9452f136 --- /dev/null +++ b/libs/vkd3d/acceleration_structure.c @@ -0,0 +1,179 @@ +/* + * Copyright 2021 Hans-Kristian Arntzen for Valve Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API +#include "vkd3d_private.h" + +void vkd3d_acceleration_structure_build_info_cleanup( + struct vkd3d_acceleration_structure_build_info *info) +{ + if (info->primitive_counts != info->primitive_counts_stack) + vkd3d_free(info->primitive_counts); + if (info->geometries != info->geometries_stack) + vkd3d_free(info->geometries); + if (info->build_range_ptrs != info->build_range_ptr_stack) + vkd3d_free(info->build_range_ptrs); + if (info->build_ranges != info->build_range_stack) + vkd3d_free(info->build_ranges); +} + +static VkBuildAccelerationStructureFlagsKHR d3d12_build_flags_to_vk( + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS flags) +{ + VkBuildAccelerationStructureFlagsKHR vk_flags = 0; + + if (flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION) + vk_flags |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR; + if (flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE) + vk_flags |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; + if (flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY) + vk_flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + if (flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD) + vk_flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + if (flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE) + vk_flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + + return vk_flags; +} + +bool vkd3d_acceleration_structure_convert_inputs( + struct vkd3d_acceleration_structure_build_info *info, + const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *desc) +{ + VkAccelerationStructureGeometryTrianglesDataKHR *triangles; + VkAccelerationStructureBuildGeometryInfoKHR *build_info; + VkAccelerationStructureGeometryAabbsDataKHR *aabbs; + const D3D12_RAYTRACING_GEOMETRY_DESC *geom_desc; + unsigned int i; + + build_info = &info->build_info; + memset(build_info, 0, sizeof(*build_info)); + build_info->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + + if (desc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) + build_info->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + else + build_info->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + + build_info->flags = d3d12_build_flags_to_vk(desc->Flags); + + if (desc->Flags & D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE) + build_info->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; + else + build_info->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + + info->geometries = info->geometries_stack; + info->primitive_counts = info->primitive_counts_stack; + info->build_ranges = info->build_range_stack; + info->build_range_ptrs = info->build_range_ptr_stack; + + if (desc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) + { + memset(info->geometries, 0, sizeof(*info->geometries)); + info->geometries[0].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + info->geometries[0].geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + info->geometries[0].geometry.instances.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + info->geometries[0].geometry.instances.arrayOfPointers = + desc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS ? VK_TRUE : VK_FALSE; + info->geometries[0].geometry.instances.data.deviceAddress = desc->InstanceDescs; + + info->primitive_counts = info->primitive_counts_stack; + info->primitive_counts[0] = desc->NumDescs; + build_info->geometryCount = 1; + } + else + { + if (desc->NumDescs <= VKD3D_BUILD_INFO_STACK_COUNT) + { + memset(info->geometries, 0, sizeof(*info->geometries) * desc->NumDescs); + memset(info->primitive_counts, 0, sizeof(*info->primitive_counts) * desc->NumDescs); + } + else + { + info->geometries = vkd3d_calloc(desc->NumDescs, sizeof(*info->geometries)); + info->primitive_counts = vkd3d_calloc(desc->NumDescs, sizeof(*info->primitive_counts)); + info->build_ranges = vkd3d_malloc(desc->NumDescs * sizeof(*info->build_ranges)); + info->build_range_ptrs = vkd3d_malloc(desc->NumDescs * sizeof(*info->build_range_ptrs)); + } + build_info->geometryCount = desc->NumDescs; + + for (i = 0; i < desc->NumDescs; i++) + { + info->geometries[i].sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + + if (desc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) + geom_desc = desc->ppGeometryDescs[i]; + else + geom_desc = &desc->pGeometryDescs[i]; + + switch (geom_desc->Type) + { + case D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES: + info->geometries[i].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + triangles = &info->geometries[i].geometry.triangles; + triangles->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + triangles->indexData.deviceAddress = geom_desc->Triangles.IndexBuffer; + if (geom_desc->Triangles.IndexBuffer) + { + triangles->indexType = + geom_desc->Triangles.IndexFormat == DXGI_FORMAT_R16_UINT ? + VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; + info->primitive_counts[i] = geom_desc->Triangles.IndexCount / 3; + } + else + { + info->primitive_counts[i] = geom_desc->Triangles.VertexCount / 3; + triangles->indexType = VK_INDEX_TYPE_NONE_KHR; + } + + triangles->maxVertex = max(1, geom_desc->Triangles.VertexCount) - 1; + triangles->vertexStride = geom_desc->Triangles.VertexBuffer.StrideInBytes; + triangles->vertexFormat = vkd3d_get_vk_format(geom_desc->Triangles.VertexFormat); + triangles->vertexData.deviceAddress = geom_desc->Triangles.VertexBuffer.StartAddress; + triangles->transformData.deviceAddress = geom_desc->Triangles.Transform3x4; + break; + + case D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS: + info->geometries[i].geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + aabbs = &info->geometries[i].geometry.aabbs; + aabbs->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + aabbs->stride = geom_desc->AABBs.AABBs.StrideInBytes; + aabbs->data.deviceAddress = geom_desc->AABBs.AABBs.StartAddress; + info->primitive_counts[i] = geom_desc->AABBs.AABBCount; + break; + + default: + FIXME("Unsupported geometry type %u.\n", geom_desc->Type); + return false; + } + } + } + + for (i = 0; i < build_info->geometryCount; i++) + { + info->build_range_ptrs[i] = &info->build_ranges[i]; + info->build_ranges[i].primitiveCount = info->primitive_counts[i]; + info->build_ranges[i].firstVertex = 0; + info->build_ranges[i].primitiveOffset = 0; + info->build_ranges[i].transformOffset = 0; + } + + build_info->pGeometries = info->geometries; + return true; +} diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 98b0d576..be0d514f 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -4230,7 +4230,43 @@ static void STDMETHODCALLTYPE d3d12_device_GetRaytracingAccelerationStructurePre const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *desc, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO *info) { - FIXME("iface %p, desc %p, info %p stub!\n", iface, desc, info); + struct d3d12_device *device = impl_from_ID3D12Device(iface); + + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + struct vkd3d_acceleration_structure_build_info build_info; + VkAccelerationStructureBuildSizesInfoKHR size_info; + + TRACE("iface %p, desc %p, info %p!\n", iface, desc, info); + + if (!d3d12_device_supports_ray_tracing_tier_1_0(device)) + { + ERR("Acceleration structure is not supported. Calling this is invalid.\n"); + memset(info, 0, sizeof(*info)); + return; + } + + if (!vkd3d_acceleration_structure_convert_inputs(&build_info, desc)) + { + ERR("Failed to convert inputs.\n"); + memset(info, 0, sizeof(*info)); + return; + } + + if (build_info.build_info.mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) + FIXME("MODE_UPDATE_KHR in PrebuildInfo?\n"); + + memset(&size_info, 0, sizeof(size_info)); + size_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + + VK_CALL(vkGetAccelerationStructureBuildSizesKHR(device->vk_device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &build_info.build_info, + build_info.primitive_counts, &size_info)); + + vkd3d_acceleration_structure_build_info_cleanup(&build_info); + + info->ResultDataMaxSizeInBytes = size_info.accelerationStructureSize; + info->ScratchDataSizeInBytes = size_info.buildScratchSize; + info->UpdateScratchDataSizeInBytes = size_info.updateScratchSize; } static D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS STDMETHODCALLTYPE d3d12_device_CheckDriverMatchingIdentifier(d3d12_device_iface *iface, diff --git a/libs/vkd3d/meson.build b/libs/vkd3d/meson.build index 15f83c4f..1acba030 100644 --- a/libs/vkd3d/meson.build +++ b/libs/vkd3d/meson.build @@ -42,6 +42,7 @@ vkd3d_src = [ 'va_map.c', 'vkd3d_main.c', 'raytracing_pipeline.c', + 'acceleration_structure.c' ] if enable_d3d12 diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index af10b761..cc62bd87 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -2672,6 +2672,29 @@ struct vkd3d_view_key struct vkd3d_view *vkd3d_view_map_create_view(struct vkd3d_view_map *view_map, struct d3d12_device *device, const struct vkd3d_view_key *key); +/* Acceleration structure helpers. */ +struct vkd3d_acceleration_structure_build_info +{ + /* This is not a hard limit, just an arbitrary value which lets us avoid allocation for + * the common case. */ +#define VKD3D_BUILD_INFO_STACK_COUNT 16 + const struct VkAccelerationStructureBuildRangeInfoKHR *build_range_ptr_stack[VKD3D_BUILD_INFO_STACK_COUNT]; + VkAccelerationStructureBuildRangeInfoKHR build_range_stack[VKD3D_BUILD_INFO_STACK_COUNT]; + VkAccelerationStructureGeometryKHR geometries_stack[VKD3D_BUILD_INFO_STACK_COUNT]; + const VkAccelerationStructureBuildRangeInfoKHR **build_range_ptrs; + uint32_t primitive_counts_stack[VKD3D_BUILD_INFO_STACK_COUNT]; + VkAccelerationStructureBuildRangeInfoKHR *build_ranges; + VkAccelerationStructureBuildGeometryInfoKHR build_info; + VkAccelerationStructureGeometryKHR *geometries; + uint32_t *primitive_counts; +}; + +void vkd3d_acceleration_structure_build_info_cleanup( + struct vkd3d_acceleration_structure_build_info *info); +bool vkd3d_acceleration_structure_convert_inputs( + struct vkd3d_acceleration_structure_build_info *info, + const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *desc); + #define VKD3D_VENDOR_ID_NVIDIA 0x10DE #define VKD3D_VENDOR_ID_AMD 0x1002 #define VKD3D_VENDOR_ID_INTEL 0x8086 diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h index d30677a5..4307f7ac 100644 --- a/libs/vkd3d/vulkan_procs.h +++ b/libs/vkd3d/vulkan_procs.h @@ -205,6 +205,9 @@ VK_DEVICE_EXT_PFN(vkCmdSetRayTracingPipelineStackSizeKHR) VK_DEVICE_EXT_PFN(vkCmdTraceRaysKHR) VK_DEVICE_EXT_PFN(vkCmdTraceRaysIndirectKHR) +/* VK_KHR_acceleration_structure */ +VK_DEVICE_EXT_PFN(vkGetAccelerationStructureBuildSizesKHR) + /* VK_KHR_fragment_shading_rate */ VK_INSTANCE_PFN(vkGetPhysicalDeviceFragmentShadingRatesKHR) VK_DEVICE_EXT_PFN(vkCmdSetFragmentShadingRateKHR)