blob: 96f9d624d21768273a40c96bbad9a6fe92f0c8ec [file] [log] [blame]
/*------------------------------------------------------------------------
* 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 <array>
#include <set>
#include <limits>
#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<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures (Context& context,
TestParams& testParams) = 0;
virtual de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure (Context& context,
TestParams& testParams,
std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& 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<RayTracingProperties> rayTracingPropertiesKHR;
rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
return rayTracingPropertiesKHR->getShaderGroupHandleSize();
}
deUint32 getShaderGroupBaseAlignment (const InstanceInterface& vki,
const VkPhysicalDevice physicalDevice)
{
de::MovePtr<RayTracingProperties> 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<VkQueryPool> 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<de::SharedPtr<Move<VkShaderModule>>>& shaderModules,
std::vector<VkPipelineShaderStageCreateInfo>& 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<VkShaderModule> 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<VkDescriptorSetLayout> descriptorSetLayout;
Move<VkDescriptorPool> descriptorPool;
Move<VkDescriptorSet> descriptorSet;
Move<VkPipelineLayout> pipelineLayout;
Move<VkRenderPass> renderPass;
Move<VkFramebuffer> framebuffer;
std::vector<de::SharedPtr<Move<VkShaderModule> > > shaderModules;
Move<VkPipeline> pipeline;
std::vector<tcu::Vec3> vertices;
Move<VkBuffer> vertexBuffer;
de::MovePtr<Allocation> 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<std::string> rayQueryTestName;
rayQueryTestName.push_back("as_triangle");
rayQueryTestName.push_back("as_aabb");
const std::map<ShaderSourceType,std::vector<std::string>> 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<VkPipelineShaderStageCreateInfo> 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<deUint32>(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<deUint32> reference(testParams.width * testParams.height * 2);
tcu::PixelBufferAccess referenceAccess(imageFormat, testParams.width, testParams.height, 2, reference.data());
std::vector<std::vector<deUint32>> 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<VkDescriptorSetLayout> descriptorSetLayout;
Move<VkDescriptorPool> descriptorPool;
Move<VkDescriptorSet> descriptorSet;
Move<VkPipelineLayout> pipelineLayout;
Move<VkShaderModule> shaderModule;
Move<VkPipeline> 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<std::string> 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<deUint32> 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<VkDescriptorSetLayout> descriptorSetLayout;
Move<VkDescriptorPool> descriptorPool;
Move<VkDescriptorSet> descriptorSet;
Move<VkPipelineLayout> pipelineLayout;
de::MovePtr<RayTracingPipeline> rayTracingPipeline;
Move<VkPipeline> rtPipeline;
de::MovePtr<BufferWithMemory> raygenShaderBindingTable;
de::MovePtr<BufferWithMemory> hitShaderBindingTable;
de::MovePtr<BufferWithMemory> missShaderBindingTable;
de::MovePtr<BufferWithMemory> callableShaderBindingTable;
std::vector<de::SharedPtr<BottomLevelAccelerationStructure> > bottomLevelAccelerationStructures;
de::MovePtr<TopLevelAccelerationStructure> 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<RayTracingPipeline>();
const std::map<ShaderSourceType,std::vector<std::string>> 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<std::string> 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> bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
bottomLevelAccelerationStructure->setGeometryCount(1);
de::SharedPtr<RaytracedGeometryBase> 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>(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<deUint32> 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<TestConfiguration> createTestConfiguration(const ShaderSourcePipeline& shaderSourcePipeline)
{
switch (shaderSourcePipeline)
{
case SSP_GRAPHICS_PIPELINE:
return de::SharedPtr<TestConfiguration>(new GraphicsConfiguration());
case SSP_COMPUTE_PIPELINE:
return de::SharedPtr<TestConfiguration>(new ComputeConfiguration());
case SSP_RAY_TRACING_PIPELINE:
return de::SharedPtr<TestConfiguration>(new RayTracingConfiguration());
default:
TCU_THROW(InternalError, "Wrong shader source pipeline");
}
return de::SharedPtr<TestConfiguration>();
}
class CheckerboardSceneBuilder : public SceneBuilder
{
public:
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> initBottomAccelerationStructures (Context& context,
TestParams& testParams) override;
de::MovePtr<TopLevelAccelerationStructure> initTopAccelerationStructure (Context& context,
TestParams& testParams,
std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures) override;
};
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> 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<de::SharedPtr<BottomLevelAccelerationStructure> > 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> bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
bottomLevelAccelerationStructure->setGeometryCount(1u);
de::SharedPtr<RaytracedGeometryBase> 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>(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> bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
bottomLevelAccelerationStructure->setGeometryCount(1u);
de::SharedPtr<RaytracedGeometryBase> 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>(bottomLevelAccelerationStructure.release()));
}
}
return result;
}
de::MovePtr<TopLevelAccelerationStructure> CheckerboardSceneBuilder::initTopAccelerationStructure (Context& context,
TestParams& testParams,
std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >& bottomLevelAccelerationStructures)
{
DE_UNREF(context);
const auto instanceCount = testParams.width * testParams.height / 2u;
const auto instanceFlags = getCullFlags(testParams.cullFlags);
de::MovePtr<TopLevelAccelerationStructure> 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<BufferWithMemory> 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<std::string> rayQueryTest;
std::vector<std::string> 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<BufferWithMemory> 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<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
const Move<VkImageView> 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<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
const VkDescriptorImageInfo resultImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructures;
de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructureCopies;
de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructureCopy;
std::vector<de::SharedPtr<SerialStorage>> bottomSerialized;
std::vector<de::SharedPtr<SerialStorage>> topSerialized;
std::vector<VkDeviceSize> accelerationCompactedSizes;
std::vector<VkDeviceSize> accelerationSerialSizes;
Move<VkQueryPool> m_queryPoolCompact;
Move<VkQueryPool> 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<VkAccelerationStructureKHR> accelerationStructureHandles;
std::vector<VkDeviceSize> bottomBlasCompactSize;
std::vector<VkDeviceSize> 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<BottomLevelAccelerationStructure> 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<BottomLevelAccelerationStructure>(asCopy.release()));
}
break;
}
case OP_COMPACT:
{
for (size_t i = 0; i < bottomLevelAccelerationStructures.size(); ++i)
{
de::MovePtr<BottomLevelAccelerationStructure> 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<BottomLevelAccelerationStructure>(asCopy.release()));
}
break;
}
case OP_SERIALIZE:
{
for (size_t i = 0; i < bottomLevelAccelerationStructures.size(); ++i)
{
de::SharedPtr<SerialStorage> 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<BottomLevelAccelerationStructure> 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<BottomLevelAccelerationStructure>(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<VkAccelerationStructureKHR> topLevelStructureHandles;
std::vector<VkDeviceSize> topBlasCompactSize;
std::vector<VkDeviceSize> 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<SerialStorage> 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> testConfiguration = createTestConfiguration(m_data.shaderSourcePipeline);
de::SharedPtr<SceneBuilder> sceneBuilder = de::SharedPtr<SceneBuilder>(new CheckerboardSceneBuilder());
const de::MovePtr<BufferWithMemory> buffer = runTest(testConfiguration.get(), sceneBuilder.get(), 0);
return testConfiguration->verifyImage(buffer.get(), m_context, m_data);
}
bool RayQueryASBasicTestInstance::iterateWithWorkers (void)
{
de::SharedPtr<SceneBuilder> sceneBuilder = de::SharedPtr<SceneBuilder>(new CheckerboardSceneBuilder());
de::SharedPtr<TestConfiguration> testConfigurationS = createTestConfiguration(m_data.shaderSourcePipeline);
const deUint64 singleThreadTimeStart = deGetMicroseconds();
de::MovePtr<BufferWithMemory> 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<TestConfiguration> testConfigurationM = createTestConfiguration(m_data.shaderSourcePipeline);
deUint64 multiThreadTimeStart = deGetMicroseconds();
de::MovePtr<BufferWithMemory> 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"
// <changed_section>
"%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"
// </changed_section>
// 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"
// <changed_section>
"%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"
// </changed_section>
"%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 <tlasCount> that will be active
const Move<VkDescriptorSetLayout> 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<VkDescriptorPool> 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<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
Move<VkShaderModule> 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<VkPipeline> 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<BufferWithMemory> pointerBuffer = de::MovePtr<BufferWithMemory>(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<BufferWithMemory> indicesBuffer = de::MovePtr<BufferWithMemory>(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<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, queueFamilyIndex);
const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
de::SharedPtr<BottomLevelAccelerationStructure> blas = de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
std::vector<de::MovePtr<TopLevelAccelerationStructure>> tlasVect(tlasCount);
std::vector<VkDeviceAddress> tlasPtrVect(tlasCount);
std::vector<VkAccelerationStructureKHR> 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<deUint32> 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<deUint32*>(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<size_t>(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<deUint32*>(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<tcu::TestCaseGroup> sourceTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, ""));
for (size_t buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx)
{
de::MovePtr<tcu::TestCaseGroup> buildGroup(new tcu::TestCaseGroup(group->getTestContext(), buildTypes[buildTypeNdx].name, ""));
for (size_t bottomNdx = 0; bottomNdx < DE_LENGTH_OF_ARRAY(bottomTestTypes); ++bottomNdx)
{
de::MovePtr<tcu::TestCaseGroup> bottomGroup(new tcu::TestCaseGroup(group->getTestContext(), bottomTestTypes[bottomNdx].name, ""));
for (size_t topNdx = 0; topNdx < DE_LENGTH_OF_ARRAY(topTestTypes); ++topNdx)
{
de::MovePtr<tcu::TestCaseGroup> topGroup(new tcu::TestCaseGroup(group->getTestContext(), topTestTypes[topNdx].name, ""));
for (int paddingTypeIdx = 0; paddingTypeIdx < DE_LENGTH_OF_ARRAY(paddingType); ++paddingTypeIdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> sourceTypeGroup(new tcu::TestCaseGroup(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, ""));
for (size_t buildTypeNdx = 0; buildTypeNdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeNdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> vertexFormatGroup(new tcu::TestCaseGroup(group->getTestContext(), formatName.c_str(), ""));
for (int paddingIdx = 0; paddingIdx < DE_LENGTH_OF_ARRAY(paddingType); ++paddingIdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> buildGroup(new tcu::TestCaseGroup(group->getTestContext(), buildTypes[buildTypeNdx].name, ""));
for (size_t operationTargetNdx = 0; operationTargetNdx < DE_LENGTH_OF_ARRAY(operationTargets); ++operationTargetNdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<deUint32>::max() };
for (size_t threadsNdx = 0; threadsNdx < DE_LENGTH_OF_ARRAY(threads); ++threadsNdx)
{
const std::string groupName = threads[threadsNdx] != std::numeric_limits<deUint32>::max()
? de::toString(threads[threadsNdx])
: "max";
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> shaderSourceGroup(new tcu::TestCaseGroup(ctx, shaderSourceTypes[shaderSourceIdx].name.c_str(), ""));
for (int buildTypeIdx = 0; buildTypeIdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeIdx)
{
de::MovePtr<tcu::TestCaseGroup> buildTypeGroup(new tcu::TestCaseGroup(ctx, buildTypes[buildTypeIdx].name.c_str(), ""));
for (int indexFormatIdx = 0; indexFormatIdx < DE_LENGTH_OF_ARRAY(indexFormats); ++indexFormatIdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> sourceTypeGroup(new tcu::TestCaseGroup(ctx, shaderSourceTypes[shaderSourceNdx].name.c_str(), ""));
for (int buildTypeIdx = 0; buildTypeIdx < DE_LENGTH_OF_ARRAY(buildTypes); ++buildTypeIdx)
{
de::MovePtr<tcu::TestCaseGroup> buildTypeGroup(new tcu::TestCaseGroup(ctx, buildTypes[buildTypeIdx].name.c_str(), ""));
for (int indexFormatIdx = 0; indexFormatIdx < DE_LENGTH_OF_ARRAY(indexFormats); ++indexFormatIdx)
{
de::MovePtr<tcu::TestCaseGroup> 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<tcu::TestCaseGroup> 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