*//*--------------------------------------------------------------------*/
#include "vktRayTracingMiscTests.hpp"
+#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "deRandom.hpp"
#include <algorithm>
#include <memory>
+#include <sstream>
namespace vkt
{
return tcu::TestStatus::fail("Fail");
}
+void nullMissSupport (Context& context)
+{
+ context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
+ context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
+ context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
+}
+
+void nullMissPrograms (vk::SourceCollections& programCollection)
+{
+ const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
+
+ std::ostringstream rgen;
+ std::ostringstream chit;
+
+ rgen
+ << "#version 460\n"
+ << "#extension GL_EXT_ray_tracing : require\n"
+ << "layout(location=0) rayPayloadEXT vec3 unused;\n"
+ << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
+ << "layout(set=0, binding=1) buffer OutputBuffer { float val; } outBuffer;\n"
+ << "\n"
+ << "void main()\n"
+ << "{\n"
+ << " uint rayFlags = 0u;\n"
+ << " uint cullMask = 0xFFu;\n"
+ << " float tmin = 0.0;\n"
+ << " float tmax = 9.0;\n"
+ << " vec3 origin = vec3(0.0, 0.0, 0.0);\n"
+ << " vec3 direct = vec3(0.0, 0.0, 1.0);\n"
+ << " traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
+ << "}\n"
+ ;
+
+ chit
+ << "#version 460\n"
+ << "#extension GL_EXT_ray_tracing : require\n"
+ << "layout(location=0) rayPayloadInEXT vec3 unused;\n"
+ << "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
+ << "layout(set=0, binding=1) buffer OutputBuffer { float val; } outBuffer;\n"
+ << "\n"
+ << "void main()\n"
+ << "{\n"
+ << " outBuffer.val = 1.0;\n"
+ << "}\n"
+ ;
+
+ programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
+ programCollection.glslSources.add("chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions;
+}
+
+// Creates an empty shader binding table with a zeroed-out shader group handle.
+de::MovePtr<BufferWithMemory> createEmptySBT (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 shaderGroupHandleSize)
+{
+ const auto sbtSize = static_cast<VkDeviceSize>(shaderGroupHandleSize);
+ const auto sbtFlags = (VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
+ const auto sbtInfo = makeBufferCreateInfo(sbtSize, sbtFlags);
+ const auto sbtReqs = (MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress);
+
+ auto sbtBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, sbtInfo, sbtReqs));
+ auto& sbtAlloc = sbtBuffer->getAllocation();
+ void* sbtData = sbtAlloc.getHostPtr();
+
+ deMemset(sbtData, 0, static_cast<size_t>(sbtSize));
+ flushAlloc(vkd, device, sbtAlloc);
+
+ return sbtBuffer;
+}
+
+tcu::TestStatus nullMissInstance (Context& context)
+{
+ const auto& vki = context.getInstanceInterface();
+ const auto physDev = context.getPhysicalDevice();
+ const auto& vkd = context.getDeviceInterface();
+ const auto device = context.getDevice();
+ auto& alloc = context.getDefaultAllocator();
+ const auto qIndex = context.getUniversalQueueFamilyIndex();
+ const auto queue = context.getUniversalQueue();
+ const auto stages = (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
+
+ // Command pool and buffer.
+ const auto cmdPool = makeCommandPool(vkd, device, qIndex);
+ const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+ const auto cmdBuffer = cmdBufferPtr.get();
+
+ beginCommandBuffer(vkd, cmdBuffer);
+
+ // Build acceleration structures.
+ auto topLevelAS = makeTopLevelAccelerationStructure();
+ auto bottomLevelAS = makeBottomLevelAccelerationStructure();
+
+ std::vector<tcu::Vec3> triangle;
+ triangle.reserve(3u);
+ triangle.emplace_back( 0.0f, 1.0f, 10.0f);
+ triangle.emplace_back(-1.0f, -1.0f, 10.0f);
+ triangle.emplace_back( 1.0f, -1.0f, 10.0f);
+ bottomLevelAS->addGeometry(triangle, true/*triangles*/);
+ bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
+
+ de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
+ topLevelAS->setInstanceCount(1);
+ topLevelAS->addInstance(blasSharedPtr);
+ topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
+
+ // Create output buffer.
+ const auto bufferSize = static_cast<VkDeviceSize>(sizeof(float));
+ const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+ BufferWithMemory buffer (vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
+ auto& bufferAlloc = buffer.getAllocation();
+
+ // Fill output buffer with an initial value.
+ deMemset(bufferAlloc.getHostPtr(), 0, sizeof(float));
+ flushAlloc(vkd, device, bufferAlloc);
+
+ // Descriptor set layout and pipeline layout.
+ DescriptorSetLayoutBuilder setLayoutBuilder;
+ setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
+ setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
+
+ const auto setLayout = setLayoutBuilder.build(vkd, device);
+ const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
+
+ // Descriptor pool and set.
+ DescriptorPoolBuilder poolBuilder;
+ poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
+ poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+ const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+ const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
+
+ // Update descriptor set.
+ {
+ const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
+ nullptr,
+ 1u,
+ topLevelAS.get()->getPtr(),
+ };
+
+ const auto bufferDescInfo = makeDescriptorBufferInfo(buffer.get(), 0ull, VK_WHOLE_SIZE);
+
+ DescriptorSetUpdateBuilder updateBuilder;
+ updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
+ updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescInfo);
+ updateBuilder.update(vkd, device);
+ }
+
+ // Shader modules.
+ auto rgenModule = createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0);
+ auto chitModule = createShaderModule(vkd, device, context.getBinaryCollection().get("chit"), 0);
+
+ // Get some ray tracing properties.
+ deUint32 shaderGroupHandleSize = 0u;
+ deUint32 shaderGroupBaseAlignment = 1u;
+ {
+ const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physDev);
+ shaderGroupHandleSize = rayTracingPropertiesKHR->getShaderGroupHandleSize();
+ shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
+ }
+
+ // Create raytracing pipeline and shader binding tables.
+ Move<VkPipeline> pipeline;
+
+ de::MovePtr<BufferWithMemory> raygenSBT;
+ de::MovePtr<BufferWithMemory> missSBT;
+ de::MovePtr<BufferWithMemory> hitSBT;
+ de::MovePtr<BufferWithMemory> callableSBT;
+
+ VkStridedDeviceAddressRegionKHR raygenSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+ VkStridedDeviceAddressRegionKHR missSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+ VkStridedDeviceAddressRegionKHR hitSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+ VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
+
+ {
+ const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
+
+ rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, 0u);
+ rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule, 1u);
+
+ pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
+
+ raygenSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0u, 1u);
+ raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
+
+ hitSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1u, 1u);
+ hitSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
+
+ // Critical for the test: the miss shader binding table buffer is empty and contains a zero'ed out shader group handle.
+ missSBT = createEmptySBT(vkd, device, alloc, shaderGroupHandleSize);
+ missSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
+ }
+
+ // Trace rays.
+ vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
+ vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
+ vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
+
+ // Barrier for the output buffer just in case (no writes should take place).
+ const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
+ vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
+
+ endCommandBuffer(vkd, cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+
+ // Read value back from the buffer. No write should have taken place.
+ float bufferValue = 0.0f;
+ invalidateAlloc(vkd, device, bufferAlloc);
+ deMemcpy(&bufferValue, bufferAlloc.getHostPtr(), sizeof(bufferValue));
+
+ if (bufferValue != 0.0f)
+ TCU_FAIL("Unexpected value found in buffer: " + de::toString(bufferValue));
+
+ return tcu::TestStatus::pass("Pass");
+}
+
} // anonymous
miscGroupPtr->addChild(newTestCase6Ptr);
}
+ {
+ addFunctionCaseWithPrograms(miscGroupPtr.get(), "null_miss", "", nullMissSupport, nullMissPrograms, nullMissInstance);
+ }
+
return miscGroupPtr.release();
}