diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt
index 8df03e9819..5804960430 100644
--- a/util/test/demos/CMakeLists.txt
+++ b/util/test/demos/CMakeLists.txt
@@ -141,6 +141,7 @@ set(VULKAN_SRC
vk/vk_pixel_history.cpp
vk/vk_postponed.cpp
vk/vk_query_pool.cpp
+ vk/vk_ray_query.cpp
vk/vk_read_before_overwrite.cpp
vk/vk_resource_lifetimes.cpp
vk/vk_robustness2.cpp
diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj
index 9be5d72967..71c4b0ff97 100644
--- a/util/test/demos/demos.vcxproj
+++ b/util/test/demos/demos.vcxproj
@@ -331,6 +331,7 @@
+
diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters
index a5a39d1c99..35bd94d992 100644
--- a/util/test/demos/demos.vcxproj.filters
+++ b/util/test/demos/demos.vcxproj.filters
@@ -694,6 +694,9 @@
D3D12\demos
+
+ Vulkan\demos
+
diff --git a/util/test/demos/vk/vk_headers.h b/util/test/demos/vk/vk_headers.h
index 6ed7d31441..4d955a6dad 100644
--- a/util/test/demos/vk/vk_headers.h
+++ b/util/test/demos/vk/vk_headers.h
@@ -85,8 +85,12 @@
// then include volk
#include "3rdparty/volk/volk.h"
+#if defined(__linux__) && defined(__GLIBCXX__) && defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)
+#define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) aligned_alloc(alignment, size)
+#endif
+
// avoid warning about unused variables
-#define VMA_DEBUG_LOG_FORMAT(format, ...) (void)(__VA_ARGS__);
+#define VMA_DEBUG_LOG_FORMAT(format, ...) (void)(#__VA_ARGS__)
// finally VMA
#include "3rdparty/VulkanMemoryAllocator/vk_mem_alloc.h"
diff --git a/util/test/demos/vk/vk_ray_query.cpp b/util/test/demos/vk/vk_ray_query.cpp
new file mode 100644
index 0000000000..7395baeeb2
--- /dev/null
+++ b/util/test/demos/vk/vk_ray_query.cpp
@@ -0,0 +1,489 @@
+/******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019-2024 Baldur Karlsson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+
+#include "test_common.h"
+#include "vk_test.h"
+
+RD_TEST(VK_Ray_Query, VulkanGraphicsTest)
+{
+ static constexpr const char *Description = "Test capture and replay of VK_KHR_ray_query";
+
+ std::string frag = R"EOSHADER(
+
+#version 460
+#extension GL_EXT_ray_query : enable
+
+layout(location = 0) in vec4 in_scene_pos;
+
+layout(location = 0) out vec4 o_color;
+
+layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
+
+bool intersects_light(vec3 light_origin, vec3 pos)
+{
+ const float tmin = 0.01, tmax = 1000;
+ const vec3 direction = light_origin - pos;
+
+ rayQueryEXT query;
+ rayQueryInitializeEXT(query, topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, pos, tmin, direction.xyz, 1.0);
+ rayQueryProceedEXT(query);
+
+ return rayQueryGetIntersectionTypeEXT(query, true) != gl_RayQueryCommittedIntersectionNoneEXT;
+}
+
+void main(void)
+{
+ vec3 light_pos = vec3(0,0,0);
+ o_color = intersects_light(light_pos, in_scene_pos.xyz) ? vec4(0.6, 0.6, 0.6, 1) : vec4(1, 1, 1, 1);
+}
+
+)EOSHADER";
+
+ std::string vert = R"EOSHADER(
+
+#version 460
+#extension GL_EXT_ray_query : enable
+
+layout(location = 0) in vec3 position;
+
+layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
+
+layout(location = 0) out vec4 scene_pos;
+
+void main(void)
+{
+ gl_Position = scene_pos = vec4(position.xyz, 1.0f);
+}
+
+)EOSHADER";
+
+ void Prepare(int argc, char **argv)
+ {
+ devExts.push_back(VK_KHR_RAY_QUERY_EXTENSION_NAME);
+
+ devExts.push_back(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
+
+ // Required by VK_KHR_acceleration_structure
+ devExts.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
+ devExts.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
+ devExts.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
+
+ // Required for ray queries
+ devExts.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
+
+ // Required by VK_KHR_spirv_1_4
+ devExts.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
+
+ VulkanGraphicsTest::Prepare(argc, argv);
+
+ if(!Avail.empty())
+ return;
+
+ static VkPhysicalDeviceAccelerationStructureFeaturesKHR asFeatures = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
+ getPhysFeatures2(&asFeatures);
+
+ static VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bdaFeatures = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR};
+ getPhysFeatures2(&bdaFeatures);
+
+ static VkPhysicalDeviceRayQueryFeaturesKHR rqFeatures = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
+ getPhysFeatures2(&rqFeatures);
+
+ if(!asFeatures.accelerationStructure)
+ Avail = "Acceleration structure feature 'accelerationStructure' not available";
+ if(!bdaFeatures.bufferDeviceAddress)
+ Avail = "Buffer device address feature 'bufferDeviceAddress' not available";
+ if(!rqFeatures.rayQuery)
+ Avail = "Ray query feature 'rayQuery' not available";
+
+ devInfoNext = &asFeatures;
+ asFeatures.pNext = &bdaFeatures;
+ bdaFeatures.pNext = &rqFeatures;
+ }
+
+ int main()
+ {
+ vmaBDA = true;
+
+ if(!Init())
+ return 3;
+
+ Vec3f vertices[] = {
+ // Triangle below
+ {-0.8f, 0.8f, 0.8f},
+ {0.f, -0.8f, 0.8f},
+ {0.8f, 0.8f, 0.8f},
+
+ // Triangle above
+ {0.0f, 0.3f, 0.5f},
+ {-0.3f, -0.3f, 0.5f},
+ {0.3f, -0.3f, 0.5f},
+ };
+
+ uint32_t indices[] = {0, 1, 2, 3, 4, 5};
+
+ uint32_t primitiveCount = (uint32_t)sizeof(indices) / (sizeof(indices[0]) * 3);
+ uint32_t indexCount = (uint32_t)sizeof(indices) / sizeof(indices[0]);
+ uint32_t vertexCount = (uint32_t)sizeof(vertices) / sizeof(vertices[0]);
+
+ VkFormat vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+
+ constexpr VkBufferUsageFlags blasInputBufferUsageFlags =
+ VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR;
+
+ VkTransformMatrixKHR identityTransformMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+
+ VkTransformMatrixKHR blasTransformMatrix = identityTransformMatrix;
+
+ const size_t vertexBufferSize = vertexCount * sizeof(vertices[0]);
+ const size_t indexBufferSize = indexCount * sizeof(indices[0]);
+
+ AllocatedBuffer blasVertexBuffer(
+ this, vkh::BufferCreateInfo(vertexBufferSize, blasInputBufferUsageFlags),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
+ AllocatedBuffer blasIndexBuffer(
+ this, vkh::BufferCreateInfo(indexBufferSize, blasInputBufferUsageFlags),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
+
+ blasVertexBuffer.upload(vertices, vertexBufferSize);
+ blasIndexBuffer.upload(indices, indexBufferSize);
+
+ /*
+ * Create bottom level acceleration structure
+ */
+ VkAccelerationStructureGeometryKHR blasGeometry = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
+ blasGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ blasGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ blasGeometry.geometry.triangles.sType =
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ blasGeometry.geometry.triangles.vertexFormat = vertexFormat;
+ blasGeometry.geometry.triangles.maxVertex = vertexCount - 1;
+ blasGeometry.geometry.triangles.vertexStride = sizeof(Vec3f);
+ blasGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
+ blasGeometry.geometry.triangles.vertexData.deviceAddress = blasVertexBuffer.address;
+ blasGeometry.geometry.triangles.indexData.deviceAddress = blasIndexBuffer.address;
+ blasGeometry.geometry.triangles.transformData.deviceAddress = 0;
+ std::vector blasGeometries = {blasGeometry};
+
+ VkAccelerationStructureBuildRangeInfoKHR buildRangeInfo = {primitiveCount, 0, 0, 0};
+
+ std::vector asBuildRangeInfosVector = {buildRangeInfo};
+ VkAccelerationStructureBuildRangeInfoKHR *asBuildRangeInfos = asBuildRangeInfosVector.data();
+ std::vector primitiveCounts = {primitiveCount};
+
+ VkAccelerationStructureBuildGeometryInfoKHR blasBuildGeometryInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR};
+ blasBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ blasBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ blasBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
+ blasBuildGeometryInfo.geometryCount = (uint32_t)blasGeometries.size();
+ blasBuildGeometryInfo.pGeometries = blasGeometries.data();
+
+ VkAccelerationStructureBuildSizesInfoKHR blasBuildSizesInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
+ vkGetAccelerationStructureBuildSizesKHR(device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
+ &blasBuildGeometryInfo, primitiveCounts.data(),
+ &blasBuildSizesInfo);
+
+ AllocatedBuffer blasBuffer(
+ this,
+ vkh::BufferCreateInfo(blasBuildSizesInfo.accelerationStructureSize,
+ VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
+
+ VkAccelerationStructureCreateInfoKHR blasCreateInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR};
+ blasCreateInfo.buffer = blasBuffer.buffer;
+ blasCreateInfo.size = blasBuildSizesInfo.accelerationStructureSize;
+ blasCreateInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+
+ VkAccelerationStructureKHR blas;
+ CHECK_VKR(vkCreateAccelerationStructureKHR(device, &blasCreateInfo, VK_NULL_HANDLE, &blas))
+
+ VkAccelerationStructureDeviceAddressInfoKHR blasDeviceAddressInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, NULL, blas};
+ uint64_t blasDeviceAddress =
+ vkGetAccelerationStructureDeviceAddressKHR(device, &blasDeviceAddressInfo);
+
+ AllocatedBuffer blasScratchBuffer(
+ this,
+ vkh::BufferCreateInfo(
+ blasBuildSizesInfo.buildScratchSize,
+ VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
+
+ blasBuildGeometryInfo.scratchData.deviceAddress = blasScratchBuffer.address;
+ blasBuildGeometryInfo.dstAccelerationStructure = blas;
+
+ {
+ VkCommandBuffer cmd = GetCommandBuffer();
+ CHECK_VKR(vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()));
+ vkCmdBuildAccelerationStructuresKHR(cmd, 1, &blasBuildGeometryInfo, &asBuildRangeInfos);
+ CHECK_VKR(vkEndCommandBuffer(cmd));
+ Submit(99, 99, {cmd});
+ }
+
+ /*
+ * Create top level acceleration structure
+ */
+ VkTransformMatrixKHR tlasTransformMatrix = identityTransformMatrix;
+
+ VkAccelerationStructureInstanceKHR asInstance = {
+ tlasTransformMatrix, 0, 0xFF, 0, VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR,
+ blasDeviceAddress,
+ };
+
+ const size_t asInstanceSize = sizeof(asInstance);
+
+ AllocatedBuffer instancesBuffer(
+ this,
+ vkh::BufferCreateInfo(asInstanceSize,
+ VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
+ instancesBuffer.upload(&asInstance, asInstanceSize);
+
+ VkAccelerationStructureGeometryKHR tlasGeometry = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
+ tlasGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ tlasGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ tlasGeometry.geometry.instances.sType =
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ tlasGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
+ tlasGeometry.geometry.instances.data.deviceAddress = instancesBuffer.address;
+
+ std::vector tlasGeometries = {tlasGeometry};
+
+ VkAccelerationStructureBuildGeometryInfoKHR tlasBuildGeometryInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR};
+ tlasBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ tlasBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ tlasBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
+ tlasBuildGeometryInfo.geometryCount = (uint32_t)tlasGeometries.size();
+ tlasBuildGeometryInfo.pGeometries = tlasGeometries.data();
+
+ VkAccelerationStructureBuildSizesInfoKHR tlasBuildSizesInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
+ vkGetAccelerationStructureBuildSizesKHR(device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
+ &tlasBuildGeometryInfo, primitiveCounts.data(),
+ &tlasBuildSizesInfo);
+
+ AllocatedBuffer tlasBuffer(
+ this,
+ vkh::BufferCreateInfo(tlasBuildSizesInfo.accelerationStructureSize,
+ VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
+
+ VkAccelerationStructureCreateInfoKHR tlasCreateInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR};
+ tlasCreateInfo.buffer = tlasBuffer.buffer;
+ tlasCreateInfo.size = tlasBuildSizesInfo.accelerationStructureSize;
+ tlasCreateInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+
+ VkAccelerationStructureKHR tlas;
+ CHECK_VKR(vkCreateAccelerationStructureKHR(device, &tlasCreateInfo, VK_NULL_HANDLE, &tlas));
+
+ AllocatedBuffer tlasScratchBuffer(
+ this,
+ vkh::BufferCreateInfo(
+ tlasBuildSizesInfo.buildScratchSize,
+ VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
+
+ tlasBuildGeometryInfo.scratchData.deviceAddress = tlasScratchBuffer.address;
+ tlasBuildGeometryInfo.dstAccelerationStructure = tlas;
+
+ asBuildRangeInfosVector[0].primitiveCount = 1;
+
+ {
+ VkCommandBuffer cmd = GetCommandBuffer();
+ CHECK_VKR(vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()));
+ vkCmdBuildAccelerationStructuresKHR(cmd, 1, &tlasBuildGeometryInfo, &asBuildRangeInfos);
+ CHECK_VKR(vkEndCommandBuffer(cmd));
+ Submit(99, 99, {cmd});
+ }
+
+ /*
+ * Create a pointless copy for more API coverage
+ */
+ AllocatedBuffer newBlasBuffer(
+ this,
+ vkh::BufferCreateInfo(blasBuildSizesInfo.accelerationStructureSize,
+ VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
+
+ VkAccelerationStructureCreateInfoKHR newBlasCreateInfo = {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR};
+ newBlasCreateInfo.buffer = newBlasBuffer.buffer;
+ newBlasCreateInfo.size = blasBuildSizesInfo.accelerationStructureSize;
+ newBlasCreateInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+
+ VkAccelerationStructureKHR newBlas;
+ CHECK_VKR(vkCreateAccelerationStructureKHR(device, &newBlasCreateInfo, VK_NULL_HANDLE, &newBlas))
+
+ /*
+ * Create triangle draw buffers
+ */
+ AllocatedBuffer trisVertexBuffer(
+ this,
+ vkh::BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
+ AllocatedBuffer trisIndexBuffer(
+ this,
+ vkh::BufferCreateInfo(
+ indexBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
+ VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
+
+ trisVertexBuffer.upload(vertices);
+ trisIndexBuffer.upload(indices);
+
+ /*
+ * Create descriptor set layout
+ */
+ std::vector descriptorSetLayoutBindings = {
+ {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT}};
+ VkDescriptorSetLayout descriptorSetLayout =
+ createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo(descriptorSetLayoutBindings));
+
+ /*
+ * Prepare pipelines
+ */
+ vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
+
+ VkPipelineLayout layout =
+ createPipelineLayout(vkh::PipelineLayoutCreateInfo{{descriptorSetLayout}});
+ pipeCreateInfo.layout = layout;
+
+ pipeCreateInfo.renderPass = mainWindow->rp;
+
+ pipeCreateInfo.stages = {
+ CompileShaderModule(vert, ShaderLang::glsl, ShaderStage::vert, "main"),
+ CompileShaderModule(frag, ShaderLang::glsl, ShaderStage::frag, "main"),
+ };
+
+ pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, Vec3f)};
+ pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = {
+ {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
+ };
+
+ pipeCreateInfo.depthStencilState.depthBoundsTestEnable = VK_FALSE;
+
+ VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo);
+
+ /*
+ * Create descriptor sets
+ */
+ VkDescriptorSet descriptorSet = allocateDescriptorSet(descriptorSetLayout);
+
+ VkWriteDescriptorSetAccelerationStructureKHR asWriteDescriptorInfo = {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
+ NULL,
+ 1,
+ &tlas,
+ };
+
+ VkWriteDescriptorSet asWriteDescriptorSet = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
+ asWriteDescriptorSet.dstSet = descriptorSet;
+ asWriteDescriptorSet.dstBinding = 0;
+ asWriteDescriptorSet.descriptorCount = 1;
+ asWriteDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ asWriteDescriptorSet.pNext = &asWriteDescriptorInfo;
+
+ vkh::updateDescriptorSets(device, {asWriteDescriptorSet}, {});
+
+ while(Running())
+ {
+ {
+ VkCommandBuffer cmd = GetCommandBuffer();
+ vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
+ pushMarker(cmd, "Copy AS");
+
+ VkCopyAccelerationStructureInfoKHR copyInfo = {
+ VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR, NULL, blas, newBlas,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR,
+ };
+ vkCmdCopyAccelerationStructureKHR(cmd, ©Info);
+
+ popMarker(cmd);
+ CHECK_VKR(vkEndCommandBuffer(cmd));
+
+ Submit(0, 2, {cmd});
+ }
+
+ VkCommandBuffer cmd = GetCommandBuffer();
+
+ vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
+
+ VkImage swapimg =
+ StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
+
+ vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL,
+ vkh::ClearColorValue(0.1f, 0.1f, 0.1f, 1.0f), 1,
+ vkh::ImageSubresourceRange());
+
+ vkCmdBeginRenderPass(
+ cmd, vkh::RenderPassBeginInfo(mainWindow->rp, mainWindow->GetFB(), mainWindow->scissor),
+ VK_SUBPASS_CONTENTS_INLINE);
+
+ vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
+ vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 1, &descriptorSet, 0,
+ VK_NULL_HANDLE);
+ vkCmdSetViewport(cmd, 0, 1, &mainWindow->viewport);
+ vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor);
+ vkh::cmdBindVertexBuffers(cmd, 0, {trisVertexBuffer.buffer}, {0});
+ vkCmdBindIndexBuffer(cmd, trisIndexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
+ vkCmdDrawIndexed(cmd, indexCount, 1, 0, 0, 0);
+
+ vkCmdEndRenderPass(cmd);
+
+ FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
+
+ CHECK_VKR(vkEndCommandBuffer(cmd));
+
+ Submit(1, 2, {cmd});
+
+ Present();
+ }
+
+ vkDeviceWaitIdle(device);
+
+ vkDestroyAccelerationStructureKHR(device, newBlas, NULL);
+ vkDestroyAccelerationStructureKHR(device, tlas, NULL);
+ vkDestroyAccelerationStructureKHR(device, blas, NULL);
+
+ return 0;
+ }
+};
+
+REGISTER_TEST();
diff --git a/util/test/demos/vk/vk_test.cpp b/util/test/demos/vk/vk_test.cpp
index 09d28be35b..b87603e377 100644
--- a/util/test/demos/vk/vk_test.cpp
+++ b/util/test/demos/vk/vk_test.cpp
@@ -93,6 +93,7 @@ void main()
#pragma warning(push)
#pragma warning(disable : 4127)
+#pragma warning(disable : 4189)
#pragma warning(disable : 4324)
#pragma warning(disable : 4505)
@@ -1217,6 +1218,11 @@ VkDescriptorSet VulkanGraphicsTest::allocateDescriptorSet(VkDescriptorSetLayout
next = &inlineCreateInfo;
}
+ if(hasExt(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME))
+ {
+ poolSizes.push_back({VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1024});
+ }
+
CHECK_VKR(vkCreateDescriptorPool(
device, vkh::DescriptorPoolCreateInfo(128, poolSizes).next(next), NULL, &pool));
descPools.push_back(pool);
diff --git a/util/test/tests/Vulkan/VK_Ray_Query.py b/util/test/tests/Vulkan/VK_Ray_Query.py
new file mode 100644
index 0000000000..ec076ba337
--- /dev/null
+++ b/util/test/tests/Vulkan/VK_Ray_Query.py
@@ -0,0 +1,37 @@
+import renderdoc as rd
+import rdtest
+
+class VK_Ray_Query(rdtest.TestCase):
+ demos_test_name = 'VK_Ray_Query'
+
+ def check_capture(self):
+ last_action: rd.ActionDescription = self.get_last_action()
+
+ self.controller.SetFrameEvent(last_action.eventId, True)
+
+ pipe: rd.PipeState = self.controller.GetPipelineState()
+
+ out = last_action.copyDestination
+
+ background_color = [0.1, 0.1, 0.1, 1.0]
+ shadow_color = [0.6, 0.6, 0.6, 1.0]
+ tri_color = [1.0, 1.0, 1.0, 1.0]
+
+ # inside edge of triangle
+ self.check_pixel_value(out, 200, 193, tri_color)
+ self.check_pixel_value(out, 143, 107, tri_color)
+ self.check_pixel_value(out, 257, 107, tri_color)
+
+ # outside edge of triangle, in shadow
+ self.check_pixel_value(out, 200, 195, shadow_color)
+
+ # outer edge of shadow
+ self.check_pixel_value(out, 200, 220, shadow_color)
+
+ # below tri not in shadow
+ self.check_pixel_value(out, 200, 225, tri_color)
+
+ # background coords outside of lower triangle
+ self.check_pixel_value(out, 200, 29, background_color)
+ self.check_pixel_value(out, 39, 271, background_color)
+ self.check_pixel_value(out, 361, 271, background_color)