/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2020 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Testing acceleration structures in ray query extension *//*--------------------------------------------------------------------*/ #include "vktRayQueryAccelerationStructuresTests.hpp" #include #include #include #include "vkDefs.hpp" #include "deClock.h" #include "vktTestCase.hpp" #include "vktTestGroupUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "vkBuilderUtil.hpp" #include "vkBarrierUtil.hpp" #include "vkBufferWithMemory.hpp" #include "vkImageWithMemory.hpp" #include "vkTypeUtil.hpp" #include "vkImageUtil.hpp" #include "vkRayTracingUtil.hpp" #include "deRandom.hpp" #include "tcuTexture.hpp" #include "tcuTextureUtil.hpp" #include "tcuTestLog.hpp" #include "tcuImageCompare.hpp" #include "tcuFloat.hpp" namespace vkt { namespace RayQuery { namespace { using namespace vk; using namespace vkt; static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR; enum ShaderSourcePipeline { SSP_GRAPHICS_PIPELINE, SSP_COMPUTE_PIPELINE, SSP_RAY_TRACING_PIPELINE }; enum ShaderSourceType { SST_VERTEX_SHADER, SST_TESSELATION_CONTROL_SHADER, SST_TESSELATION_EVALUATION_SHADER, SST_GEOMETRY_SHADER, SST_FRAGMENT_SHADER, SST_COMPUTE_SHADER, SST_RAY_GENERATION_SHADER, SST_INTERSECTION_SHADER, SST_ANY_HIT_SHADER, SST_CLOSEST_HIT_SHADER, SST_MISS_SHADER, SST_CALLABLE_SHADER, }; enum ShaderTestType { STT_GENERATE_INTERSECTION = 0, STT_SKIP_INTERSECTION = 1, }; enum BottomTestType { BTT_TRIANGLES, BTT_AABBS }; enum TopTestType { TTT_IDENTICAL_INSTANCES, TTT_DIFFERENT_INSTANCES }; enum OperationTarget { OT_NONE, OT_TOP_ACCELERATION, OT_BOTTOM_ACCELERATION }; enum OperationType { OP_NONE, OP_COPY, OP_COMPACT, OP_SERIALIZE }; enum class InstanceCullFlags { NONE, CULL_DISABLE, COUNTERCLOCKWISE, ALL, }; enum class EmptyAccelerationStructureCase { NOT_EMPTY = 0, INACTIVE_TRIANGLES = 1, INACTIVE_INSTANCES = 2, NO_GEOMETRIES_BOTTOM = 3, // geometryCount zero when building. NO_PRIMITIVES_BOTTOM = 4, // primitiveCount zero when building. NO_PRIMITIVES_TOP = 5, // primitiveCount zero when building. }; const deUint32 TEST_WIDTH = 8; const deUint32 TEST_HEIGHT = 8; struct TestParams; class TestConfiguration { public: virtual ~TestConfiguration (); virtual void initConfiguration (Context& context, TestParams& testParams) = 0; virtual void fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) = 0; virtual bool verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) = 0; virtual VkFormat getResultImageFormat () = 0; virtual size_t getResultImageFormatSize () = 0; virtual VkClearValue getClearValue () = 0; }; TestConfiguration::~TestConfiguration() { } class SceneBuilder { public: virtual std::vector> initBottomAccelerationStructures (Context& context, TestParams& testParams) = 0; virtual de::MovePtr initTopAccelerationStructure (Context& context, TestParams& testParams, std::vector >& bottomLevelAccelerationStructures) = 0; }; struct TestParams { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; vk::VkAccelerationStructureBuildTypeKHR buildType; // are we making AS on CPU or GPU VkFormat vertexFormat; bool padVertices; VkIndexType indexType; BottomTestType bottomTestType; // what kind of geometry is stored in bottom AS InstanceCullFlags cullFlags; // Flags for instances, if needed. bool bottomUsesAOP; // does bottom AS use arrays, or arrays of pointers bool bottomGeneric; // Bottom created as generic AS type. TopTestType topTestType; // If instances are identical then bottom geometries must have different vertices/aabbs bool topUsesAOP; // does top AS use arrays, or arrays of pointers bool topGeneric; // Top created as generic AS type. VkBuildAccelerationStructureFlagsKHR buildFlags; OperationTarget operationTarget; OperationType operationType; deUint32 width; deUint32 height; deUint32 workerThreadsCount; EmptyAccelerationStructureCase emptyASCase; }; deUint32 getShaderGroupHandleSize (const InstanceInterface& vki, const VkPhysicalDevice physicalDevice) { de::MovePtr rayTracingPropertiesKHR; rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice); return rayTracingPropertiesKHR->getShaderGroupHandleSize(); } deUint32 getShaderGroupBaseAlignment (const InstanceInterface& vki, const VkPhysicalDevice physicalDevice) { de::MovePtr rayTracingPropertiesKHR; rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice); return rayTracingPropertiesKHR->getShaderGroupBaseAlignment(); } VkImageCreateInfo makeImageCreateInfo (deUint32 width, deUint32 height, deUint32 depth, VkFormat format) { const VkImageCreateInfo imageCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkImageCreateFlags)0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_3D, // VkImageType imageType; format, // VkFormat format; makeExtent3D(width, height, depth), // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 0u, // deUint32 queueFamilyIndexCount; DE_NULL, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; return imageCreateInfo; } Move makeQueryPool(const DeviceInterface& vk, const VkDevice device, const VkQueryType queryType, deUint32 queryCount) { const VkQueryPoolCreateInfo queryPoolCreateInfo = { VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // sType DE_NULL, // pNext (VkQueryPoolCreateFlags)0, // flags queryType, // queryType queryCount, // queryCount 0u, // pipelineStatistics }; return createQueryPool(vk, device, &queryPoolCreateInfo); } bool registerShaderModule (const DeviceInterface& vkd, const VkDevice device, Context& context, std::vector>>& shaderModules, std::vector& shaderCreateInfos, VkShaderStageFlagBits stage, const std::string& externalNamePart, const std::string& internalNamePart) { char fullShaderName[40]; snprintf(fullShaderName, 40, externalNamePart.c_str(), internalNamePart.c_str()); std::string fsn = fullShaderName; if (fsn.empty()) return false; shaderModules.push_back(makeVkSharedPtr(createShaderModule(vkd, device, context.getBinaryCollection().get(fsn), 0))); shaderCreateInfos.push_back( { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0, stage, // stage shaderModules.back()->get(), // shader "main", DE_NULL, // pSpecializationInfo }); return true; } bool registerShaderModule (const DeviceInterface& vkd, const VkDevice device, Context& context, RayTracingPipeline& rayTracingPipeline, VkShaderStageFlagBits shaderStage, const std::string& externalNamePart, const std::string& internalNamePart, deUint32 groupIndex) { char fullShaderName[40]; snprintf(fullShaderName, 40, externalNamePart.c_str(), internalNamePart.c_str()); std::string fsn = fullShaderName; if (fsn.empty()) return false; Move shaderModule = createShaderModule(vkd, device, context.getBinaryCollection().get(fsn), 0); if (*shaderModule == DE_NULL) return false; rayTracingPipeline.addShader(shaderStage, shaderModule, groupIndex); return true; } VkGeometryInstanceFlagsKHR getCullFlags (InstanceCullFlags flags) { VkGeometryInstanceFlagsKHR cullFlags = 0u; if (flags == InstanceCullFlags::CULL_DISABLE || flags == InstanceCullFlags::ALL) cullFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; if (flags == InstanceCullFlags::COUNTERCLOCKWISE || flags == InstanceCullFlags::ALL) cullFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; return cullFlags; } class GraphicsConfiguration : public TestConfiguration { public: virtual ~GraphicsConfiguration (); void initConfiguration (Context& context, TestParams& testParams) override; void fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) override; bool verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) override; VkFormat getResultImageFormat () override; size_t getResultImageFormatSize () override; VkClearValue getClearValue () override; protected: Move descriptorSetLayout; Move descriptorPool; Move descriptorSet; Move pipelineLayout; Move renderPass; Move framebuffer; std::vector > > shaderModules; Move pipeline; std::vector vertices; Move vertexBuffer; de::MovePtr vertexAlloc; }; GraphicsConfiguration::~GraphicsConfiguration() { shaderModules.clear(); } void GraphicsConfiguration::initConfiguration (Context& context, TestParams& testParams) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); Allocator& allocator = context.getDefaultAllocator(); descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL_GRAPHICS) .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_ALL_GRAPHICS) .build(vkd, device); descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout); pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get()); std::vector rayQueryTestName; rayQueryTestName.push_back("as_triangle"); rayQueryTestName.push_back("as_aabb"); const std::map> shaderNames = { //idx: 0 1 2 3 4 //shader: vert, tesc, tese, geom, frag, { SST_VERTEX_SHADER, { "vert_%s", "", "", "", "", } }, { SST_TESSELATION_CONTROL_SHADER, { "vert", "tesc_%s", "tese", "", "", } }, { SST_TESSELATION_EVALUATION_SHADER, { "vert", "tesc", "tese_%s", "", "", } }, { SST_GEOMETRY_SHADER, { "vert_vid", "", "", "geom_%s", "", } }, { SST_FRAGMENT_SHADER, { "vert", "", "", "", "frag_%s", } }, }; auto shaderNameIt = shaderNames.find(testParams.shaderSourceType); if(shaderNameIt == end(shaderNames)) TCU_THROW(InternalError, "Wrong shader source type"); std::vector shaderCreateInfos; bool tescX, teseX, fragX; registerShaderModule(vkd, device, context, shaderModules, shaderCreateInfos, VK_SHADER_STAGE_VERTEX_BIT, shaderNameIt->second[0], rayQueryTestName[testParams.bottomTestType]); tescX = registerShaderModule(vkd, device, context, shaderModules, shaderCreateInfos, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, shaderNameIt->second[1], rayQueryTestName[testParams.bottomTestType]); teseX = registerShaderModule(vkd, device, context, shaderModules, shaderCreateInfos, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, shaderNameIt->second[2], rayQueryTestName[testParams.bottomTestType]); registerShaderModule(vkd, device, context, shaderModules, shaderCreateInfos, VK_SHADER_STAGE_GEOMETRY_BIT, shaderNameIt->second[3], rayQueryTestName[testParams.bottomTestType]); fragX = registerShaderModule(vkd, device, context, shaderModules, shaderCreateInfos, VK_SHADER_STAGE_FRAGMENT_BIT, shaderNameIt->second[4], rayQueryTestName[testParams.bottomTestType]); const vk::VkSubpassDescription subpassDesc = { (vk::VkSubpassDescriptionFlags)0, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint 0u, // inputCount DE_NULL, // pInputAttachments 0u, // colorCount DE_NULL, // pColorAttachments DE_NULL, // pResolveAttachments DE_NULL, // depthStencilAttachment 0u, // preserveCount DE_NULL, // pPreserveAttachments }; const vk::VkRenderPassCreateInfo renderPassParams = { vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType DE_NULL, // pNext (vk::VkRenderPassCreateFlags)0, 0u, // attachmentCount DE_NULL, // pAttachments 1u, // subpassCount &subpassDesc, // pSubpasses 0u, // dependencyCount DE_NULL, // pDependencies }; renderPass = createRenderPass(vkd, device, &renderPassParams); const vk::VkFramebufferCreateInfo framebufferParams = { vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // sType DE_NULL, // pNext (vk::VkFramebufferCreateFlags)0, *renderPass, // renderPass 0u, // attachmentCount DE_NULL, // pAttachments testParams.width, // width testParams.height, // height 1u, // layers }; framebuffer = createFramebuffer(vkd, device, &framebufferParams); VkPrimitiveTopology testTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; tcu::Vec3 v0(0.0f, 0.0f, 0.0f); tcu::Vec3 v1(float(testParams.width) - 1.0f, 0.0f, 0.0f); tcu::Vec3 v2(0.0f, float(testParams.height) - 1.0f, 0.0f); tcu::Vec3 v3(float(testParams.width) - 1.0f, float(testParams.height) - 1.0f, 0.0f); switch (testParams.shaderSourceType) { case SST_TESSELATION_CONTROL_SHADER: case SST_TESSELATION_EVALUATION_SHADER: testTopology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; vertices.push_back(v0); vertices.push_back(v1); vertices.push_back(v2); vertices.push_back(v1); vertices.push_back(v3); vertices.push_back(v2); break; case SST_VERTEX_SHADER: case SST_GEOMETRY_SHADER: vertices.push_back(v0); vertices.push_back(v1); vertices.push_back(v2); vertices.push_back(v3); break; case SST_FRAGMENT_SHADER: vertices.push_back( tcu::Vec3(-1.0f, 1.0f, 0.0f) ); vertices.push_back( tcu::Vec3(-1.0f, -1.0f, 0.0f) ); vertices.push_back( tcu::Vec3( 1.0f, 1.0f, 0.0f) ); vertices.push_back( tcu::Vec3( 1.0f, -1.0f, 0.0f) ); break; default: TCU_THROW(InternalError, "Wrong shader source type"); } const VkVertexInputBindingDescription vertexInputBindingDescription = { 0u, // uint32_t binding; sizeof(tcu::Vec3), // uint32_t stride; VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; }; const VkVertexInputAttributeDescription vertexInputAttributeDescription = { 0u, // uint32_t location; 0u, // uint32_t binding; VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format; 0u, // uint32_t offset; }; const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; 1u, // deUint32 vertexBindingDescriptionCount; &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 1u, // deUint32 vertexAttributeDescriptionCount; &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; }; const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; testTopology, // VkPrimitiveTopology topology; VK_FALSE // VkBool32 primitiveRestartEnable; }; const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; VkPipelineTessellationStateCreateFlags(0u), // VkPipelineTessellationStateCreateFlags flags; 3u // deUint32 patchControlPoints; }; VkViewport viewport = makeViewport(testParams.width, testParams.height); VkRect2D scissor = makeRect2D(testParams.width, testParams.height); const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags 1u, // deUint32 viewportCount &viewport, // const VkViewport* pViewports 1u, // deUint32 scissorCount &scissor // const VkRect2D* pScissors }; const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; VK_FALSE, // VkBool32 depthClampEnable; fragX ? VK_FALSE : VK_TRUE, // VkBool32 rasterizerDiscardEnable; VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace; VK_FALSE, // VkBool32 depthBiasEnable; 0.0f, // float depthBiasConstantFactor; 0.0f, // float depthBiasClamp; 0.0f, // float depthBiasSlopeFactor; 1.0f // float lineWidth; }; const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; VK_FALSE, // VkBool32 sampleShadingEnable; 0.0f, // float minSampleShading; DE_NULL, // const VkSampleMask* pSampleMask; VK_FALSE, // VkBool32 alphaToCoverageEnable; VK_FALSE // VkBool32 alphaToOneEnable; }; const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; DE_FALSE, // VkBool32 logicOpEnable; VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp; 0, // deUint32 attachmentCount; DE_NULL, // const VkPipelineColorBlendAttachmentState* pAttachments; { 1.0f, 1.0f, 1.0f, 1.0f } // float blendConstants[4]; }; const VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; static_cast(shaderCreateInfos.size()), // deUint32 stageCount; shaderCreateInfos.data(), // const VkPipelineShaderStageCreateInfo* pStages; &vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; (tescX||teseX) ? &tessellationStateCreateInfo : DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; fragX ? &viewportStateCreateInfo : DE_NULL, // const VkPipelineViewportStateCreateInfo* pViewportState; &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; fragX ? &multisampleStateCreateInfo : DE_NULL, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; fragX ? &colorBlendStateCreateInfo : DE_NULL, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; pipelineLayout.get(), // VkPipelineLayout layout; renderPass.get(), // VkRenderPass renderPass; 0u, // deUint32 subpass; DE_NULL, // VkPipeline basePipelineHandle; 0 // int basePipelineIndex; }; pipeline = createGraphicsPipeline(vkd, device, DE_NULL, &graphicsPipelineCreateInfo); const VkBufferCreateInfo vertexBufferParams = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkBufferCreateFlags flags; VkDeviceSize(sizeof(tcu::Vec3) * vertices.size()), // VkDeviceSize size; VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex // const deUint32* pQueueFamilyIndices; }; vertexBuffer = createBuffer(vkd, device, &vertexBufferParams); vertexAlloc = allocator.allocate(getBufferMemoryRequirements(vkd, device, *vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vkd.bindBufferMemory(device, *vertexBuffer, vertexAlloc->getMemory(), vertexAlloc->getOffset())); // Upload vertex data deMemcpy(vertexAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(tcu::Vec3)); flushAlloc(vkd, device, *vertexAlloc); } void GraphicsConfiguration::fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); DescriptorSetUpdateBuilder() .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageInfo) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &rayQueryAccelerationStructureWriteDescriptorSet) .update(vkd, device); const VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; *renderPass, // VkRenderPass renderPass; *framebuffer, // VkFramebuffer framebuffer; makeRect2D(testParams.width, testParams.height), // VkRect2D renderArea; 0u, // uint32_t clearValueCount; DE_NULL // const VkClearValue* pClearValues; }; VkDeviceSize vertexBufferOffset = 0u; vkd.cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkd.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); vkd.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); vkd.cmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset); vkd.cmdDraw(commandBuffer, deUint32(vertices.size()), 1, 0, 0); vkd.cmdEndRenderPass(commandBuffer); } bool GraphicsConfiguration::verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) { // create result image const bool allMiss = (testParams.emptyASCase != EmptyAccelerationStructureCase::NOT_EMPTY); tcu::TextureFormat imageFormat = vk::mapVkFormat(getResultImageFormat()); tcu::ConstPixelBufferAccess resultAccess(imageFormat, testParams.width, testParams.height, 2, resultBuffer->getAllocation().getHostPtr()); // create reference image std::vector reference(testParams.width * testParams.height * 2); tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 2, reference.data()); std::vector> primitives = { {0, 1, 2}, {1, 3, 2} }; tcu::UVec4 hitValue0 = tcu::UVec4(1, 0, 0, 0); tcu::UVec4 hitValue1 = tcu::UVec4(1, 0, 0, 0); tcu::UVec4 missValue = tcu::UVec4(0, 0, 0, 0); tcu::UVec4 clearValue = tcu::UVec4(0xFF, 0, 0, 0); switch (testParams.shaderSourceType) { case SST_VERTEX_SHADER: tcu::clear(referenceAccess, clearValue); for (deUint32 vertexNdx = 0; vertexNdx < 4; ++vertexNdx) { if (!allMiss && (vertexNdx == 1 || vertexNdx == 2)) { referenceAccess.setPixel(hitValue0, vertexNdx, 0, 0); referenceAccess.setPixel(hitValue1, vertexNdx, 0, 1); } else { referenceAccess.setPixel(missValue, vertexNdx, 0, 0); referenceAccess.setPixel(missValue, vertexNdx, 0, 1); } } break; case SST_TESSELATION_EVALUATION_SHADER: case SST_TESSELATION_CONTROL_SHADER: case SST_GEOMETRY_SHADER: tcu::clear(referenceAccess, clearValue); for (deUint32 primitiveNdx = 0; primitiveNdx < primitives.size(); ++primitiveNdx) for (deUint32 vertexNdx = 0; vertexNdx < 3; ++vertexNdx) { deUint32 vNdx = primitives[primitiveNdx][vertexNdx]; if (!allMiss && (vNdx==1 || vNdx==2)) { referenceAccess.setPixel(hitValue0, primitiveNdx, vertexNdx, 0); referenceAccess.setPixel(hitValue1, primitiveNdx, vertexNdx, 1); } else { referenceAccess.setPixel(missValue, primitiveNdx, vertexNdx, 0); referenceAccess.setPixel(missValue, primitiveNdx, vertexNdx, 1); } } break; case SST_FRAGMENT_SHADER: tcu::clear(referenceAccess, missValue); for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { if (allMiss || ((x + y) % 2) == 0) continue; referenceAccess.setPixel(hitValue0, x, y, 0); referenceAccess.setPixel(hitValue1, x, y, 1); } break; default: TCU_THROW(InternalError, "Wrong shader source type"); } // compare result and reference return tcu::intThresholdCompare(context.getTestContext().getLog(), "Result comparison", "", referenceAccess, resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT); } VkFormat GraphicsConfiguration::getResultImageFormat () { return VK_FORMAT_R32_UINT; } size_t GraphicsConfiguration::getResultImageFormatSize () { return sizeof(deUint32); } VkClearValue GraphicsConfiguration::getClearValue () { return makeClearValueColorU32(0xFF, 0u, 0u, 0u); } class ComputeConfiguration : public TestConfiguration { public: virtual ~ComputeConfiguration (); void initConfiguration (Context& context, TestParams& testParams) override; void fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) override; bool verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) override; VkFormat getResultImageFormat () override; size_t getResultImageFormatSize () override; VkClearValue getClearValue () override; protected: Move descriptorSetLayout; Move descriptorPool; Move descriptorSet; Move pipelineLayout; Move shaderModule; Move pipeline; }; ComputeConfiguration::~ComputeConfiguration() { } void ComputeConfiguration::initConfiguration (Context& context, TestParams& testParams) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_COMPUTE_BIT) .build(vkd, device); descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout); pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get()); std::vector rayQueryTestName; rayQueryTestName.push_back("comp_as_triangle"); rayQueryTestName.push_back("comp_as_aabb"); shaderModule = createShaderModule(vkd, device, context.getBinaryCollection().get(rayQueryTestName[testParams.bottomTestType]), 0u); const VkPipelineShaderStageCreateInfo pipelineShaderStageParams = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage; *shaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; }; const VkComputePipelineCreateInfo pipelineCreateInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineCreateFlags flags; pipelineShaderStageParams, // VkPipelineShaderStageCreateInfo stage; *pipelineLayout, // VkPipelineLayout layout; DE_NULL, // VkPipeline basePipelineHandle; 0, // deInt32 basePipelineIndex; }; pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineCreateInfo); } void ComputeConfiguration::fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); DescriptorSetUpdateBuilder() .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageInfo) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &rayQueryAccelerationStructureWriteDescriptorSet) .update(vkd, device); vkd.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); vkd.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); vkd.cmdDispatch(commandBuffer, testParams.width, testParams.height, 1); } bool ComputeConfiguration::verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) { // create result image const bool allMiss = (testParams.emptyASCase != EmptyAccelerationStructureCase::NOT_EMPTY); tcu::TextureFormat imageFormat = vk::mapVkFormat(getResultImageFormat()); tcu::ConstPixelBufferAccess resultAccess(imageFormat, testParams.width, testParams.height, 2, resultBuffer->getAllocation().getHostPtr()); // create reference image std::vector reference(testParams.width * testParams.height * 2); tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 2, reference.data()); tcu::UVec4 hitValue0 = tcu::UVec4(1, 0, 0, 0); tcu::UVec4 hitValue1 = tcu::UVec4(1, 0, 0, 0); tcu::UVec4 missValue = tcu::UVec4(0, 0, 0, 0); tcu::clear(referenceAccess, missValue); for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { if (allMiss || ((x + y) % 2) == 0) continue; referenceAccess.setPixel(hitValue0, x, y, 0); referenceAccess.setPixel(hitValue1, x, y, 1); } // compare result and reference return tcu::intThresholdCompare(context.getTestContext().getLog(), "Result comparison", "", referenceAccess, resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT); } VkFormat ComputeConfiguration::getResultImageFormat () { return VK_FORMAT_R32_UINT; } size_t ComputeConfiguration::getResultImageFormatSize () { return sizeof(deUint32); } VkClearValue ComputeConfiguration::getClearValue () { return makeClearValueColorU32(0xFF, 0u, 0u, 0u); } class RayTracingConfiguration : public TestConfiguration { public: virtual ~RayTracingConfiguration (); void initConfiguration (Context& context, TestParams& testParams) override; void fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) override; bool verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) override; VkFormat getResultImageFormat () override; size_t getResultImageFormatSize () override; VkClearValue getClearValue () override; protected: Move descriptorSetLayout; Move descriptorPool; Move descriptorSet; Move pipelineLayout; de::MovePtr rayTracingPipeline; Move rtPipeline; de::MovePtr raygenShaderBindingTable; de::MovePtr hitShaderBindingTable; de::MovePtr missShaderBindingTable; de::MovePtr callableShaderBindingTable; std::vector > bottomLevelAccelerationStructures; de::MovePtr topLevelAccelerationStructure; }; RayTracingConfiguration::~RayTracingConfiguration() { } void RayTracingConfiguration::initConfiguration (Context& context, TestParams& testParams) { const InstanceInterface& vki = context.getInstanceInterface(); const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); Allocator& allocator = context.getDefaultAllocator(); descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES) .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES) .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES) .build(vkd, device); descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout); pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get()); rayTracingPipeline = de::newMovePtr(); const std::map> shaderNames = { //idx: 0 1 2 3 4 5 //shader: rgen, isect, ahit, chit, miss, call //group: 0 1 1 1 2 3 { SST_RAY_GENERATION_SHADER, { "rgen_%s", "", "", "", "", "" } }, { SST_INTERSECTION_SHADER, { "rgen", "isect_%s", "", "chit_isect", "miss", "" } }, { SST_ANY_HIT_SHADER, { "rgen", "isect", "ahit_%s", "", "miss", "" } }, { SST_CLOSEST_HIT_SHADER, { "rgen", "isect", "", "chit_%s", "miss", "" } }, { SST_MISS_SHADER, { "rgen", "isect", "", "chit", "miss_%s", "" } }, { SST_CALLABLE_SHADER, { "rgen_call", "", "", "chit", "miss", "call_%s" } }, }; std::vector rayQueryTestName; rayQueryTestName.push_back("as_triangle"); rayQueryTestName.push_back("as_aabb"); auto shaderNameIt = shaderNames.find(testParams.shaderSourceType); if(shaderNameIt == end(shaderNames)) TCU_THROW(InternalError, "Wrong shader source type"); bool rgenX, isectX, ahitX, chitX, missX, callX; rgenX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_RAYGEN_BIT_KHR, shaderNameIt->second[0], rayQueryTestName[testParams.bottomTestType], 0); if (testParams.shaderSourceType == SST_INTERSECTION_SHADER) isectX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_INTERSECTION_BIT_KHR, shaderNameIt->second[1], rayQueryTestName[testParams.bottomTestType], 1); else isectX = false; ahitX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_ANY_HIT_BIT_KHR, shaderNameIt->second[2], rayQueryTestName[testParams.bottomTestType], 1); chitX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, shaderNameIt->second[3], rayQueryTestName[testParams.bottomTestType], 1); missX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_MISS_BIT_KHR, shaderNameIt->second[4], rayQueryTestName[testParams.bottomTestType], 2); callX = registerShaderModule(vkd, device, context, *rayTracingPipeline, VK_SHADER_STAGE_CALLABLE_BIT_KHR, shaderNameIt->second[5], rayQueryTestName[testParams.bottomTestType], 3); bool hitX = isectX || ahitX || chitX; rtPipeline = rayTracingPipeline->createPipeline(vkd, device, *pipelineLayout); deUint32 shaderGroupHandleSize = getShaderGroupHandleSize(vki, physicalDevice); deUint32 shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice); if (rgenX) raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, *rtPipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); if (hitX) hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, *rtPipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1); if (missX) missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, *rtPipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 2, 1); if (callX) callableShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, *rtPipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, 3, 1); } void RayTracingConfiguration::fillCommandBuffer (Context& context, TestParams& testParams, VkCommandBuffer commandBuffer, const VkWriteDescriptorSetAccelerationStructureKHR& rayQueryAccelerationStructureWriteDescriptorSet, const VkDescriptorImageInfo& resultImageInfo) { const InstanceInterface& vki = context.getInstanceInterface(); const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); Allocator& allocator = context.getDefaultAllocator(); { de::MovePtr bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure(); bottomLevelAccelerationStructure->setGeometryCount(1); de::SharedPtr geometry; if (testParams.shaderSourceType != SST_INTERSECTION_SHADER) { tcu::Vec3 v0(0.0f, float(testParams.height), 0.0f); tcu::Vec3 v1(0.0f, 0.0f, 0.0f); tcu::Vec3 v2(float(testParams.width), float(testParams.height), 0.0f); tcu::Vec3 v3(float(testParams.width), 0.0f, 0.0f); tcu::Vec3 missOffset(0.0f, 0.0f, 0.0f); if (testParams.shaderSourceType == SST_MISS_SHADER) missOffset = tcu::Vec3(1.0f + float(testParams.width), 0.0f, 0.0f); geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR); geometry->addVertex(v0 + missOffset); geometry->addVertex(v1 + missOffset); geometry->addVertex(v2 + missOffset); geometry->addVertex(v2 + missOffset); geometry->addVertex(v1 + missOffset); geometry->addVertex(v3 + missOffset); } else // testParams.shaderSourceType == SST_INTERSECTION_SHADER { tcu::Vec3 v0(0.0f, 0.0f, -0.1f); tcu::Vec3 v1(float(testParams.width), float(testParams.height), 0.1f); geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR); geometry->addVertex(v0); geometry->addVertex(v1); } bottomLevelAccelerationStructure->addGeometry(geometry); bottomLevelAccelerationStructures.push_back(de::SharedPtr(bottomLevelAccelerationStructure.release())); for (auto& blas : bottomLevelAccelerationStructures) blas->createAndBuild(vkd, device, commandBuffer, allocator); } topLevelAccelerationStructure = makeTopLevelAccelerationStructure(); topLevelAccelerationStructure->setInstanceCount(1); topLevelAccelerationStructure->addInstance(bottomLevelAccelerationStructures[0]); topLevelAccelerationStructure->createAndBuild(vkd, device, commandBuffer, allocator); const TopLevelAccelerationStructure* topLevelAccelerationStructurePtr = topLevelAccelerationStructure.get(); VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; 1u, // deUint32 accelerationStructureCount; topLevelAccelerationStructurePtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures; }; DescriptorSetUpdateBuilder() .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageInfo) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &rayQueryAccelerationStructureWriteDescriptorSet) .update(vkd, device); vkd.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL); vkd.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *rtPipeline); deUint32 shaderGroupHandleSize = getShaderGroupHandleSize(vki, physicalDevice); VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion = raygenShaderBindingTable.get() != DE_NULL ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize) : makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion = hitShaderBindingTable.get() != DE_NULL ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize) : makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion = missShaderBindingTable.get() != DE_NULL ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize) : makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion = callableShaderBindingTable.get() != DE_NULL ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, callableShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize) : makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); cmdTraceRays(vkd, commandBuffer, &raygenShaderBindingTableRegion, &missShaderBindingTableRegion, &hitShaderBindingTableRegion, &callableShaderBindingTableRegion, testParams.width, testParams.height, 1); } bool RayTracingConfiguration::verifyImage (BufferWithMemory* resultBuffer, Context& context, TestParams& testParams) { // create result image const bool allMiss = (testParams.emptyASCase != EmptyAccelerationStructureCase::NOT_EMPTY); tcu::TextureFormat imageFormat = vk::mapVkFormat(getResultImageFormat()); tcu::ConstPixelBufferAccess resultAccess(imageFormat, testParams.width, testParams.height, 2, resultBuffer->getAllocation().getHostPtr()); // create reference image std::vector reference(testParams.width * testParams.height * 2); tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 2, reference.data()); tcu::UVec4 missValue (0, 0, 0, 0); tcu::UVec4 hitValue (1, 0, 0, 0); for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { if (allMiss || ((x + y) % 2) == 0) { referenceAccess.setPixel(missValue, x, y, 0); referenceAccess.setPixel(missValue, x, y, 1); } else { referenceAccess.setPixel(hitValue, x, y, 0); referenceAccess.setPixel(hitValue, x, y, 1); } } // compare result and reference return tcu::intThresholdCompare(context.getTestContext().getLog(), "Result comparison", "", referenceAccess, resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT); } VkFormat RayTracingConfiguration::getResultImageFormat () { return VK_FORMAT_R32_UINT; } size_t RayTracingConfiguration::getResultImageFormatSize () { return sizeof(deUint32); } VkClearValue RayTracingConfiguration::getClearValue () { return makeClearValueColorU32(0xFF, 0u, 0u, 0u); } de::SharedPtr createTestConfiguration(const ShaderSourcePipeline& shaderSourcePipeline) { switch (shaderSourcePipeline) { case SSP_GRAPHICS_PIPELINE: return de::SharedPtr(new GraphicsConfiguration()); case SSP_COMPUTE_PIPELINE: return de::SharedPtr(new ComputeConfiguration()); case SSP_RAY_TRACING_PIPELINE: return de::SharedPtr(new RayTracingConfiguration()); default: TCU_THROW(InternalError, "Wrong shader source pipeline"); } return de::SharedPtr(); } class CheckerboardSceneBuilder : public SceneBuilder { public: std::vector> initBottomAccelerationStructures (Context& context, TestParams& testParams) override; de::MovePtr initTopAccelerationStructure (Context& context, TestParams& testParams, std::vector >& bottomLevelAccelerationStructures) override; }; std::vector> CheckerboardSceneBuilder::initBottomAccelerationStructures (Context& context, TestParams& testParams) { DE_UNREF(context); // Cull flags can only be used with triangles. DE_ASSERT(testParams.cullFlags == InstanceCullFlags::NONE || testParams.bottomTestType == BTT_TRIANGLES); std::vector > result; const auto instanceFlags = getCullFlags(testParams.cullFlags); tcu::Vec3 v0(0.0, 1.0, 0.0); tcu::Vec3 v1(0.0, 0.0, 0.0); tcu::Vec3 v2(1.0, 1.0, 0.0); tcu::Vec3 v3(1.0, 0.0, 0.0); if (testParams.emptyASCase == EmptyAccelerationStructureCase::INACTIVE_TRIANGLES) { const auto nanValue = tcu::Float32::nan().asFloat(); v0.x() = nanValue; v1.x() = nanValue; v2.x() = nanValue; v3.x() = nanValue; } if (testParams.topTestType == TTT_DIFFERENT_INSTANCES) { de::MovePtr bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure(); bottomLevelAccelerationStructure->setGeometryCount(1u); de::SharedPtr geometry; if (testParams.bottomTestType == BTT_TRIANGLES) { geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, testParams.vertexFormat, testParams.indexType, testParams.padVertices); if (testParams.indexType == VK_INDEX_TYPE_NONE_KHR) { if (instanceFlags == 0u) { geometry->addVertex(v0); geometry->addVertex(v1); geometry->addVertex(v2); geometry->addVertex(v2); geometry->addVertex(v1); geometry->addVertex(v3); } else // Counterclockwise so the flags will be needed for the geometry to be visible. { geometry->addVertex(v2); geometry->addVertex(v1); geometry->addVertex(v0); geometry->addVertex(v3); geometry->addVertex(v1); geometry->addVertex(v2); } } else // m_data.indexType != VK_INDEX_TYPE_NONE_KHR { geometry->addVertex(v0); geometry->addVertex(v1); geometry->addVertex(v2); geometry->addVertex(v3); if (instanceFlags == 0u) { geometry->addIndex(0); geometry->addIndex(1); geometry->addIndex(2); geometry->addIndex(2); geometry->addIndex(1); geometry->addIndex(3); } else // Counterclockwise so the flags will be needed for the geometry to be visible. { geometry->addIndex(2); geometry->addIndex(1); geometry->addIndex(0); geometry->addIndex(3); geometry->addIndex(1); geometry->addIndex(2); } } } else // m_data.bottomTestType == BTT_AABBS { geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, testParams.vertexFormat, testParams.indexType, testParams.padVertices); if (!testParams.padVertices) { // Single AABB. geometry->addVertex(tcu::Vec3(0.0f, 0.0f, -0.1f)); geometry->addVertex(tcu::Vec3(1.0f, 1.0f, 0.1f)); } else { // Multiple AABBs covering the same space. geometry->addVertex(tcu::Vec3(0.0f, 0.0f, -0.1f)); geometry->addVertex(tcu::Vec3(0.5f, 0.5f, 0.1f)); geometry->addVertex(tcu::Vec3(0.5f, 0.5f, -0.1f)); geometry->addVertex(tcu::Vec3(1.0f, 1.0f, 0.1f)); geometry->addVertex(tcu::Vec3(0.0f, 0.5f, -0.1f)); geometry->addVertex(tcu::Vec3(0.5f, 1.0f, 0.1f)); geometry->addVertex(tcu::Vec3(0.5f, 0.0f, -0.1f)); geometry->addVertex(tcu::Vec3(1.0f, 0.5f, 0.1f)); } } bottomLevelAccelerationStructure->addGeometry(geometry); result.push_back(de::SharedPtr(bottomLevelAccelerationStructure.release())); } else // m_data.topTestType == TTT_IDENTICAL_INSTANCES { tcu::TextureFormat texFormat = mapVkFormat(testParams.vertexFormat); tcu::Vec3 scale ( 1.0f, 1.0f, 1.0f ); if (tcu::getTextureChannelClass(texFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT) scale = tcu::Vec3(1.0f / float(testParams.width), 1.0f / float(testParams.height), 1.0f); // triangle and aabb tests use geometries/aabbs with different vertex positions and the same identity matrix in each instance data for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { // let's build a chessboard of geometries if (((x + y) % 2) == 0) continue; tcu::Vec3 xyz((float)x, (float)y, 0.0f); de::MovePtr bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure(); bottomLevelAccelerationStructure->setGeometryCount(1u); de::SharedPtr geometry; if (testParams.bottomTestType == BTT_TRIANGLES) { geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, testParams.vertexFormat, testParams.indexType, testParams.padVertices); if (testParams.indexType == VK_INDEX_TYPE_NONE_KHR) { if (instanceFlags == 0u) { geometry->addVertex(scale * (xyz + v0)); geometry->addVertex(scale * (xyz + v1)); geometry->addVertex(scale * (xyz + v2)); geometry->addVertex(scale * (xyz + v2)); geometry->addVertex(scale * (xyz + v1)); geometry->addVertex(scale * (xyz + v3)); } else // Counterclockwise so the flags will be needed for the geometry to be visible. { geometry->addVertex(scale * (xyz + v2)); geometry->addVertex(scale * (xyz + v1)); geometry->addVertex(scale * (xyz + v0)); geometry->addVertex(scale * (xyz + v3)); geometry->addVertex(scale * (xyz + v1)); geometry->addVertex(scale * (xyz + v2)); } } else { geometry->addVertex(scale * (xyz + v0)); geometry->addVertex(scale * (xyz + v1)); geometry->addVertex(scale * (xyz + v2)); geometry->addVertex(scale * (xyz + v3)); if (instanceFlags == 0u) { geometry->addIndex(0); geometry->addIndex(1); geometry->addIndex(2); geometry->addIndex(2); geometry->addIndex(1); geometry->addIndex(3); } else // Counterclockwise so the flags will be needed for the geometry to be visible. { geometry->addIndex(2); geometry->addIndex(1); geometry->addIndex(0); geometry->addIndex(3); geometry->addIndex(1); geometry->addIndex(2); } } } else // testParams.bottomTestType == BTT_AABBS { geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, testParams.vertexFormat, testParams.indexType, testParams.padVertices); if (!testParams.padVertices) { // Single AABB. geometry->addVertex(scale * (xyz + tcu::Vec3(0.0f, 0.0f, -0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(1.0f, 1.0f, 0.1f))); } else { // Multiple AABBs covering the same space. geometry->addVertex(scale * (xyz + tcu::Vec3(0.0f, 0.0f, -0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(0.5f, 0.5f, 0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(0.5f, 0.5f, -0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(1.0f, 1.0f, 0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(0.0f, 0.5f, -0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(0.5f, 1.0f, 0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(0.5f, 0.0f, -0.1f))); geometry->addVertex(scale * (xyz + tcu::Vec3(1.0f, 0.5f, 0.1f))); } } bottomLevelAccelerationStructure->addGeometry(geometry); result.push_back(de::SharedPtr(bottomLevelAccelerationStructure.release())); } } return result; } de::MovePtr CheckerboardSceneBuilder::initTopAccelerationStructure (Context& context, TestParams& testParams, std::vector >& bottomLevelAccelerationStructures) { DE_UNREF(context); const auto instanceCount = testParams.width * testParams.height / 2u; const auto instanceFlags = getCullFlags(testParams.cullFlags); de::MovePtr result = makeTopLevelAccelerationStructure(); result->setInstanceCount(instanceCount); if (testParams.topTestType == TTT_DIFFERENT_INSTANCES) { for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { if (((x + y) % 2) == 0) continue; const VkTransformMatrixKHR transformMatrixKHR = { { // float matrix[3][4]; { 1.0f, 0.0f, 0.0f, (float)x }, { 0.0f, 1.0f, 0.0f, (float)y }, { 0.0f, 0.0f, 1.0f, 0.0f }, } }; result->addInstance(bottomLevelAccelerationStructures[0], transformMatrixKHR, 0u, 0xFFu, 0u, instanceFlags); } } else // testParams.topTestType == TTT_IDENTICAL_INSTANCES { tcu::TextureFormat texFormat = mapVkFormat(testParams.vertexFormat); tcu::Vec3 scale ( 1.0f, 1.0f, 1.0f ); if (tcu::getTextureChannelClass(texFormat.type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT) scale = tcu::Vec3(float(testParams.width), float(testParams.height), 1.0f); const VkTransformMatrixKHR transformMatrixKHR = { { // float matrix[3][4]; { scale.x(), 0.0f, 0.0f, 0.0f }, { 0.0f, scale.y(), 0.0f, 0.0f }, { 0.0f, 0.0f, scale.z(), 0.0f }, } }; deUint32 currentInstanceIndex = 0; for (deUint32 y = 0; y < testParams.height; ++y) for (deUint32 x = 0; x < testParams.width; ++x) { if (((x + y) % 2) == 0) continue; result->addInstance(bottomLevelAccelerationStructures[currentInstanceIndex++], transformMatrixKHR, 0u, 0xFFu, 0u, instanceFlags); } } return result; } void commonASTestsCheckSupport(Context& context) { context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2"); context.requireDeviceFunctionality("VK_KHR_acceleration_structure"); context.requireDeviceFunctionality("VK_KHR_ray_query"); const VkPhysicalDeviceRayQueryFeaturesKHR& rayQueryFeaturesKHR = context.getRayQueryFeatures(); if (rayQueryFeaturesKHR.rayQuery == DE_FALSE) TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayQueryFeaturesKHR.rayQuery"); const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures(); if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE) TCU_THROW(TestError, "VK_KHR_ray_query requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure"); } class RayQueryASBasicTestCase : public TestCase { public: RayQueryASBasicTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams& data); ~RayQueryASBasicTestCase (void); virtual void checkSupport (Context& context) const; virtual void initPrograms (SourceCollections& programCollection) const; virtual TestInstance* createInstance (Context& context) const; protected: TestParams m_data; }; class RayQueryASFuncArgTestCase : public RayQueryASBasicTestCase { public: RayQueryASFuncArgTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams& data); ~RayQueryASFuncArgTestCase (void) {} virtual void initPrograms (SourceCollections& programCollection) const; }; class RayQueryASBasicTestInstance : public TestInstance { public: RayQueryASBasicTestInstance (Context& context, const TestParams& data); ~RayQueryASBasicTestInstance (void); tcu::TestStatus iterate (void); protected: bool iterateNoWorkers (void); bool iterateWithWorkers (void); de::MovePtr runTest (TestConfiguration* testConfiguration, SceneBuilder* sceneBuilder, const deUint32 workerThreadsCount); private: TestParams m_data; }; RayQueryASBasicTestCase::RayQueryASBasicTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams& data) : vkt::TestCase (context, name, desc) , m_data (data) { } RayQueryASBasicTestCase::~RayQueryASBasicTestCase (void) { } void RayQueryASBasicTestCase::checkSupport (Context& context) const { commonASTestsCheckSupport(context); const VkPhysicalDeviceFeatures2& features2 = context.getDeviceFeatures2(); if ((m_data.shaderSourceType == SST_TESSELATION_CONTROL_SHADER || m_data.shaderSourceType == SST_TESSELATION_EVALUATION_SHADER) && features2.features.tessellationShader == DE_FALSE ) TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceFeatures2.tessellationShader"); if (m_data.shaderSourceType == SST_GEOMETRY_SHADER && features2.features.geometryShader == DE_FALSE ) TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceFeatures2.geometryShader"); if (m_data.shaderSourceType == SST_RAY_GENERATION_SHADER || m_data.shaderSourceType == SST_INTERSECTION_SHADER || m_data.shaderSourceType == SST_ANY_HIT_SHADER || m_data.shaderSourceType == SST_CLOSEST_HIT_SHADER || m_data.shaderSourceType == SST_MISS_SHADER || m_data.shaderSourceType == SST_CALLABLE_SHADER) { context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline"); const VkPhysicalDeviceRayTracingPipelineFeaturesKHR& rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures(); if(rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE ) TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline"); } switch (m_data.shaderSourceType) { case SST_VERTEX_SHADER: case SST_TESSELATION_CONTROL_SHADER: case SST_TESSELATION_EVALUATION_SHADER: case SST_GEOMETRY_SHADER: context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS); break; default: break; } const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures(); if (m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == DE_FALSE) TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureHostCommands"); // Check supported vertex format. checkAccelerationStructureVertexBufferFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_data.vertexFormat); } void RayQueryASBasicTestCase::initPrograms (SourceCollections& programCollection) const { const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true); // create parts of programs responsible for test execution std::vector rayQueryTest; std::vector rayQueryTestName; rayQueryTestName.push_back("as_triangle"); rayQueryTestName.push_back("as_aabb"); { std::stringstream css; css << " float tmin = 0.0;\n" " float tmax = 1.0;\n" " vec3 direct = vec3(0.0, 0.0, -1.0);\n" " rayQueryEXT rq;\n" " rayQueryInitializeEXT(rq, rqTopLevelAS, " << ((m_data.cullFlags == InstanceCullFlags::NONE) ? "0" : "gl_RayFlagsCullBackFacingTrianglesEXT") << ", 0xFF, origin, tmin, direct, tmax);\n" " if(rayQueryProceedEXT(rq))\n" " {\n" " if (rayQueryGetIntersectionTypeEXT(rq, false)==gl_RayQueryCandidateIntersectionTriangleEXT)\n" " {\n" " hitValue.y = 1;\n" " hitValue.x = 1;\n" " }\n" " }\n"; rayQueryTest.push_back(css.str()); } { std::stringstream css; css << " float tmin = 0.0;\n" " float tmax = 1.0;\n" " vec3 direct = vec3(0.0, 0.0, -1.0);\n" " rayQueryEXT rq;\n" " rayQueryInitializeEXT(rq, rqTopLevelAS, 0, 0xFF, origin, tmin, direct, tmax);\n" " if(rayQueryProceedEXT(rq))\n" " {\n" " if (rayQueryGetIntersectionTypeEXT(rq, false)==gl_RayQueryCandidateIntersectionAABBEXT)\n" " {\n" " hitValue.y = 1;\n" " hitValue.x = 1;\n" " }\n" " }\n"; rayQueryTest.push_back(css.str()); } // create all programs if (m_data.shaderSourcePipeline == SSP_GRAPHICS_PIPELINE) { { std::stringstream css; css << "#version 460 core\n" "layout (location = 0) in vec3 position;\n" "out gl_PerVertex\n" "{\n" " vec4 gl_Position;\n" "};\n" "void main()\n" "{\n" " gl_Position = vec4(position, 1.0);\n" "}\n"; programCollection.glslSources.add("vert") << glu::VertexSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "layout (location = 0) in vec3 position;\n" "out gl_PerVertex\n" "{\n" " vec4 gl_Position;\n" "};\n" "layout(location = 0) out int vertexIndex;\n" "void main()\n" "{\n" " gl_Position = vec4(position, 1.0);\n" " vertexIndex = gl_VertexIndex;\n" "}\n"; programCollection.glslSources.add("vert_vid") << glu::VertexSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_query : require\n" "layout (location = 0) in vec3 position;\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = vec3(float(position.x) + 0.5, float(position.y) + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_VertexIndex, 0, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_VertexIndex, 0, 1), uvec4(hitValue.y, 0, 0, 0));\n" " gl_Position = vec4(position,1);\n" "}\n"; std::stringstream cssName; cssName << "vert_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::VertexSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_tessellation_shader : require\n" "in gl_PerVertex {\n" " vec4 gl_Position;\n" "} gl_in[];\n" "layout(vertices = 3) out;\n" "void main (void)\n" "{\n" " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" " gl_TessLevelInner[0] = 1;\n" " gl_TessLevelOuter[0] = 1;\n" " gl_TessLevelOuter[1] = 1;\n" " gl_TessLevelOuter[2] = 1;\n" "}\n"; programCollection.glslSources.add("tesc") << glu::TessellationControlSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_tessellation_shader : require\n" "#extension GL_EXT_ray_query : require\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "in gl_PerVertex {\n" " vec4 gl_Position;\n" "} gl_in[];\n" "layout(vertices = 3) out;\n" "void main (void)\n" "{\n" " vec3 origin = vec3(gl_in[gl_InvocationID].gl_Position.x + 0.5, gl_in[gl_InvocationID].gl_Position.y + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_PrimitiveID, gl_InvocationID, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_PrimitiveID, gl_InvocationID, 1), uvec4(hitValue.y, 0, 0, 0));\n" " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" " gl_TessLevelInner[0] = 1;\n" " gl_TessLevelOuter[0] = 1;\n" " gl_TessLevelOuter[1] = 1;\n" " gl_TessLevelOuter[2] = 1;\n" "}\n"; std::stringstream cssName; cssName << "tesc_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::TessellationControlSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_tessellation_shader : require\n" "#extension GL_EXT_ray_query : require\n" "layout(triangles, equal_spacing, ccw) in;\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main (void)\n" "{\n" " for (int i = 0; i < 3; ++i)\n" " {\n" " vec3 origin = vec3(gl_in[i].gl_Position.x + 0.5, gl_in[i].gl_Position.y + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_PrimitiveID, i, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_PrimitiveID, i, 1), uvec4(hitValue.y, 0, 0, 0));\n" " }\n" " gl_Position = gl_in[0].gl_Position;\n" "}\n"; std::stringstream cssName; cssName << "tese_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::TessellationEvaluationSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_tessellation_shader : require\n" "layout(triangles, equal_spacing, ccw) in;\n" "void main (void)\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" "}\n"; programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_query : require\n" "layout(triangles) in;\n" "layout (triangle_strip, max_vertices = 4) out;\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "\n" "in gl_PerVertex {\n" " vec4 gl_Position;\n" "} gl_in[];\n" "layout(location = 0) in int vertexIndex[];\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main (void)\n" "{\n" " // geometry shader may reorder the vertices, keeping only the winding of the triangles.\n" " // To iterate from the 'first vertex' of the triangle we need to find it first by looking for\n" " // smallest vertex index value.\n" " int minVertexIndex = 10000;" " int firstVertex;" " for (int i = 0; i < gl_in.length(); ++i)\n" " {\n" " if (minVertexIndex > vertexIndex[i])\n" " {\n" " minVertexIndex = vertexIndex[i];\n" " firstVertex = i;\n" " }\n" " }\n" " for (int j = 0; j < gl_in.length(); ++j)\n" " {\n" " // iterate starting at firstVertex, possibly wrapping around, so the triangle is\n" " // always iterated starting from the smallest vertex index, as found above.\n" " int i = (firstVertex + j) % gl_in.length();\n" " vec3 origin = vec3(gl_in[i].gl_Position.x + 0.5, gl_in[i].gl_Position.y + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_PrimitiveIDIn, j, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_PrimitiveIDIn, j, 1), uvec4(hitValue.y, 0, 0, 0));\n" " gl_Position = gl_in[i].gl_Position;\n" " EmitVertex();\n" " }\n" " EndPrimitive();\n" "}\n"; std::stringstream cssName; cssName << "geom_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::GeometrySource(css.str()) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_query : require\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = vec3(gl_FragCoord.x, gl_FragCoord.y, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_FragCoord.xy-vec2(0.5,0.5), 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_FragCoord.xy-vec2(0.5,0.5), 1), uvec4(hitValue.y, 0, 0, 0));\n" "}\n"; std::stringstream cssName; cssName << "frag_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::FragmentSource(css.str()) << buildOptions; } } else if (m_data.shaderSourcePipeline == SSP_COMPUTE_PIPELINE) { { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_query : require\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = vec3(float(gl_GlobalInvocationID.x) + 0.5, float(gl_GlobalInvocationID.y) + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_GlobalInvocationID.xy, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_GlobalInvocationID.xy, 1), uvec4(hitValue.y, 0, 0, 0));\n" "}\n"; std::stringstream cssName; cssName << "comp_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::ComputeSource(css.str()) << buildOptions; } } else if (m_data.shaderSourcePipeline == SSP_RAY_TRACING_PIPELINE) { { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "layout(location = 0) rayPayloadEXT uvec4 hitValue;\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n" "void main()\n" "{\n" " float tmin = 0.0;\n" " float tmax = 1.0;\n" " vec3 origin = vec3(float(gl_LaunchIDEXT.x) + 0.5, float(gl_LaunchIDEXT.y) + 0.5, 0.5);\n" " vec3 direct = vec3(0.0, 0.0, -1.0);\n" " hitValue = uvec4(0,0,0,0);\n" " traceRayEXT(topLevelAS, 0, 0xFF, 0, 0, 0, origin, tmin, direct, tmax, 0);\n" " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 1), uvec4(hitValue.y, 0, 0, 0));\n" "}\n"; programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = vec3(float(gl_LaunchIDEXT.x) + 0.5, float(gl_LaunchIDEXT.y) + 0.5, 0.5);\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 0), uvec4(hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 1), uvec4(hitValue.y, 0, 0, 0));\n" "}\n"; std::stringstream cssName; cssName << "rgen_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "struct CallValue\n{\n" " vec3 origin;\n" " uvec4 hitValue;\n" "};\n" "layout(location = 0) callableDataEXT CallValue param;\n" "layout(r32ui, set = 0, binding = 0) uniform uimage3D result;\n" "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n" "void main()\n" "{\n" " param.origin = vec3(float(gl_LaunchIDEXT.x) + 0.5, float(gl_LaunchIDEXT.y) + 0.5, 0.5);\n" " param.hitValue = uvec4(0, 0, 0, 0);\n" " executeCallableEXT(0, 0);\n" " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 0), uvec4(param.hitValue.x, 0, 0, 0));\n" " imageStore(result, ivec3(gl_LaunchIDEXT.xy, 1), uvec4(param.hitValue.y, 0, 0, 0));\n" "}\n"; programCollection.glslSources.add("rgen_call") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "hitAttributeEXT uvec4 hitValue;\n" "void main()\n" "{\n" " reportIntersectionEXT(0.5f, 0);\n" "}\n"; programCollection.glslSources.add("isect") << glu::IntersectionSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "hitAttributeEXT uvec4 hitValue;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = gl_WorldRayOriginEXT;\n" " hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " reportIntersectionEXT(0.5f, 0);\n" "}\n"; std::stringstream cssName; cssName << "isect_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::IntersectionSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = gl_WorldRayOriginEXT;\n" << rayQueryTest[m_data.bottomTestType] << "}\n"; std::stringstream cssName; cssName << "ahit_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::AnyHitSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "void main()\n" "{\n" " hitValue.y = 3;\n" "}\n"; programCollection.glslSources.add("chit") << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = gl_WorldRayOriginEXT;\n" << rayQueryTest[m_data.bottomTestType] << "}\n"; std::stringstream cssName; cssName << "chit_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "hitAttributeEXT uvec4 hitAttrib;\n" "void main()\n" "{\n" " hitValue = hitAttrib;\n" "}\n"; programCollection.glslSources.add("chit_isect") << glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "void main()\n" "{\n" " hitValue.x = 4;\n" "}\n"; programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = gl_WorldRayOriginEXT;\n" << rayQueryTest[m_data.bottomTestType] << "}\n"; std::stringstream cssName; cssName << "miss_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions; } { std::stringstream css; css << "#version 460 core\n" "#extension GL_EXT_ray_tracing : require\n" "#extension GL_EXT_ray_query : require\n" "struct CallValue\n{\n" " vec3 origin;\n" " uvec4 hitValue;\n" "};\n" "layout(location = 0) callableDataInEXT CallValue result;\n" "layout(set = 0, binding = 2) uniform accelerationStructureEXT rqTopLevelAS;\n" "void main()\n" "{\n" " vec3 origin = result.origin;\n" " uvec4 hitValue = uvec4(0,0,0,0);\n" << rayQueryTest[m_data.bottomTestType] << " result.hitValue = hitValue;\n" "}\n"; std::stringstream cssName; cssName << "call_" << rayQueryTestName[m_data.bottomTestType]; programCollection.glslSources.add(cssName.str()) << glu::CallableSource(updateRayTracingGLSL(css.str())) << buildOptions; } } } TestInstance* RayQueryASBasicTestCase::createInstance (Context& context) const { return new RayQueryASBasicTestInstance(context, m_data); } RayQueryASFuncArgTestCase::RayQueryASFuncArgTestCase (tcu::TestContext& context, const char* name, const char* desc, const TestParams& data) : RayQueryASBasicTestCase (context, name, desc, data) { } void RayQueryASFuncArgTestCase::initPrograms (SourceCollections& programCollection) const { const vk::SpirVAsmBuildOptions spvBuildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true); DE_ASSERT(m_data.shaderSourcePipeline == SSP_COMPUTE_PIPELINE); DE_ASSERT(m_data.bottomTestType == BTT_TRIANGLES); // The SPIR-V assembly shader below is based on the following GLSL code. // In it, rayQueryInitializeBottomWrapper has been modified to take a // bare AS as the second argument, instead of a pointer. // // #version 460 core // #extension GL_EXT_ray_query : require // layout(r32ui, set = 0, binding = 0) uniform uimage3D result; // layout(set = 0, binding = 1) uniform accelerationStructureEXT rqTopLevelAS; // // void rayQueryInitializeBottomWrapper(rayQueryEXT rayQuery, // accelerationStructureEXT topLevel, // uint rayFlags, uint cullMask, vec3 origin, // float tMin, vec3 direction, float tMax) // { // rayQueryInitializeEXT(rayQuery, topLevel, rayFlags, cullMask, origin, tMin, direction, tMax); // } // // void rayQueryInitializeTopWrapper(rayQueryEXT rayQuery, // accelerationStructureEXT topLevel, // uint rayFlags, uint cullMask, vec3 origin, // float tMin, vec3 direction, float tMax) // { // rayQueryInitializeBottomWrapper(rayQuery, topLevel, rayFlags, cullMask, origin, tMin, direction, tMax); // } // // void main() // { // vec3 origin = vec3(float(gl_GlobalInvocationID.x) + 0.5, float(gl_GlobalInvocationID.y) + 0.5, 0.5); // uvec4 hitValue = uvec4(0,0,0,0); // float tmin = 0.0; // float tmax = 1.0; // vec3 direct = vec3(0.0, 0.0, -1.0); // rayQueryEXT rq; // rayQueryInitializeTopWrapper(rq, rqTopLevelAS, 0, 0xFF, origin, tmin, direct, tmax); // if(rayQueryProceedEXT(rq)) // { // if (rayQueryGetIntersectionTypeEXT(rq, false)==gl_RayQueryCandidateIntersectionTriangleEXT) // { // hitValue.y = 1; // hitValue.x = 1; // } // } // imageStore(result, ivec3(gl_GlobalInvocationID.xy, 0), uvec4(hitValue.x, 0, 0, 0)); // imageStore(result, ivec3(gl_GlobalInvocationID.xy, 1), uvec4(hitValue.y, 0, 0, 0)); // } std::stringstream css; css << "; SPIR-V\n" << "; Version: 1.4\n" << "; Generator: Khronos Glslang Reference Front End; 10\n" << "; Bound: 139\n" << "; Schema: 0\n" << "OpCapability Shader\n" << "OpCapability RayQueryKHR\n" << "OpExtension \"SPV_KHR_ray_query\"\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint GLCompute %4 \"main\" %60 %86 %114\n" << "OpExecutionMode %4 LocalSize 1 1 1\n" << "OpDecorate %60 BuiltIn GlobalInvocationId\n" << "OpDecorate %86 DescriptorSet 0\n" << "OpDecorate %86 Binding 1\n" << "OpDecorate %114 DescriptorSet 0\n" << "OpDecorate %114 Binding 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" // Bare query type << "%6 = OpTypeRayQueryKHR\n" // Pointer to query. << "%7 = OpTypePointer Function %6\n" // Bare AS type. << "%8 = OpTypeAccelerationStructureKHR\n" // Pointer to AS. << "%9 = OpTypePointer UniformConstant %8\n" << "%10 = OpTypeInt 32 0\n" << "%11 = OpTypePointer Function %10\n" << "%12 = OpTypeFloat 32\n" << "%13 = OpTypeVector %12 3\n" << "%14 = OpTypePointer Function %13\n" << "%15 = OpTypePointer Function %12\n" // This is the function type for rayQueryInitializeTopWrapper and the old rayQueryInitializeBottomWrapper. << "%16 = OpTypeFunction %2 %7 %9 %11 %11 %14 %15 %14 %15\n" // This is the new function type for the modified rayQueryInitializeBottomWrapper that uses a bare AS. //<< "%16b = OpTypeFunction %2 %6 %8 %11 %11 %14 %15 %14 %15\n" << "%16b = OpTypeFunction %2 %7 %8 %11 %11 %14 %15 %14 %15\n" << "%58 = OpTypeVector %10 3\n" << "%59 = OpTypePointer Input %58\n" << "%60 = OpVariable %59 Input\n" << "%61 = OpConstant %10 0\n" << "%62 = OpTypePointer Input %10\n" << "%66 = OpConstant %12 0.5\n" << "%68 = OpConstant %10 1\n" << "%74 = OpTypeVector %10 4\n" << "%75 = OpTypePointer Function %74\n" << "%77 = OpConstantComposite %74 %61 %61 %61 %61\n" << "%79 = OpConstant %12 0\n" << "%81 = OpConstant %12 1\n" << "%83 = OpConstant %12 -1\n" << "%84 = OpConstantComposite %13 %79 %79 %83\n" << "%86 = OpVariable %9 UniformConstant\n" << "%87 = OpConstant %10 255\n" << "%99 = OpTypeBool\n" << "%103 = OpConstantFalse %99\n" << "%104 = OpTypeInt 32 1\n" << "%105 = OpConstant %104 0\n" << "%112 = OpTypeImage %10 3D 0 0 0 2 R32ui\n" << "%113 = OpTypePointer UniformConstant %112\n" << "%114 = OpVariable %113 UniformConstant\n" << "%116 = OpTypeVector %10 2\n" << "%119 = OpTypeVector %104 2\n" << "%121 = OpTypeVector %104 3\n" << "%132 = OpConstant %104 1\n" // This is main(). << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%57 = OpVariable %14 Function\n" << "%76 = OpVariable %75 Function\n" << "%78 = OpVariable %15 Function\n" << "%80 = OpVariable %15 Function\n" << "%82 = OpVariable %14 Function\n" << "%85 = OpVariable %7 Function\n" << "%88 = OpVariable %11 Function\n" << "%89 = OpVariable %11 Function\n" << "%90 = OpVariable %14 Function\n" << "%92 = OpVariable %15 Function\n" << "%94 = OpVariable %14 Function\n" << "%96 = OpVariable %15 Function\n" << "%63 = OpAccessChain %62 %60 %61\n" << "%64 = OpLoad %10 %63\n" << "%65 = OpConvertUToF %12 %64\n" << "%67 = OpFAdd %12 %65 %66\n" << "%69 = OpAccessChain %62 %60 %68\n" << "%70 = OpLoad %10 %69\n" << "%71 = OpConvertUToF %12 %70\n" << "%72 = OpFAdd %12 %71 %66\n" << "%73 = OpCompositeConstruct %13 %67 %72 %66\n" << "OpStore %57 %73\n" << "OpStore %76 %77\n" << "OpStore %78 %79\n" << "OpStore %80 %81\n" << "OpStore %82 %84\n" << "OpStore %88 %61\n" << "OpStore %89 %87\n" << "%91 = OpLoad %13 %57\n" << "OpStore %90 %91\n" << "%93 = OpLoad %12 %78\n" << "OpStore %92 %93\n" << "%95 = OpLoad %13 %82\n" << "OpStore %94 %95\n" << "%97 = OpLoad %12 %80\n" << "OpStore %96 %97\n" << "%98 = OpFunctionCall %2 %35 %85 %86 %88 %89 %90 %92 %94 %96\n" << "%100 = OpRayQueryProceedKHR %99 %85\n" << "OpSelectionMerge %102 None\n" << "OpBranchConditional %100 %101 %102\n" << "%101 = OpLabel\n" << "%106 = OpRayQueryGetIntersectionTypeKHR %10 %85 %105\n" << "%107 = OpIEqual %99 %106 %61\n" << "OpSelectionMerge %109 None\n" << "OpBranchConditional %107 %108 %109\n" << "%108 = OpLabel\n" << "%110 = OpAccessChain %11 %76 %68\n" << "OpStore %110 %68\n" << "%111 = OpAccessChain %11 %76 %61\n" << "OpStore %111 %68\n" << "OpBranch %109\n" << "%109 = OpLabel\n" << "OpBranch %102\n" << "%102 = OpLabel\n" << "%115 = OpLoad %112 %114\n" << "%117 = OpLoad %58 %60\n" << "%118 = OpVectorShuffle %116 %117 %117 0 1\n" << "%120 = OpBitcast %119 %118\n" << "%122 = OpCompositeExtract %104 %120 0\n" << "%123 = OpCompositeExtract %104 %120 1\n" << "%124 = OpCompositeConstruct %121 %122 %123 %105\n" << "%125 = OpAccessChain %11 %76 %61\n" << "%126 = OpLoad %10 %125\n" << "%127 = OpCompositeConstruct %74 %126 %61 %61 %61\n" << "OpImageWrite %115 %124 %127 ZeroExtend\n" << "%128 = OpLoad %112 %114\n" << "%129 = OpLoad %58 %60\n" << "%130 = OpVectorShuffle %116 %129 %129 0 1\n" << "%131 = OpBitcast %119 %130\n" << "%133 = OpCompositeExtract %104 %131 0\n" << "%134 = OpCompositeExtract %104 %131 1\n" << "%135 = OpCompositeConstruct %121 %133 %134 %132\n" << "%136 = OpAccessChain %11 %76 %68\n" << "%137 = OpLoad %10 %136\n" << "%138 = OpCompositeConstruct %74 %137 %61 %61 %61\n" << "OpImageWrite %128 %135 %138 ZeroExtend\n" << "OpReturn\n" << "OpFunctionEnd\n" // This is rayQueryInitializeBottomWrapper, calling OpRayQueryInitializeKHR. // We have modified the function type so it takes bare arguments. //%25 = OpFunction %2 None %16 << "%25 = OpFunction %2 None %16b\n" // These is the modified parameter. << "%17 = OpFunctionParameter %7\n" //<< "%17 = OpFunctionParameter %6\n" //%18 = OpFunctionParameter %9 << "%18 = OpFunctionParameter %8\n" << "%19 = OpFunctionParameter %11\n" << "%20 = OpFunctionParameter %11\n" << "%21 = OpFunctionParameter %14\n" << "%22 = OpFunctionParameter %15\n" << "%23 = OpFunctionParameter %14\n" << "%24 = OpFunctionParameter %15\n" << "%26 = OpLabel\n" // We no longer need to load this parameter. //%37 = OpLoad %8 %18 << "%38 = OpLoad %10 %19\n" << "%39 = OpLoad %10 %20\n" << "%40 = OpLoad %13 %21\n" << "%41 = OpLoad %12 %22\n" << "%42 = OpLoad %13 %23\n" << "%43 = OpLoad %12 %24\n" // We call OpRayQueryInitializeKHR with bare arguments. // Note: some experimental lines to pass a bare rayQuery as the first argument have been commented out. //OpRayQueryInitializeKHR %17 %37 %38 %39 %40 %41 %42 %43 << "OpRayQueryInitializeKHR %17 %18 %38 %39 %40 %41 %42 %43\n" << "OpReturn\n" << "OpFunctionEnd\n" // This is rayQueryInitializeTopWrapper, calling rayQueryInitializeBottomWrapper. << "%35 = OpFunction %2 None %16\n" << "%27 = OpFunctionParameter %7\n" << "%28 = OpFunctionParameter %9\n" << "%29 = OpFunctionParameter %11\n" << "%30 = OpFunctionParameter %11\n" << "%31 = OpFunctionParameter %14\n" << "%32 = OpFunctionParameter %15\n" << "%33 = OpFunctionParameter %14\n" << "%34 = OpFunctionParameter %15\n" << "%36 = OpLabel\n" << "%44 = OpVariable %11 Function\n" << "%46 = OpVariable %11 Function\n" << "%48 = OpVariable %14 Function\n" << "%50 = OpVariable %15 Function\n" << "%52 = OpVariable %14 Function\n" << "%54 = OpVariable %15 Function\n" // We need to load the second argument. //<< "%27b = OpLoad %6 %27\n" << "%28b = OpLoad %8 %28\n" << "%45 = OpLoad %10 %29\n" << "OpStore %44 %45\n" << "%47 = OpLoad %10 %30\n" << "OpStore %46 %47\n" << "%49 = OpLoad %13 %31\n" << "OpStore %48 %49\n" << "%51 = OpLoad %12 %32\n" << "OpStore %50 %51\n" << "%53 = OpLoad %13 %33\n" << "OpStore %52 %53\n" << "%55 = OpLoad %12 %34\n" << "OpStore %54 %55\n" // We call rayQueryInitializeBottomWrapper with the loaded argument. //%56 = OpFunctionCall %2 %25 %27 %28 %44 %46 %48 %50 %52 %54 //<< "%56 = OpFunctionCall %2 %25 %27b %28b %44 %46 %48 %50 %52 %54\n" << "%56 = OpFunctionCall %2 %25 %27 %28b %44 %46 %48 %50 %52 %54\n" << "OpReturn\n" << "OpFunctionEnd\n" ; programCollection.spirvAsmSources.add("comp_as_triangle") << spvBuildOptions << css.str(); } RayQueryASBasicTestInstance::RayQueryASBasicTestInstance (Context& context, const TestParams& data) : vkt::TestInstance (context) , m_data (data) { } RayQueryASBasicTestInstance::~RayQueryASBasicTestInstance (void) { } de::MovePtr RayQueryASBasicTestInstance::runTest (TestConfiguration* testConfiguration, SceneBuilder* sceneBuilder, const deUint32 workerThreadsCount) { testConfiguration->initConfiguration(m_context, m_data); const DeviceInterface& vkd = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); Allocator& allocator = m_context.getDefaultAllocator(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); const bool htCopy = (workerThreadsCount != 0) && (m_data.operationType == OP_COPY); const bool htSerialize = (workerThreadsCount != 0) && (m_data.operationType == OP_SERIALIZE); const VkFormat imageFormat = testConfiguration->getResultImageFormat(); const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_data.width, m_data.height, 2, imageFormat); const VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); const de::MovePtr image = de::MovePtr(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any)); const Move imageView = makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_3D, imageFormat, imageSubresourceRange); const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(m_data.width * m_data.height * 2 * testConfiguration->getResultImageFormatSize(), VK_BUFFER_USAGE_TRANSFER_DST_BIT); const VkImageSubresourceLayers resultBufferImageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); const VkBufferImageCopy resultBufferImageRegion = makeBufferImageCopy(makeExtent3D(m_data.width, m_data.height, 2), resultBufferImageSubresourceLayers); de::MovePtr resultBuffer = de::MovePtr(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible)); const VkDescriptorImageInfo resultImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL); const Move cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex); const Move cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); std::vector> bottomLevelAccelerationStructures; de::MovePtr topLevelAccelerationStructure; std::vector> bottomLevelAccelerationStructureCopies; de::MovePtr topLevelAccelerationStructureCopy; std::vector> bottomSerialized; std::vector> topSerialized; std::vector accelerationCompactedSizes; std::vector accelerationSerialSizes; Move m_queryPoolCompact; Move m_queryPoolSerial; beginCommandBuffer(vkd, *cmdBuffer, 0u); { const VkImageMemoryBarrier preImageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **image, imageSubresourceRange); cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preImageBarrier); const VkClearValue clearValue = testConfiguration->getClearValue(); vkd.cmdClearColorImage(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &imageSubresourceRange); const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, **image, imageSubresourceRange); cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, &postImageBarrier); // build bottom level acceleration structures and their copies ( only when we are testing copying bottom level acceleration structures ) bool bottomCompact = m_data.operationType == OP_COMPACT && m_data.operationTarget == OT_BOTTOM_ACCELERATION; bool bottomSerial = m_data.operationType == OP_SERIALIZE && m_data.operationTarget == OT_BOTTOM_ACCELERATION; const bool buildWithoutGeom = (m_data.emptyASCase == EmptyAccelerationStructureCase::NO_GEOMETRIES_BOTTOM); const bool bottomNoPrimitives = (m_data.emptyASCase == EmptyAccelerationStructureCase::NO_PRIMITIVES_BOTTOM); const bool topNoPrimitives = (m_data.emptyASCase == EmptyAccelerationStructureCase::NO_PRIMITIVES_TOP); const bool inactiveInstances = (m_data.emptyASCase == EmptyAccelerationStructureCase::INACTIVE_INSTANCES); bottomLevelAccelerationStructures = sceneBuilder->initBottomAccelerationStructures(m_context, m_data); VkBuildAccelerationStructureFlagsKHR allowCompactionFlag = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR; VkBuildAccelerationStructureFlagsKHR emptyCompactionFlag = VkBuildAccelerationStructureFlagsKHR(0); VkBuildAccelerationStructureFlagsKHR bottomCompactFlags = (bottomCompact ? allowCompactionFlag : emptyCompactionFlag); VkBuildAccelerationStructureFlagsKHR bottomBuildFlags = m_data.buildFlags | bottomCompactFlags; std::vector accelerationStructureHandles; std::vector bottomBlasCompactSize; std::vector bottomBlasSerialSize; for (auto& blas : bottomLevelAccelerationStructures) { blas->setBuildType (m_data.buildType); blas->setBuildFlags (bottomBuildFlags); blas->setUseArrayOfPointers (m_data.bottomUsesAOP); blas->setCreateGeneric (m_data.bottomGeneric); blas->setBuildWithoutGeometries (buildWithoutGeom); blas->setBuildWithoutPrimitives (bottomNoPrimitives); blas->createAndBuild (vkd, device, *cmdBuffer, allocator); accelerationStructureHandles.push_back (*(blas->getPtr())); } if (m_data.operationType == OP_COMPACT) { deUint32 queryCount = (m_data.operationTarget == OT_BOTTOM_ACCELERATION) ? deUint32(bottomLevelAccelerationStructures.size()) : 1u; if (m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) m_queryPoolCompact = makeQueryPool(vkd, device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, queryCount); if (m_data.operationTarget == OT_BOTTOM_ACCELERATION) queryAccelerationStructureSize(vkd, device, *cmdBuffer, accelerationStructureHandles, m_data.buildType, m_queryPoolCompact.get(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 0u, bottomBlasCompactSize); } if (m_data.operationType == OP_SERIALIZE) { deUint32 queryCount = (m_data.operationTarget == OT_BOTTOM_ACCELERATION) ? deUint32(bottomLevelAccelerationStructures.size()) : 1u; if (m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) m_queryPoolSerial = makeQueryPool(vkd, device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, queryCount); if (m_data.operationTarget == OT_BOTTOM_ACCELERATION) queryAccelerationStructureSize(vkd, device, *cmdBuffer, accelerationStructureHandles, m_data.buildType, m_queryPoolSerial.get(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, 0u, bottomBlasSerialSize); } // if AS is built on GPU and we are planning to make a compact copy of it or serialize / deserialize it - we have to have download query results to CPU if ((m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) && (bottomCompact || bottomSerial)) { endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); if (bottomCompact) VK_CHECK(vkd.getQueryPoolResults(device, *m_queryPoolCompact, 0u, deUint32(bottomBlasCompactSize.size()), sizeof(VkDeviceSize) * bottomBlasCompactSize.size(), bottomBlasCompactSize.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); if (bottomSerial) VK_CHECK(vkd.getQueryPoolResults(device, *m_queryPoolSerial, 0u, deUint32(bottomBlasSerialSize.size()), sizeof(VkDeviceSize) * bottomBlasSerialSize.size(), bottomBlasSerialSize.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); vkd.resetCommandPool(device, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); beginCommandBuffer(vkd, *cmdBuffer, 0u); } auto bottomLevelAccelerationStructuresPtr = &bottomLevelAccelerationStructures; if (m_data.operationType != OP_NONE && m_data.operationTarget == OT_BOTTOM_ACCELERATION) { switch (m_data.operationType) { case OP_COPY: { for (size_t i = 0; i < bottomLevelAccelerationStructures.size(); ++i) { de::MovePtr asCopy = makeBottomLevelAccelerationStructure(); asCopy->setDeferredOperation(htCopy, workerThreadsCount); asCopy->setBuildType(m_data.buildType); asCopy->setBuildFlags(m_data.buildFlags); asCopy->setUseArrayOfPointers(m_data.bottomUsesAOP); asCopy->setCreateGeneric(m_data.bottomGeneric); asCopy->setBuildWithoutGeometries(buildWithoutGeom); asCopy->setBuildWithoutPrimitives(bottomNoPrimitives); asCopy->createAndCopyFrom(vkd, device, *cmdBuffer, allocator, bottomLevelAccelerationStructures[i].get(), 0u, 0u); bottomLevelAccelerationStructureCopies.push_back(de::SharedPtr(asCopy.release())); } break; } case OP_COMPACT: { for (size_t i = 0; i < bottomLevelAccelerationStructures.size(); ++i) { de::MovePtr asCopy = makeBottomLevelAccelerationStructure(); asCopy->setBuildType(m_data.buildType); asCopy->setBuildFlags(m_data.buildFlags); asCopy->setUseArrayOfPointers(m_data.bottomUsesAOP); asCopy->setCreateGeneric(m_data.bottomGeneric); asCopy->setBuildWithoutGeometries(buildWithoutGeom); asCopy->setBuildWithoutPrimitives(bottomNoPrimitives); asCopy->createAndCopyFrom(vkd, device, *cmdBuffer, allocator, bottomLevelAccelerationStructures[i].get(), bottomBlasCompactSize[i], 0u); bottomLevelAccelerationStructureCopies.push_back(de::SharedPtr(asCopy.release())); } break; } case OP_SERIALIZE: { for (size_t i = 0; i < bottomLevelAccelerationStructures.size(); ++i) { de::SharedPtr storage(new SerialStorage(vkd, device, allocator, m_data.buildType, bottomBlasSerialSize[i])); bottomLevelAccelerationStructures[i]->setDeferredOperation(htSerialize, workerThreadsCount); bottomLevelAccelerationStructures[i]->serialize(vkd, device, *cmdBuffer, storage.get()); bottomSerialized.push_back(storage); if (m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) { endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); vkd.resetCommandPool(device, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); beginCommandBuffer(vkd, *cmdBuffer, 0u); } de::MovePtr asCopy = makeBottomLevelAccelerationStructure(); asCopy->setBuildType(m_data.buildType); asCopy->setBuildFlags(m_data.buildFlags); asCopy->setUseArrayOfPointers(m_data.bottomUsesAOP); asCopy->setCreateGeneric(m_data.bottomGeneric); asCopy->setBuildWithoutGeometries(buildWithoutGeom); asCopy->setBuildWithoutPrimitives(bottomNoPrimitives); asCopy->setDeferredOperation(htSerialize, workerThreadsCount); asCopy->createAndDeserializeFrom(vkd, device, *cmdBuffer, allocator, storage.get(), 0u); bottomLevelAccelerationStructureCopies.push_back(de::SharedPtr(asCopy.release())); } break; } default: DE_ASSERT(DE_FALSE); } bottomLevelAccelerationStructuresPtr = &bottomLevelAccelerationStructureCopies; } // build top level acceleration structures and their copies ( only when we are testing copying top level acceleration structures ) bool topCompact = m_data.operationType == OP_COMPACT && m_data.operationTarget == OT_TOP_ACCELERATION; bool topSerial = m_data.operationType == OP_SERIALIZE && m_data.operationTarget == OT_TOP_ACCELERATION; VkBuildAccelerationStructureFlagsKHR topCompactFlags = (topCompact ? allowCompactionFlag : emptyCompactionFlag); VkBuildAccelerationStructureFlagsKHR topBuildFlags = m_data.buildFlags | topCompactFlags; std::vector topLevelStructureHandles; std::vector topBlasCompactSize; std::vector topBlasSerialSize; topLevelAccelerationStructure = sceneBuilder->initTopAccelerationStructure(m_context, m_data, *bottomLevelAccelerationStructuresPtr); topLevelAccelerationStructure->setBuildType (m_data.buildType); topLevelAccelerationStructure->setBuildFlags (topBuildFlags); topLevelAccelerationStructure->setBuildWithoutPrimitives (topNoPrimitives); topLevelAccelerationStructure->setUseArrayOfPointers (m_data.topUsesAOP); topLevelAccelerationStructure->setCreateGeneric (m_data.topGeneric); topLevelAccelerationStructure->setInactiveInstances (inactiveInstances); topLevelAccelerationStructure->createAndBuild (vkd, device, *cmdBuffer, allocator); topLevelStructureHandles.push_back (*(topLevelAccelerationStructure->getPtr())); if (topCompact) queryAccelerationStructureSize(vkd, device, *cmdBuffer, topLevelStructureHandles, m_data.buildType, m_queryPoolCompact.get(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 0u, topBlasCompactSize); if (topSerial) queryAccelerationStructureSize(vkd, device, *cmdBuffer, topLevelStructureHandles, m_data.buildType, m_queryPoolSerial.get(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, 0u, topBlasSerialSize); // if AS is built on GPU and we are planning to make a compact copy of it or serialize / deserialize it - we have to have download query results to CPU if ((m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) && (topCompact || topSerial)) { endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); if (topCompact) VK_CHECK(vkd.getQueryPoolResults(device, *m_queryPoolCompact, 0u, deUint32(topBlasCompactSize.size()), sizeof(VkDeviceSize) * topBlasCompactSize.size(), topBlasCompactSize.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); if (topSerial) VK_CHECK(vkd.getQueryPoolResults(device, *m_queryPoolSerial, 0u, deUint32(topBlasSerialSize.size()), sizeof(VkDeviceSize) * topBlasSerialSize.size(), topBlasSerialSize.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); vkd.resetCommandPool(device, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); beginCommandBuffer(vkd, *cmdBuffer, 0u); } const TopLevelAccelerationStructure* topLevelRayTracedPtr = topLevelAccelerationStructure.get(); if (m_data.operationType != OP_NONE && m_data.operationTarget == OT_TOP_ACCELERATION) { switch (m_data.operationType) { case OP_COPY: { topLevelAccelerationStructureCopy = makeTopLevelAccelerationStructure(); topLevelAccelerationStructureCopy->setDeferredOperation(htCopy, workerThreadsCount); topLevelAccelerationStructureCopy->setBuildType(m_data.buildType); topLevelAccelerationStructureCopy->setBuildFlags(m_data.buildFlags); topLevelAccelerationStructureCopy->setBuildWithoutPrimitives(topNoPrimitives); topLevelAccelerationStructureCopy->setInactiveInstances(inactiveInstances); topLevelAccelerationStructureCopy->setUseArrayOfPointers(m_data.topUsesAOP); topLevelAccelerationStructureCopy->setCreateGeneric(m_data.topGeneric); topLevelAccelerationStructureCopy->createAndCopyFrom(vkd, device, *cmdBuffer, allocator, topLevelAccelerationStructure.get(), 0u, 0u); break; } case OP_COMPACT: { topLevelAccelerationStructureCopy = makeTopLevelAccelerationStructure(); topLevelAccelerationStructureCopy->setBuildType(m_data.buildType); topLevelAccelerationStructureCopy->setBuildFlags(m_data.buildFlags); topLevelAccelerationStructureCopy->setBuildWithoutPrimitives(topNoPrimitives); topLevelAccelerationStructureCopy->setInactiveInstances(inactiveInstances); topLevelAccelerationStructureCopy->setUseArrayOfPointers(m_data.topUsesAOP); topLevelAccelerationStructureCopy->setCreateGeneric(m_data.topGeneric); topLevelAccelerationStructureCopy->createAndCopyFrom(vkd, device, *cmdBuffer, allocator, topLevelAccelerationStructure.get(), topBlasCompactSize[0], 0u); break; } case OP_SERIALIZE: { de::SharedPtr storage(new SerialStorage(vkd, device, allocator, m_data.buildType, topBlasSerialSize[0])); topLevelAccelerationStructure->setDeferredOperation(htSerialize, workerThreadsCount); topLevelAccelerationStructure->serialize(vkd, device, *cmdBuffer, storage.get()); topSerialized.push_back(storage); if (m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR) { endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); vkd.resetCommandPool(device, *cmdPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); beginCommandBuffer(vkd, *cmdBuffer, 0u); } topLevelAccelerationStructureCopy = makeTopLevelAccelerationStructure(); topLevelAccelerationStructureCopy->setBuildType(m_data.buildType); topLevelAccelerationStructureCopy->setBuildFlags(m_data.buildFlags); topLevelAccelerationStructureCopy->setBuildWithoutPrimitives(topNoPrimitives); topLevelAccelerationStructureCopy->setInactiveInstances(inactiveInstances); topLevelAccelerationStructureCopy->setUseArrayOfPointers(m_data.topUsesAOP); topLevelAccelerationStructureCopy->setCreateGeneric(m_data.topGeneric); topLevelAccelerationStructureCopy->setDeferredOperation(htSerialize, workerThreadsCount); topLevelAccelerationStructureCopy->createAndDeserializeFrom(vkd, device, *cmdBuffer, allocator, storage.get(), 0u); break; } default: DE_ASSERT(DE_FALSE); } topLevelRayTracedPtr = topLevelAccelerationStructureCopy.get(); } const VkMemoryBarrier preTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &preTraceMemoryBarrier); VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; 1u, // deUint32 accelerationStructureCount; topLevelRayTracedPtr->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures; }; testConfiguration->fillCommandBuffer(m_context, m_data, *cmdBuffer, accelerationStructureWriteDescriptorSet, resultImageInfo); const VkMemoryBarrier postTestMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); const VkMemoryBarrier postCopyMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTestMemoryBarrier); vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u, &resultBufferImageRegion); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier); } endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE); return resultBuffer; } bool RayQueryASBasicTestInstance::iterateNoWorkers (void) { de::SharedPtr testConfiguration = createTestConfiguration(m_data.shaderSourcePipeline); de::SharedPtr sceneBuilder = de::SharedPtr(new CheckerboardSceneBuilder()); const de::MovePtr buffer = runTest(testConfiguration.get(), sceneBuilder.get(), 0); return testConfiguration->verifyImage(buffer.get(), m_context, m_data); } bool RayQueryASBasicTestInstance::iterateWithWorkers (void) { de::SharedPtr sceneBuilder = de::SharedPtr(new CheckerboardSceneBuilder()); de::SharedPtr testConfigurationS = createTestConfiguration(m_data.shaderSourcePipeline); const deUint64 singleThreadTimeStart = deGetMicroseconds(); de::MovePtr singleThreadBufferCPU = runTest(testConfigurationS.get(), sceneBuilder.get(), 0); const bool singleThreadValidation = testConfigurationS->verifyImage(singleThreadBufferCPU.get(), m_context, m_data); const deUint64 singleThreadTime = deGetMicroseconds() - singleThreadTimeStart; testConfigurationS.clear(); de::SharedPtr testConfigurationM = createTestConfiguration(m_data.shaderSourcePipeline); deUint64 multiThreadTimeStart = deGetMicroseconds(); de::MovePtr multiThreadBufferCPU = runTest(testConfigurationM.get(), sceneBuilder.get(), m_data.workerThreadsCount); const bool multiThreadValidation = testConfigurationM->verifyImage(multiThreadBufferCPU.get(), m_context, m_data); deUint64 multiThreadTime = deGetMicroseconds() - multiThreadTimeStart; const deUint64 multiThreadTimeOut = 10 * singleThreadTime; testConfigurationM.clear(); const deUint32 result = singleThreadValidation && multiThreadValidation; if (multiThreadTime > multiThreadTimeOut) { std::string failMsg = "Time of multithreaded test execution " + de::toString(multiThreadTime) + " that is longer than expected execution time " + de::toString(multiThreadTimeOut); TCU_FAIL(failMsg); } return result; } tcu::TestStatus RayQueryASBasicTestInstance::iterate(void) { bool result; if (m_data.workerThreadsCount != 0) result = iterateWithWorkers(); else result = iterateNoWorkers(); if (result) return tcu::TestStatus::pass("Pass"); else return tcu::TestStatus::fail("Fail"); } // Tests dynamic indexing of acceleration structures class RayQueryASDynamicIndexingTestCase : public TestCase { public: RayQueryASDynamicIndexingTestCase (tcu::TestContext& context, const char* name); ~RayQueryASDynamicIndexingTestCase (void) = default; void checkSupport (Context& context) const override; void initPrograms (SourceCollections& programCollection) const override; TestInstance* createInstance (Context& context) const override; }; class RayQueryASDynamicIndexingTestInstance : public TestInstance { public: RayQueryASDynamicIndexingTestInstance (Context& context); ~RayQueryASDynamicIndexingTestInstance (void) = default; tcu::TestStatus iterate (void) override; }; RayQueryASDynamicIndexingTestCase::RayQueryASDynamicIndexingTestCase(tcu::TestContext& context, const char* name) : TestCase(context, name, "") { } void RayQueryASDynamicIndexingTestCase::checkSupport(Context& context) const { commonASTestsCheckSupport(context); context.requireDeviceFunctionality("VK_EXT_descriptor_indexing"); } void RayQueryASDynamicIndexingTestCase::initPrograms(SourceCollections& programCollection) const { const vk::SpirVAsmBuildOptions spvBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true); // compute shader is defined in spir-v as it requires possing pointer to TLAS that was read from ssbo; // original spir-v code was generated using following glsl code but resulting spir-v code was modiifed // #version 460 core // #extension GL_EXT_ray_query : require // #extension GL_EXT_nonuniform_qualifier : enable // #define ARRAY_SIZE 500 // layout(set = 0, binding = 0) uniform accelerationStructureEXT tlasArray[ARRAY_SIZE]; // layout(set = 0, binding = 1) readonly buffer topLevelASPointers { // uvec2 ptr[]; // } tlasPointers; // layout(set = 0, binding = 2) readonly buffer topLevelASIndices { // uint idx[]; // } tlasIndices; // layout(set = 0, binding = 3, std430) writeonly buffer Result { // uint value[]; // } result; // void main() // { // float tmin = 0.0; // float tmax = 2.0; // vec3 origin = vec3(0.25f, 0.5f, 1.0); // vec3 direction = vec3(0.0,0.0,-1.0); // uint tlasIndex = tlasIndices.idx[nonuniformEXT(gl_GlobalInvocationID.x)]; // rayQueryEXT rq; // rayQueryInitializeEXT(rq, tlasArray[nonuniformEXT(tlasIndex)], gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, origin, tmin, direction, tmax); // atomicAdd(result.value[nonuniformEXT(gl_GlobalInvocationID.x)], 2); // if (rayQueryProceedEXT(rq)) // { // if (rayQueryGetIntersectionTypeEXT(rq, false) == gl_RayQueryCandidateIntersectionTriangleEXT) // atomicAdd(result.value[nonuniformEXT(gl_GlobalInvocationID.x + gl_NumWorkGroups.x)], 3); // } // //rayQueryInitializeEXT(rq, tlasArray[nonuniformEXT(tlasIndex)], gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, origin, tmin, direction, tmax); // rayQueryInitializeEXT(rq, *tlasPointers.ptr[nonuniformEXT(tlasIndex)], gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, origin, tmin, direction, tmax); // atomicAdd(result.value[nonuniformEXT(gl_GlobalInvocationID.x + gl_NumWorkGroups.x * 2)], 5); // if (rayQueryProceedEXT(rq)) // { // if (rayQueryGetIntersectionTypeEXT(rq, false) == gl_RayQueryCandidateIntersectionTriangleEXT) // atomicAdd(result.value[nonuniformEXT(gl_GlobalInvocationID.x + gl_NumWorkGroups.x * 3)], 7); // } // } const std::string compSource = "OpCapability Shader\n" "OpCapability RayQueryKHR\n" "OpCapability ShaderNonUniform\n" "OpExtension \"SPV_EXT_descriptor_indexing\"\n" "OpExtension \"SPV_KHR_ray_query\"\n" "%1 = OpExtInstImport \"GLSL.std.450\"\n" "OpMemoryModel Logical GLSL450\n" "OpEntryPoint GLCompute %4 \"main\" %var_index_ssbo %33 %var_as_arr_uni_ptr %64 %83 %var_as_pointers_ssbo\n" "OpExecutionMode %4 LocalSize 1 1 1\n" "OpDecorate %25 ArrayStride 4\n" "OpMemberDecorate %26 0 NonWritable\n" "OpMemberDecorate %26 0 Offset 0\n" "OpDecorate %26 Block\n" "OpDecorate %var_index_ssbo DescriptorSet 0\n" "OpDecorate %var_index_ssbo Binding 2\n" "OpDecorate %33 BuiltIn GlobalInvocationId\n" "OpDecorate %38 NonUniform\n" "OpDecorate %40 NonUniform\n" "OpDecorate %41 NonUniform\n" "OpDecorate %var_as_arr_uni_ptr DescriptorSet 0\n" "OpDecorate %var_as_arr_uni_ptr Binding 0\n" "OpDecorate %51 NonUniform\n" "OpDecorate %53 NonUniform\n" "OpDecorate %54 NonUniform\n" "OpDecorate %61 ArrayStride 4\n" "OpMemberDecorate %62 0 NonReadable\n" "OpMemberDecorate %62 0 Offset 0\n" "OpDecorate %62 Block\n" "OpDecorate %64 DescriptorSet 0\n" "OpDecorate %64 Binding 3\n" "OpDecorate %67 NonUniform\n" "OpDecorate %83 BuiltIn NumWorkgroups\n" "OpDecorate %87 NonUniform\n" "OpDecorate %as_index NonUniform\n" "OpDecorate %as_device_addres NonUniform\n" "OpDecorate %105 NonUniform\n" "OpDecorate %122 NonUniform\n" "OpDecorate %127 ArrayStride 8\n" "OpMemberDecorate %128 0 NonWritable\n" "OpMemberDecorate %128 0 Offset 0\n" "OpDecorate %128 Block\n" "OpDecorate %var_as_pointers_ssbo DescriptorSet 0\n" "OpDecorate %var_as_pointers_ssbo Binding 1\n" "%2 = OpTypeVoid\n" "%3 = OpTypeFunction %2\n" "%6 = OpTypeFloat 32\n" "%7 = OpTypePointer Function %6\n" "%9 = OpConstant %6 0\n" "%11 = OpConstant %6 2\n" "%12 = OpTypeVector %6 3\n" "%13 = OpTypePointer Function %12\n" "%15 = OpConstant %6 0.25\n" "%16 = OpConstant %6 0.5\n" "%17 = OpConstant %6 1\n" "%18 = OpConstantComposite %12 %15 %16 %17\n" "%20 = OpConstant %6 -1\n" "%21 = OpConstantComposite %12 %9 %9 %20\n" "%type_uint32 = OpTypeInt 32 0\n" "%23 = OpTypePointer Function %type_uint32\n" "%25 = OpTypeRuntimeArray %type_uint32\n" "%26 = OpTypeStruct %25\n" "%27 = OpTypePointer StorageBuffer %26\n" "%var_index_ssbo = OpVariable %27 StorageBuffer\n" "%29 = OpTypeInt 32 1\n" "%c_int32_0 = OpConstant %29 0\n" "%31 = OpTypeVector %type_uint32 3\n" "%32 = OpTypePointer Input %31\n" "%33 = OpVariable %32 Input\n" "%34 = OpConstant %type_uint32 0\n" "%35 = OpTypePointer Input %type_uint32\n" "%type_uint32_ssbo_ptr = OpTypePointer StorageBuffer %type_uint32\n" "%42 = OpTypeRayQueryKHR\n" "%43 = OpTypePointer Function %42\n" "%type_as = OpTypeAccelerationStructureKHR\n" "%46 = OpConstant %type_uint32 500\n" "%type_as_arr = OpTypeArray %type_as %46\n" "%type_as_arr_uni_ptr = OpTypePointer UniformConstant %type_as_arr\n" "%var_as_arr_uni_ptr = OpVariable %type_as_arr_uni_ptr UniformConstant\n" "%type_as_uni_ptr = OpTypePointer UniformConstant %type_as\n" "%55 = OpConstant %type_uint32 16\n" "%56 = OpConstant %type_uint32 255\n" "%61 = OpTypeRuntimeArray %type_uint32\n" "%62 = OpTypeStruct %61\n" "%63 = OpTypePointer StorageBuffer %62\n" "%64 = OpVariable %63 StorageBuffer\n" "%69 = OpConstant %type_uint32 2\n" "%70 = OpConstant %type_uint32 1\n" "%72 = OpTypeBool\n" "%76 = OpConstantFalse %72\n" "%83 = OpVariable %32 Input\n" "%89 = OpConstant %type_uint32 3\n" "%107 = OpConstant %type_uint32 5\n" "%124 = OpConstant %type_uint32 7\n" // "%v2uint = OpTypeVector %type_uint32 2\n" "%127 = OpTypeRuntimeArray %v2uint\n" "%128 = OpTypeStruct %127\n" "%129 = OpTypePointer StorageBuffer %128\n" "%var_as_pointers_ssbo = OpVariable %129 StorageBuffer\n" "%type_uint64_ssbo_ptr = OpTypePointer StorageBuffer %v2uint\n" // // void main() "%4 = OpFunction %2 None %3\n" "%5 = OpLabel\n" "%8 = OpVariable %7 Function\n" "%10 = OpVariable %7 Function\n" "%14 = OpVariable %13 Function\n" "%19 = OpVariable %13 Function\n" "%24 = OpVariable %23 Function\n" "%var_ray_query = OpVariable %43 Function\n" "OpStore %8 %9\n" "OpStore %10 %11\n" "OpStore %14 %18\n" "OpStore %19 %21\n" "%36 = OpAccessChain %35 %33 %34\n" "%37 = OpLoad %type_uint32 %36\n" "%38 = OpCopyObject %type_uint32 %37\n" "%40 = OpAccessChain %type_uint32_ssbo_ptr %var_index_ssbo %c_int32_0 %38\n" "%41 = OpLoad %type_uint32 %40\n" "OpStore %24 %41\n" // rayQueryInitializeEXT using AS that was read from array "%50 = OpLoad %type_uint32 %24\n" "%51 = OpCopyObject %type_uint32 %50\n" "%53 = OpAccessChain %type_as_uni_ptr %var_as_arr_uni_ptr %51\n" "%54 = OpLoad %type_as %53\n" "%57 = OpLoad %12 %14\n" "%58 = OpLoad %6 %8\n" "%59 = OpLoad %12 %19\n" "%60 = OpLoad %6 %10\n" "OpRayQueryInitializeKHR %var_ray_query %54 %55 %56 %57 %58 %59 %60\n" "%65 = OpAccessChain %35 %33 %34\n" "%66 = OpLoad %type_uint32 %65\n" "%67 = OpCopyObject %type_uint32 %66\n" "%68 = OpAccessChain %type_uint32_ssbo_ptr %64 %c_int32_0 %67\n" "%71 = OpAtomicIAdd %type_uint32 %68 %70 %34 %69\n" "%73 = OpRayQueryProceedKHR %72 %var_ray_query\n" "OpSelectionMerge %75 None\n" "OpBranchConditional %73 %74 %75\n" "%74 = OpLabel\n" "%77 = OpRayQueryGetIntersectionTypeKHR %type_uint32 %var_ray_query %c_int32_0\n" "%78 = OpIEqual %72 %77 %34\n" "OpSelectionMerge %80 None\n" "OpBranchConditional %78 %79 %80\n" "%79 = OpLabel\n" "%81 = OpAccessChain %35 %33 %34\n" "%82 = OpLoad %type_uint32 %81\n" "%84 = OpAccessChain %35 %83 %34\n" "%85 = OpLoad %type_uint32 %84\n" "%86 = OpIAdd %type_uint32 %82 %85\n" "%87 = OpCopyObject %type_uint32 %86\n" "%88 = OpAccessChain %type_uint32_ssbo_ptr %64 %c_int32_0 %87\n" "%90 = OpAtomicIAdd %type_uint32 %88 %70 %34 %89\n" "OpBranch %80\n" "%80 = OpLabel\n" "OpBranch %75\n" "%75 = OpLabel\n" // rayQueryInitializeEXT using pointer to AS "%91 = OpLoad %type_uint32 %24\n" "%as_index = OpCopyObject %type_uint32 %91\n" // "%as_device_addres_ptr = OpAccessChain %type_uint64_ssbo_ptr %var_as_pointers_ssbo %c_int32_0 %as_index\n" "%as_device_addres = OpLoad %v2uint %as_device_addres_ptr\n" "%as_to_use = OpConvertUToAccelerationStructureKHR %type_as %as_device_addres\n" // "%95 = OpLoad %12 %14\n" "%96 = OpLoad %6 %8\n" "%97 = OpLoad %12 %19\n" "%98 = OpLoad %6 %10\n" "OpRayQueryInitializeKHR %var_ray_query %as_to_use %55 %56 %95 %96 %97 %98\n" "%99 = OpAccessChain %35 %33 %34\n" "%100 = OpLoad %type_uint32 %99\n" "%101 = OpAccessChain %35 %83 %34\n" "%102 = OpLoad %type_uint32 %101\n" "%103 = OpIMul %type_uint32 %102 %69\n" "%104 = OpIAdd %type_uint32 %100 %103\n" "%105 = OpCopyObject %type_uint32 %104\n" "%106 = OpAccessChain %type_uint32_ssbo_ptr %64 %c_int32_0 %105\n" "%108 = OpAtomicIAdd %type_uint32 %106 %70 %34 %107\n" "%109 = OpRayQueryProceedKHR %72 %var_ray_query\n" "OpSelectionMerge %111 None\n" "OpBranchConditional %109 %110 %111\n" "%110 = OpLabel\n" "%112 = OpRayQueryGetIntersectionTypeKHR %type_uint32 %var_ray_query %c_int32_0\n" "%113 = OpIEqual %72 %112 %34\n" "OpSelectionMerge %115 None\n" "OpBranchConditional %113 %114 %115\n" "%114 = OpLabel\n" "%116 = OpAccessChain %35 %33 %34\n" "%117 = OpLoad %type_uint32 %116\n" "%118 = OpAccessChain %35 %83 %34\n" "%119 = OpLoad %type_uint32 %118\n" "%120 = OpIMul %type_uint32 %119 %89\n" "%121 = OpIAdd %type_uint32 %117 %120\n" "%122 = OpCopyObject %type_uint32 %121\n" "%123 = OpAccessChain %type_uint32_ssbo_ptr %64 %c_int32_0 %122\n" "%125 = OpAtomicIAdd %type_uint32 %123 %70 %34 %124\n" "OpBranch %115\n" "%115 = OpLabel\n" "OpBranch %111\n" "%111 = OpLabel\n" "OpReturn\n" "OpFunctionEnd\n"; programCollection.spirvAsmSources.add("comp") << compSource << spvBuildOptions; } TestInstance* RayQueryASDynamicIndexingTestCase::createInstance(Context& context) const { return new RayQueryASDynamicIndexingTestInstance(context); } RayQueryASDynamicIndexingTestInstance::RayQueryASDynamicIndexingTestInstance(Context& context) : vkt::TestInstance(context) { } tcu::TestStatus RayQueryASDynamicIndexingTestInstance::iterate(void) { const DeviceInterface& vkd = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); const VkQueue queue = m_context.getUniversalQueue(); Allocator& allocator = m_context.getDefaultAllocator(); const deUint32 tlasCount = 500; // changing this will require also changing shaders const deUint32 activeTlasCount = 32; // number of tlas out of that will be active const Move descriptorSetLayout = DescriptorSetLayoutBuilder() .addArrayBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, tlasCount, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) // pointers to all acceleration structures .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) // ssbo with indices of all acceleration structures .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) // ssbo with result values .build(vkd, device); const Move descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, tlasCount) .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); const Move descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout); const Move pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get()); Move shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u); const VkComputePipelineCreateInfo pipelineCreateInfo { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext 0u, // VkPipelineCreateFlags flags { // VkPipelineShaderStageCreateInfo stage VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0, VK_SHADER_STAGE_COMPUTE_BIT, *shaderModule, "main", DE_NULL }, *pipelineLayout, // VkPipelineLayout layout DE_NULL, // VkPipeline basePipelineHandle 0, // deInt32 basePipelineIndex }; Move pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineCreateInfo); const VkDeviceSize pointerBufferSize = tlasCount * sizeof(VkDeviceAddress); const VkBufferCreateInfo pointerBufferCreateInfo = makeBufferCreateInfo(pointerBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); de::MovePtr pointerBuffer = de::MovePtr(new BufferWithMemory(vkd, device, allocator, pointerBufferCreateInfo, MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress)); const VkDeviceSize indicesBufferSize = activeTlasCount * sizeof(deUint32); const VkBufferCreateInfo indicesBufferCreateInfo = makeBufferCreateInfo(indicesBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); de::MovePtr indicesBuffer = de::MovePtr(new BufferWithMemory(vkd, device, allocator, indicesBufferCreateInfo, MemoryRequirement::HostVisible)); const VkDeviceSize resultBufferSize = activeTlasCount * sizeof(deUint32) * 4; const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT); de::MovePtr resultBuffer = de::MovePtr(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible)); const Move cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex); const Move cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); de::SharedPtr blas = de::SharedPtr(makeBottomLevelAccelerationStructure().release()); std::vector> tlasVect(tlasCount); std::vector tlasPtrVect(tlasCount); std::vector tlasVkVect; // randomly scatter AS indices across the range (number of them should be equal to the max subgroup size) deRandom rnd; deRandom_init(&rnd, 123); std::set asIndicesSet; while (asIndicesSet.size() < activeTlasCount) asIndicesSet.insert(deRandom_getUint32(&rnd) % tlasCount); // fill indices buffer deUint32 helperIndex = 0; auto& indicesBufferAlloc = indicesBuffer->getAllocation(); deUint32* indicesBufferPtr = reinterpret_cast(indicesBufferAlloc.getHostPtr()); std::for_each(asIndicesSet.begin(), asIndicesSet.end(), [&helperIndex, indicesBufferPtr](const deUint32& index) { indicesBufferPtr[helperIndex++] = index; }); vk::flushAlloc(vkd, device, indicesBufferAlloc); // clear result buffer auto& resultBufferAlloc = resultBuffer->getAllocation(); void* resultBufferPtr = resultBufferAlloc.getHostPtr(); deMemset(resultBufferPtr, 0, static_cast(resultBufferSize)); vk::flushAlloc(vkd, device, resultBufferAlloc); beginCommandBuffer(vkd, *cmdBuffer, 0u); { // build bottom level acceleration structure blas->setGeometryData( { { 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, }, true, 0u ); blas->createAndBuild(vkd, device, *cmdBuffer, allocator); // build top level acceleration structures for (deUint32 tlasIndex = 0; tlasIndex < tlasCount; ++tlasIndex) { auto& tlas = tlasVect[tlasIndex]; tlas = makeTopLevelAccelerationStructure(); tlas->setInstanceCount(1); tlas->addInstance(blas); if (!asIndicesSet.count(tlasIndex)) { // tlas that are not in asIndicesSet should be empty but it is hard to do // that with current cts utils so we are marking them as inactive instead tlas->setInactiveInstances(true); } tlas->createAndBuild(vkd, device, *cmdBuffer, allocator); // get acceleration structure device address const VkAccelerationStructureDeviceAddressInfoKHR addressInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, // VkStructureType sType DE_NULL, // const void* pNext *tlas->getPtr() // VkAccelerationStructureKHR accelerationStructure }; VkDeviceAddress vkda = vkd.getAccelerationStructureDeviceAddressKHR(device, &addressInfo); tlasPtrVect[tlasIndex] = vkda; } // fill pointer buffer vkd.cmdUpdateBuffer(*cmdBuffer, **pointerBuffer, 0, pointerBufferSize, tlasPtrVect.data()); // wait for data transfers const VkMemoryBarrier uploadBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, &uploadBarrier, 1u); // wait for as build const VkMemoryBarrier asBuildBarrier = makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, &asBuildBarrier, 1u); tlasVkVect.reserve(tlasCount); for (auto& tlas : tlasVect) tlasVkVect.push_back(*tlas->getPtr()); VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; tlasCount, // deUint32 accelerationStructureCount; tlasVkVect.data(), // const VkAccelerationStructureKHR* pAccelerationStructures; }; const vk::VkDescriptorBufferInfo pointerBufferInfo = makeDescriptorBufferInfo(**pointerBuffer, 0u, VK_WHOLE_SIZE); const vk::VkDescriptorBufferInfo indicesBufferInfo = makeDescriptorBufferInfo(**indicesBuffer, 0u, VK_WHOLE_SIZE); const vk::VkDescriptorBufferInfo resultInfo = makeDescriptorBufferInfo(**resultBuffer, 0u, VK_WHOLE_SIZE); DescriptorSetUpdateBuilder() .writeArray (*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, tlasCount, &accelerationStructureWriteDescriptorSet) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &pointerBufferInfo) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &indicesBufferInfo) .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(3u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo) .update(vkd, device); vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL); vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); vkd.cmdDispatch(*cmdBuffer, activeTlasCount, 1, 1); const VkMemoryBarrier postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier); } endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer.get()); invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), resultBufferSize); // verify result buffer deUint32 failures = 0; const deUint32* resultPtr = reinterpret_cast(resultBuffer->getAllocation().getHostPtr()); for (deUint32 index = 0; index < activeTlasCount; ++index) { failures += (resultPtr[0 * activeTlasCount + index] != 2) + (resultPtr[1 * activeTlasCount + index] != 3) + (resultPtr[2 * activeTlasCount + index] != 5) + (resultPtr[3 * activeTlasCount + index] != 7); } if (failures) return tcu::TestStatus::fail(de::toString(failures) + " failures, " + de::toString(4 * activeTlasCount - failures) + " are ok"); return tcu::TestStatus::pass("Pass"); } } // anonymous /********************/ void addBasicBuildingTests(tcu::TestCaseGroup* group) { struct ShaderSourceTypeData { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; const char* name; } shaderSourceTypes[] = { { SST_FRAGMENT_SHADER, SSP_GRAPHICS_PIPELINE, "fragment_shader", }, { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, "compute_shader", }, { SST_CLOSEST_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "chit_shader", }, }; struct { vk::VkAccelerationStructureBuildTypeKHR buildType; const char* name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; struct { BottomTestType testType; bool usesAOP; const char* name; } bottomTestTypes[] = { { BTT_TRIANGLES, false, "triangles" }, { BTT_TRIANGLES, true, "triangles_aop" }, { BTT_AABBS, false, "aabbs" }, { BTT_AABBS, true, "aabbs_aop" }, }; struct { TopTestType testType; bool usesAOP; const char* name; } topTestTypes[] = { { TTT_IDENTICAL_INSTANCES, false, "identical_instances" }, { TTT_IDENTICAL_INSTANCES, true, "identical_instances_aop" }, { TTT_DIFFERENT_INSTANCES, false, "different_instances" }, { TTT_DIFFERENT_INSTANCES, true, "different_instances_aop" }, }; struct BuildFlagsData { VkBuildAccelerationStructureFlagsKHR flags; const char* name; }; BuildFlagsData optimizationTypes[] = { { VkBuildAccelerationStructureFlagsKHR(0u), "0" }, { VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, "fasttrace" }, { VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, "fastbuild" }, }; BuildFlagsData updateTypes[] = { { VkBuildAccelerationStructureFlagsKHR(0u), "0" }, { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, "update" }, }; BuildFlagsData compactionTypes[] = { { VkBuildAccelerationStructureFlagsKHR(0u), "0" }, { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, "compaction" }, }; BuildFlagsData lowMemoryTypes[] = { { VkBuildAccelerationStructureFlagsKHR(0u), "0" }, { VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, "lowmemory" }, }; struct { bool padVertices; const char* name; } paddingType[] = { { false, "nopadding" }, { true, "padded" }, }; struct { bool topGeneric; bool bottomGeneric; const char* suffix; } createGenericParams[] = { { false, false, "" }, { false, true, "_bottomgeneric" }, { true, false, "_topgeneric" }, { true, true, "_bothgeneric" }, }; for (size_t shaderSourceNdx = 0; shaderSourceNdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceNdx) { de::MovePtr sourceTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, "")); for (size_t buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx) { de::MovePtr buildGroup(new tcu::TestCaseGroup(group->getTestContext(), buildTypes[buildTypeNdx].name, "")); for (size_t bottomNdx = 0; bottomNdx < DE_LENGTH_OF_ARRAY(bottomTestTypes); ++bottomNdx) { de::MovePtr bottomGroup(new tcu::TestCaseGroup(group->getTestContext(), bottomTestTypes[bottomNdx].name, "")); for (size_t topNdx = 0; topNdx < DE_LENGTH_OF_ARRAY(topTestTypes); ++topNdx) { de::MovePtr topGroup(new tcu::TestCaseGroup(group->getTestContext(), topTestTypes[topNdx].name, "")); for (int paddingTypeIdx = 0; paddingTypeIdx < DE_LENGTH_OF_ARRAY(paddingType); ++paddingTypeIdx) { de::MovePtr paddingTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), paddingType[paddingTypeIdx].name, "")); for (size_t optimizationNdx = 0; optimizationNdx < DE_LENGTH_OF_ARRAY(optimizationTypes); ++optimizationNdx) { for (size_t updateNdx = 0; updateNdx < DE_LENGTH_OF_ARRAY(updateTypes); ++updateNdx) { for (size_t compactionNdx = 0; compactionNdx < DE_LENGTH_OF_ARRAY(compactionTypes); ++compactionNdx) { for (size_t lowMemoryNdx = 0; lowMemoryNdx < DE_LENGTH_OF_ARRAY(lowMemoryTypes); ++lowMemoryNdx) { for (int createGenericIdx = 0; createGenericIdx < DE_LENGTH_OF_ARRAY(createGenericParams); ++createGenericIdx) { std::string testName = std::string(optimizationTypes[optimizationNdx].name) + "_" + std::string(updateTypes[updateNdx].name) + "_" + std::string(compactionTypes[compactionNdx].name) + "_" + std::string(lowMemoryTypes[lowMemoryNdx].name) + std::string(createGenericParams[createGenericIdx].suffix); TestParams testParams { shaderSourceTypes[shaderSourceNdx].shaderSourceType, shaderSourceTypes[shaderSourceNdx].shaderSourcePipeline, buildTypes[buildTypeNdx].buildType, VK_FORMAT_R32G32B32_SFLOAT, paddingType[paddingTypeIdx].padVertices, VK_INDEX_TYPE_NONE_KHR, bottomTestTypes[bottomNdx].testType, InstanceCullFlags::NONE, bottomTestTypes[bottomNdx].usesAOP, createGenericParams[createGenericIdx].bottomGeneric, topTestTypes[topNdx].testType, topTestTypes[topNdx].usesAOP, createGenericParams[createGenericIdx].topGeneric, optimizationTypes[optimizationNdx].flags | updateTypes[updateNdx].flags | compactionTypes[compactionNdx].flags | lowMemoryTypes[lowMemoryNdx].flags, OT_NONE, OP_NONE, TEST_WIDTH, TEST_HEIGHT, 0u, EmptyAccelerationStructureCase::NOT_EMPTY, }; paddingTypeGroup->addChild(new RayQueryASBasicTestCase(group->getTestContext(), testName.c_str(), "", testParams)); } } } } } topGroup->addChild(paddingTypeGroup.release()); } bottomGroup->addChild(topGroup.release()); } buildGroup->addChild(bottomGroup.release()); } sourceTypeGroup->addChild(buildGroup.release()); } group->addChild(sourceTypeGroup.release()); } } void addVertexIndexFormatsTests(tcu::TestCaseGroup* group) { struct ShaderSourceTypeData { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; const char* name; } shaderSourceTypes[] = { { SST_VERTEX_SHADER, SSP_GRAPHICS_PIPELINE, "vertex_shader" }, { SST_TESSELATION_CONTROL_SHADER, SSP_GRAPHICS_PIPELINE, "tess_control_shader" }, { SST_TESSELATION_EVALUATION_SHADER, SSP_GRAPHICS_PIPELINE, "tess_evaluation_shader" }, { SST_GEOMETRY_SHADER, SSP_GRAPHICS_PIPELINE, "geometry_shader", }, { SST_FRAGMENT_SHADER, SSP_GRAPHICS_PIPELINE, "fragment_shader", }, { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, "compute_shader", }, { SST_RAY_GENERATION_SHADER, SSP_RAY_TRACING_PIPELINE, "rgen_shader", }, { SST_INTERSECTION_SHADER, SSP_RAY_TRACING_PIPELINE, "isect_shader", }, { SST_ANY_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "ahit_shader", }, { SST_CLOSEST_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "chit_shader", }, { SST_MISS_SHADER, SSP_RAY_TRACING_PIPELINE, "miss_shader", }, { SST_CALLABLE_SHADER, SSP_RAY_TRACING_PIPELINE, "call_shader", }, }; struct { vk::VkAccelerationStructureBuildTypeKHR buildType; const char* name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; const VkFormat vertexFormats[] = { // Mandatory formats. VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16B16A16_SNORM, // Additional formats. VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8B8_SNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R16G16B16_SNORM, VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R64G64_SFLOAT, VK_FORMAT_R64G64B64_SFLOAT, VK_FORMAT_R64G64B64A64_SFLOAT, }; struct { VkIndexType indexType; const char* name; } indexFormats[] = { { VK_INDEX_TYPE_NONE_KHR , "index_none" }, { VK_INDEX_TYPE_UINT16 , "index_uint16" }, { VK_INDEX_TYPE_UINT32 , "index_uint32" }, }; struct { bool padVertices; const char* name; } paddingType[] = { { false, "nopadding" }, { true, "padded" }, }; for (size_t shaderSourceNdx = 0; shaderSourceNdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceNdx) { de::MovePtr sourceTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, "")); for (size_t buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx) { de::MovePtr buildGroup(new tcu::TestCaseGroup(group->getTestContext(), buildTypes[buildTypeNdx].name, "")); for (size_t vertexFormatNdx = 0; vertexFormatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); ++vertexFormatNdx) { const auto format = vertexFormats[vertexFormatNdx]; const auto formatName = getFormatSimpleName(format); de::MovePtr vertexFormatGroup(new tcu::TestCaseGroup(group->getTestContext(), formatName.c_str(), "")); for (int paddingIdx = 0; paddingIdx < DE_LENGTH_OF_ARRAY(paddingType); ++paddingIdx) { de::MovePtr paddingGroup(new tcu::TestCaseGroup(group->getTestContext(), paddingType[paddingIdx].name, "")); for (size_t indexFormatNdx = 0; indexFormatNdx < DE_LENGTH_OF_ARRAY(indexFormats); ++indexFormatNdx) { TestParams testParams { shaderSourceTypes[shaderSourceNdx].shaderSourceType, shaderSourceTypes[shaderSourceNdx].shaderSourcePipeline, buildTypes[buildTypeNdx].buildType, format, paddingType[paddingIdx].padVertices, indexFormats[indexFormatNdx].indexType, BTT_TRIANGLES, InstanceCullFlags::NONE, false, false, TTT_IDENTICAL_INSTANCES, false, false, VkBuildAccelerationStructureFlagsKHR(0u), OT_NONE, OP_NONE, TEST_WIDTH, TEST_HEIGHT, 0u, EmptyAccelerationStructureCase::NOT_EMPTY, }; paddingGroup->addChild(new RayQueryASBasicTestCase(group->getTestContext(), indexFormats[indexFormatNdx].name, "", testParams)); } vertexFormatGroup->addChild(paddingGroup.release()); } buildGroup->addChild(vertexFormatGroup.release()); } sourceTypeGroup->addChild(buildGroup.release()); } group->addChild(sourceTypeGroup.release()); } } void addOperationTestsImpl (tcu::TestCaseGroup* group, const deUint32 workerThreads) { struct ShaderSourceTypeData { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; const char* name; } shaderSourceTypes[] = { { SST_VERTEX_SHADER, SSP_GRAPHICS_PIPELINE, "vertex_shader" }, { SST_TESSELATION_CONTROL_SHADER, SSP_GRAPHICS_PIPELINE, "tess_control_shader" }, { SST_TESSELATION_EVALUATION_SHADER, SSP_GRAPHICS_PIPELINE, "tess_evaluation_shader" }, { SST_GEOMETRY_SHADER, SSP_GRAPHICS_PIPELINE, "geometry_shader", }, { SST_FRAGMENT_SHADER, SSP_GRAPHICS_PIPELINE, "fragment_shader", }, { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, "compute_shader", }, { SST_RAY_GENERATION_SHADER, SSP_RAY_TRACING_PIPELINE, "rgen_shader", }, { SST_INTERSECTION_SHADER, SSP_RAY_TRACING_PIPELINE, "isect_shader", }, { SST_ANY_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "ahit_shader", }, { SST_CLOSEST_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "chit_shader", }, { SST_MISS_SHADER, SSP_RAY_TRACING_PIPELINE, "miss_shader", }, { SST_CALLABLE_SHADER, SSP_RAY_TRACING_PIPELINE, "call_shader", }, }; struct { OperationType operationType; const char* name; } operationTypes[] = { { OP_COPY, "copy" }, { OP_COMPACT, "compaction" }, { OP_SERIALIZE, "serialization" }, }; struct { vk::VkAccelerationStructureBuildTypeKHR buildType; const char* name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; struct { OperationTarget operationTarget; const char* name; } operationTargets[] = { { OT_TOP_ACCELERATION, "top_acceleration_structure" }, { OT_BOTTOM_ACCELERATION, "bottom_acceleration_structure" }, }; struct { BottomTestType testType; const char* name; } bottomTestTypes[] = { { BTT_TRIANGLES, "triangles" }, { BTT_AABBS, "aabbs" }, }; for (size_t shaderSourceNdx = 0; shaderSourceNdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceNdx) { de::MovePtr sourceTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, "")); for (size_t operationTypeNdx = 0; operationTypeNdx < DE_LENGTH_OF_ARRAY(operationTypes); ++operationTypeNdx) { if (workerThreads > 0) if (operationTypes[operationTypeNdx].operationType != OP_COPY && operationTypes[operationTypeNdx].operationType != OP_SERIALIZE) continue; de::MovePtr operationTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), operationTypes[operationTypeNdx].name, "")); for (size_t buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx) { if (workerThreads > 0 && buildTypes[buildTypeNdx].buildType != VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR) continue; de::MovePtr buildGroup(new tcu::TestCaseGroup(group->getTestContext(), buildTypes[buildTypeNdx].name, "")); for (size_t operationTargetNdx = 0; operationTargetNdx < DE_LENGTH_OF_ARRAY(operationTargets); ++operationTargetNdx) { de::MovePtr operationTargetGroup(new tcu::TestCaseGroup(group->getTestContext(), operationTargets[operationTargetNdx].name, "")); for (size_t testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(bottomTestTypes); ++testTypeNdx) { TopTestType topTest = (operationTargets[operationTargetNdx].operationTarget == OT_TOP_ACCELERATION) ? TTT_DIFFERENT_INSTANCES : TTT_IDENTICAL_INSTANCES; TestParams testParams { shaderSourceTypes[shaderSourceNdx].shaderSourceType, shaderSourceTypes[shaderSourceNdx].shaderSourcePipeline, buildTypes[buildTypeNdx].buildType, VK_FORMAT_R32G32B32_SFLOAT, false, VK_INDEX_TYPE_NONE_KHR, bottomTestTypes[testTypeNdx].testType, InstanceCullFlags::NONE, false, false, topTest, false, false, VkBuildAccelerationStructureFlagsKHR(0u), operationTargets[operationTargetNdx].operationTarget, operationTypes[operationTypeNdx].operationType, TEST_WIDTH, TEST_HEIGHT, workerThreads, EmptyAccelerationStructureCase::NOT_EMPTY, }; operationTargetGroup->addChild(new RayQueryASBasicTestCase(group->getTestContext(), bottomTestTypes[testTypeNdx].name, "", testParams)); } buildGroup->addChild(operationTargetGroup.release()); } operationTypeGroup->addChild(buildGroup.release()); } sourceTypeGroup->addChild(operationTypeGroup.release()); } group->addChild(sourceTypeGroup.release()); } } void addOperationTests (tcu::TestCaseGroup* group) { addOperationTestsImpl(group, 0); } void addHostThreadingOperationTests (tcu::TestCaseGroup* group) { const deUint32 threads[] = { 1, 2, 3, 4, 8, std::numeric_limits::max() }; for (size_t threadsNdx = 0; threadsNdx < DE_LENGTH_OF_ARRAY(threads); ++threadsNdx) { const std::string groupName = threads[threadsNdx] != std::numeric_limits::max() ? de::toString(threads[threadsNdx]) : "max"; de::MovePtr threadGroup(new tcu::TestCaseGroup(group->getTestContext(), groupName.c_str(), "")); addOperationTestsImpl(threadGroup.get(), threads[threadsNdx]); group->addChild(threadGroup.release()); } } void addFuncArgTests (tcu::TestCaseGroup* group) { const struct { vk::VkAccelerationStructureBuildTypeKHR buildType; const char* name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; auto& ctx = group->getTestContext(); for (int buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx) { TestParams testParams { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, buildTypes[buildTypeNdx].buildType, VK_FORMAT_R32G32B32_SFLOAT, false, VK_INDEX_TYPE_NONE_KHR, BTT_TRIANGLES, InstanceCullFlags::NONE, false, false, TTT_IDENTICAL_INSTANCES, false, false, VkBuildAccelerationStructureFlagsKHR(0u), OT_NONE, OP_NONE, TEST_WIDTH, TEST_HEIGHT, 0u, EmptyAccelerationStructureCase::NOT_EMPTY, }; group->addChild(new RayQueryASFuncArgTestCase(ctx, buildTypes[buildTypeNdx].name, "", testParams)); } } void addInstanceTriangleCullingTests (tcu::TestCaseGroup* group) { const struct { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; std::string name; } shaderSourceTypes[] = { { SST_VERTEX_SHADER, SSP_GRAPHICS_PIPELINE, "vertex_shader" }, { SST_TESSELATION_CONTROL_SHADER, SSP_GRAPHICS_PIPELINE, "tess_control_shader" }, { SST_TESSELATION_EVALUATION_SHADER, SSP_GRAPHICS_PIPELINE, "tess_evaluation_shader" }, { SST_GEOMETRY_SHADER, SSP_GRAPHICS_PIPELINE, "geometry_shader", }, { SST_FRAGMENT_SHADER, SSP_GRAPHICS_PIPELINE, "fragment_shader", }, { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, "compute_shader", }, { SST_RAY_GENERATION_SHADER, SSP_RAY_TRACING_PIPELINE, "rgen_shader", }, { SST_INTERSECTION_SHADER, SSP_RAY_TRACING_PIPELINE, "isect_shader", }, { SST_ANY_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "ahit_shader", }, { SST_CLOSEST_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "chit_shader", }, { SST_MISS_SHADER, SSP_RAY_TRACING_PIPELINE, "miss_shader", }, { SST_CALLABLE_SHADER, SSP_RAY_TRACING_PIPELINE, "call_shader", }, }; const struct { InstanceCullFlags cullFlags; std::string name; } cullFlags[] = { { InstanceCullFlags::NONE, "noflags" }, { InstanceCullFlags::COUNTERCLOCKWISE, "ccw" }, { InstanceCullFlags::CULL_DISABLE, "nocull" }, { InstanceCullFlags::ALL, "ccw_nocull" }, }; const struct { TopTestType topType; std::string name; } topType[] = { { TTT_DIFFERENT_INSTANCES, "transformed" }, // Each instance has its own transformation matrix. { TTT_IDENTICAL_INSTANCES, "notransform" }, // "Identical" instances, different geometries. }; const struct { vk::VkAccelerationStructureBuildTypeKHR buildType; std::string name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; const struct { VkIndexType indexType; std::string name; } indexFormats[] = { { VK_INDEX_TYPE_NONE_KHR , "index_none" }, { VK_INDEX_TYPE_UINT16 , "index_uint16" }, { VK_INDEX_TYPE_UINT32 , "index_uint32" }, }; auto& ctx = group->getTestContext(); for (int shaderSourceIdx = 0; shaderSourceIdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceIdx) { de::MovePtr shaderSourceGroup(new tcu::TestCaseGroup(ctx, shaderSourceTypes[shaderSourceIdx].name.c_str(), "")); for (int buildTypeIdx = 0; buildTypeIdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeIdx) { de::MovePtr buildTypeGroup(new tcu::TestCaseGroup(ctx, buildTypes[buildTypeIdx].name.c_str(), "")); for (int indexFormatIdx = 0; indexFormatIdx < DE_LENGTH_OF_ARRAY(indexFormats); ++indexFormatIdx) { de::MovePtr indexTypeGroup(new tcu::TestCaseGroup(ctx, indexFormats[indexFormatIdx].name.c_str(), "")); for (int topTypeIdx = 0; topTypeIdx < DE_LENGTH_OF_ARRAY(topType); ++topTypeIdx) { for (int cullFlagsIdx = 0; cullFlagsIdx < DE_LENGTH_OF_ARRAY(cullFlags); ++cullFlagsIdx) { const std::string testName = topType[topTypeIdx].name + "_" + cullFlags[cullFlagsIdx].name; TestParams testParams { shaderSourceTypes[shaderSourceIdx].shaderSourceType, shaderSourceTypes[shaderSourceIdx].shaderSourcePipeline, buildTypes[buildTypeIdx].buildType, VK_FORMAT_R32G32B32_SFLOAT, false, indexFormats[indexFormatIdx].indexType, BTT_TRIANGLES, cullFlags[cullFlagsIdx].cullFlags, false, false, topType[topTypeIdx].topType, false, false, VkBuildAccelerationStructureFlagsKHR(0u), OT_NONE, OP_NONE, TEST_WIDTH, TEST_HEIGHT, 0u, EmptyAccelerationStructureCase::NOT_EMPTY, }; indexTypeGroup->addChild(new RayQueryASBasicTestCase(ctx, testName.c_str(), "", testParams)); } } buildTypeGroup->addChild(indexTypeGroup.release()); } shaderSourceGroup->addChild(buildTypeGroup.release()); } group->addChild(shaderSourceGroup.release()); } } void addDynamicIndexingTests(tcu::TestCaseGroup* group) { auto& ctx = group->getTestContext(); group->addChild(new RayQueryASDynamicIndexingTestCase(ctx, "dynamic_indexing")); } void addEmptyAccelerationStructureTests (tcu::TestCaseGroup* group) { const struct { ShaderSourceType shaderSourceType; ShaderSourcePipeline shaderSourcePipeline; std::string name; } shaderSourceTypes[] = { { SST_VERTEX_SHADER, SSP_GRAPHICS_PIPELINE, "vertex_shader" }, { SST_TESSELATION_CONTROL_SHADER, SSP_GRAPHICS_PIPELINE, "tess_control_shader" }, { SST_TESSELATION_EVALUATION_SHADER, SSP_GRAPHICS_PIPELINE, "tess_evaluation_shader" }, { SST_GEOMETRY_SHADER, SSP_GRAPHICS_PIPELINE, "geometry_shader", }, { SST_FRAGMENT_SHADER, SSP_GRAPHICS_PIPELINE, "fragment_shader", }, { SST_COMPUTE_SHADER, SSP_COMPUTE_PIPELINE, "compute_shader", }, { SST_RAY_GENERATION_SHADER, SSP_RAY_TRACING_PIPELINE, "rgen_shader", }, { SST_INTERSECTION_SHADER, SSP_RAY_TRACING_PIPELINE, "isect_shader", }, { SST_ANY_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "ahit_shader", }, { SST_CLOSEST_HIT_SHADER, SSP_RAY_TRACING_PIPELINE, "chit_shader", }, { SST_MISS_SHADER, SSP_RAY_TRACING_PIPELINE, "miss_shader", }, { SST_CALLABLE_SHADER, SSP_RAY_TRACING_PIPELINE, "call_shader", }, }; const struct { vk::VkAccelerationStructureBuildTypeKHR buildType; std::string name; } buildTypes[] = { { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" }, { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" }, }; const struct { VkIndexType indexType; std::string name; } indexFormats[] = { { VK_INDEX_TYPE_NONE_KHR , "index_none" }, { VK_INDEX_TYPE_UINT16 , "index_uint16" }, { VK_INDEX_TYPE_UINT32 , "index_uint32" }, }; const struct { EmptyAccelerationStructureCase emptyASCase; std::string name; } emptyCases[] = { { EmptyAccelerationStructureCase::INACTIVE_TRIANGLES, "inactive_triangles" }, { EmptyAccelerationStructureCase::INACTIVE_INSTANCES, "inactive_instances" }, { EmptyAccelerationStructureCase::NO_GEOMETRIES_BOTTOM, "no_geometries_bottom" }, { EmptyAccelerationStructureCase::NO_PRIMITIVES_TOP, "no_primitives_top" }, { EmptyAccelerationStructureCase::NO_PRIMITIVES_BOTTOM, "no_primitives_bottom" }, }; auto& ctx = group->getTestContext(); for (size_t shaderSourceNdx = 0; shaderSourceNdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceNdx) { de::MovePtr sourceTypeGroup(new tcu::TestCaseGroup(ctx, shaderSourceTypes[shaderSourceNdx].name.c_str(), "")); for (int buildTypeIdx = 0; buildTypeIdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeIdx) { de::MovePtr buildTypeGroup(new tcu::TestCaseGroup(ctx, buildTypes[buildTypeIdx].name.c_str(), "")); for (int indexFormatIdx = 0; indexFormatIdx < DE_LENGTH_OF_ARRAY(indexFormats); ++indexFormatIdx) { de::MovePtr indexTypeGroup(new tcu::TestCaseGroup(ctx, indexFormats[indexFormatIdx].name.c_str(), "")); for (int emptyCaseIdx = 0; emptyCaseIdx < DE_LENGTH_OF_ARRAY(emptyCases); ++emptyCaseIdx) { TestParams testParams { shaderSourceTypes[shaderSourceNdx].shaderSourceType, shaderSourceTypes[shaderSourceNdx].shaderSourcePipeline, buildTypes[buildTypeIdx].buildType, VK_FORMAT_R32G32B32_SFLOAT, false, indexFormats[indexFormatIdx].indexType, BTT_TRIANGLES, InstanceCullFlags::NONE, false, false, TTT_IDENTICAL_INSTANCES, false, false, VkBuildAccelerationStructureFlagsKHR(0u), OT_NONE, OP_NONE, TEST_WIDTH, TEST_HEIGHT, 0u, emptyCases[emptyCaseIdx].emptyASCase, }; indexTypeGroup->addChild(new RayQueryASBasicTestCase(ctx, emptyCases[emptyCaseIdx].name.c_str(), "", testParams)); } buildTypeGroup->addChild(indexTypeGroup.release()); } sourceTypeGroup->addChild(buildTypeGroup.release()); } group->addChild(sourceTypeGroup.release()); } } tcu::TestCaseGroup* createAccelerationStructuresTests(tcu::TestContext& testCtx) { de::MovePtr group(new tcu::TestCaseGroup(testCtx, "acceleration_structures", "Acceleration structure tests using rayQuery feature")); addTestGroup(group.get(), "flags", "Test building AS with different build types, build flags and geometries/instances using arrays or arrays of pointers", addBasicBuildingTests); addTestGroup(group.get(), "format", "Test building AS with different vertex and index formats", addVertexIndexFormatsTests); addTestGroup(group.get(), "operations", "Test copying, compaction and serialization of AS", addOperationTests); addTestGroup(group.get(), "host_threading", "Test host threading operations", addHostThreadingOperationTests); addTestGroup(group.get(), "function_argument", "Test using AS as function argument using both pointers and bare values", addFuncArgTests); addTestGroup(group.get(), "instance_triangle_culling", "Test building AS with counterclockwise triangles and/or disabling face culling", addInstanceTriangleCullingTests); addTestGroup(group.get(), "dynamic_indexing", "Exercise dynamic indexing of acceleration structures", addDynamicIndexingTests); addTestGroup(group.get(), "empty", "Test building empty acceleration structures using different methods", addEmptyAccelerationStructureTests); return group.release(); } } // RayQuery } // vkt