blob: 21b1d7d474df2e3e91bfc1841729aa965005d7b1 [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 Ray Tracing Capture/Replay tests
*//*--------------------------------------------------------------------*/
#include "vktRayTracingCaptureReplayTests.hpp"
#include <set>
#include "vkDefs.hpp"
#include "vktTestCase.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkImageWithMemory.hpp"
#include "vkTypeUtil.hpp"
#include "vkRayTracingUtil.hpp"
#include "tcuCommandLine.hpp"
namespace vkt
{
namespace RayTracing
{
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;
static const uint32_t RTCR_DEFAULT_SIZE = 8u;
static const uint32_t RTCR_SHADER_COUNT = 4u;
enum SBTReplayTestType
{
TEST_ACCELERATION_STRUCTURES,
TEST_PIPELINE_SINGLE,
TEST_PIPELINE_AFTER,
TEST_PIPELINE_BEFORE
};
enum ASOperationTarget
{
OT_NONE,
OT_TOP_ACCELERATION,
OT_BOTTOM_ACCELERATION
};
enum ASOperationType
{
OP_NONE,
OP_COPY,
OP_COMPACT,
OP_SERIALIZE
};
enum ASBottomTestType
{
BTT_TRIANGLES,
BTT_AABBS
};
enum ASTopTestType
{
TTT_IDENTICAL_INSTANCES,
TTT_DIFFERENT_INSTANCES
};
struct TestParams;
struct PipelineOutput
{
Move<VkPipeline> pipeline;
de::MovePtr<BufferWithMemory> raygenShaderBindingTable;
de::MovePtr<BufferWithMemory> missShaderBindingTable;
de::MovePtr<BufferWithMemory> hitShaderBindingTable;
Move<VkDescriptorSet> descriptorSet;
de::MovePtr<BufferWithMemory> uniformBuffer;
VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion;
VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion;
VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion;
VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion;
};
struct PipelineData
{
PipelineData(Allocator &alloc) : allocator(alloc)
{
}
VkDescriptorSetLayout descriptorSetLayout;
VkDescriptorPool descriptorPool;
VkPipelineLayout pipelineLayout;
Allocator &allocator;
PipelineOutput pipelines[2];
};
class TestConfiguration
{
public:
virtual ~TestConfiguration()
{
}
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;
virtual void initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
bool replay) = 0;
virtual void initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment,
PipelineData &pipelineData, bool replay) = 0;
virtual bool verifyImage(const std::vector<uint32_t> &captureResults, const std::vector<uint32_t> &replayResults,
Context &context, TestParams &testParams) = 0;
virtual VkFormat getResultImageFormat() = 0;
virtual size_t getResultImageFormatSize() = 0;
virtual VkClearValue getClearValue() = 0;
};
struct TestParams
{
SBTReplayTestType testType; // SBT
ASOperationTarget operationTarget; // AS
ASOperationType operationType; // AS
vk::VkAccelerationStructureBuildTypeKHR buildType; // AS
ASBottomTestType bottomType; // AS
ASTopTestType topType; // AS
uint32_t width;
uint32_t height;
de::SharedPtr<TestConfiguration> testConfiguration;
};
uint32_t getShaderGroupSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
{
de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
return rayTracingPropertiesKHR->getShaderGroupHandleSize();
}
uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
{
de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
}
VkImageCreateInfo makeImageCreateInfo(uint32_t width, uint32_t height, uint32_t depth, VkFormat format)
{
const VkImageCreateInfo imageCreateInfo = {
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
(VkImageCreateFlags)0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_3D, // VkImageType imageType;
format, // VkFormat format;
makeExtent3D(width, height, depth), // VkExtent3D extent;
1u, // uint32_t mipLevels;
1u, // uint32_t 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, // uint32_t queueFamilyIndexCount;
nullptr, // const uint32_t* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
return imageCreateInfo;
}
Move<VkQueryPool> makeQueryPool(const DeviceInterface &vk, const VkDevice device, const VkQueryType queryType,
uint32_t queryCount)
{
const VkQueryPoolCreateInfo queryPoolCreateInfo = {
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // sType
nullptr, // pNext
(VkQueryPoolCreateFlags)0, // flags
queryType, // queryType
queryCount, // queryCount
0u, // pipelineStatistics
};
return createQueryPool(vk, device, &queryPoolCreateInfo);
}
VkDeviceAddress getAccelerationStructureDeviceAddress(const DeviceInterface &vk, const VkDevice device,
VkAccelerationStructureKHR accelerationStructure)
{
const VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {
VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, // VkStructureType sType;
nullptr, // const void* pNext;
accelerationStructure // VkAccelerationStructureKHR accelerationStructure
};
return vk.getAccelerationStructureDeviceAddressKHR(device, &addressInfo);
}
class TestShaderBindingTablesConfiguration : public TestConfiguration
{
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;
void initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
bool replay) override;
void initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment,
PipelineData &pipelineData, bool replay) override;
bool verifyImage(const std::vector<uint32_t> &captureResults, const std::vector<uint32_t> &replayResults,
Context &context, TestParams &testParams) override;
VkFormat getResultImageFormat() override;
size_t getResultImageFormatSize() override;
VkClearValue getClearValue() override;
protected:
VkDeviceAddress sbtSavedRaygenAddress = 0u;
VkDeviceAddress sbtSavedMissAddress = 0u;
VkDeviceAddress sbtSavedHitAddress = 0u;
};
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> TestShaderBindingTablesConfiguration::
initBottomAccelerationStructures(Context &context, TestParams &testParams)
{
DE_UNREF(context);
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> result;
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);
for (uint32_t y = 0; y < testParams.height; ++y)
for (uint32_t 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);
std::vector<tcu::Vec3> geometryData;
de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure =
makeBottomLevelAccelerationStructure();
bottomLevelAccelerationStructure->setGeometryCount(1u);
geometryData.push_back(xyz + v0);
geometryData.push_back(xyz + v1);
geometryData.push_back(xyz + v2);
geometryData.push_back(xyz + v2);
geometryData.push_back(xyz + v1);
geometryData.push_back(xyz + v3);
bottomLevelAccelerationStructure->addGeometry(geometryData, true);
result.push_back(
de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
}
return result;
}
de::MovePtr<TopLevelAccelerationStructure> TestShaderBindingTablesConfiguration::initTopAccelerationStructure(
Context &context, TestParams &testParams,
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)
{
DE_UNREF(context);
uint32_t instanceCount = testParams.width * testParams.height / 2;
de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
result->setInstanceCount(instanceCount);
uint32_t currentInstanceIndex = 0;
VkTransformMatrixKHR identityMatrix = {
{{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}};
for (uint32_t y = 0; y < testParams.height; ++y)
{
uint32_t shaderOffset = y % RTCR_SHADER_COUNT;
for (uint32_t x = 0; x < testParams.width; ++x)
{
if (((x + y) % 2) == 0)
continue;
result->addInstance(bottomLevelAccelerationStructures[currentInstanceIndex++], identityMatrix, 0, 0xFF,
shaderOffset);
}
}
return result;
}
void TestShaderBindingTablesConfiguration::initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
Context &context, const DeviceInterface &vkd,
const VkDevice device, TestParams &testParams,
bool replay)
{
DE_UNREF(testParams);
DE_UNREF(replay);
rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0), 0);
rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("miss"), 0), 1);
for (uint32_t shaderNdx = 0; shaderNdx < RTCR_SHADER_COUNT; ++shaderNdx)
{
std::stringstream shaderName;
shaderName << "chit" << shaderNdx;
rayTracingPipeline->addShader(
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName.str()), 0), 2 + shaderNdx);
}
}
void TestShaderBindingTablesConfiguration::initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
Context &context, const DeviceInterface &vkd,
const VkDevice device, TestParams &testParams,
uint32_t shaderGroupHandleSize,
uint32_t shaderGroupBaseAlignment,
PipelineData &pipelineData, bool replay)
{
DE_UNREF(context);
const VkBufferCreateInfo uniformBufferCreateInfo =
makeBufferCreateInfo(sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
if (!replay) // capture phase
{
pipelineData.pipelines[0].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[0].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT,
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, MemoryRequirement::DeviceAddress, 0u);
pipelineData.pipelines[0].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT,
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, MemoryRequirement::DeviceAddress, 0u);
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT,
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, MemoryRequirement::DeviceAddress, 0u);
pipelineData.pipelines[0].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[0].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[0].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[0].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
// capture SBT addresses
VkBufferDeviceAddressInfo deviceAddressInfo = {
VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, //VkStructureType sType;
nullptr, //const void* pNext;
VK_NULL_HANDLE //VkBuffer buffer;
};
deviceAddressInfo.buffer = pipelineData.pipelines[0].raygenShaderBindingTable->get();
sbtSavedRaygenAddress = vkd.getBufferOpaqueCaptureAddress(device, &deviceAddressInfo);
deviceAddressInfo.buffer = pipelineData.pipelines[0].missShaderBindingTable->get();
sbtSavedMissAddress = vkd.getBufferOpaqueCaptureAddress(device, &deviceAddressInfo);
deviceAddressInfo.buffer = pipelineData.pipelines[0].hitShaderBindingTable->get();
sbtSavedHitAddress = vkd.getBufferOpaqueCaptureAddress(device, &deviceAddressInfo);
}
else // replay phase
{
switch (testParams.testType)
{
case TEST_PIPELINE_SINGLE:
pipelineData.pipelines[0].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[0].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedRaygenAddress);
pipelineData.pipelines[0].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedMissAddress);
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, 0u, 0u, MemoryRequirement::Any, sbtSavedHitAddress);
pipelineData.pipelines[0].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[0].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[0].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[0].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
break;
case TEST_PIPELINE_AFTER:
pipelineData.pipelines[0].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[0].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedRaygenAddress);
pipelineData.pipelines[0].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedMissAddress);
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, 0u, 0u, MemoryRequirement::Any, sbtSavedHitAddress);
pipelineData.pipelines[0].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[0].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[0].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[0].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
pipelineData.pipelines[1].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[1].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[1].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[1].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[1].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[1].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[1].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[1].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[1].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[1].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
break;
case TEST_PIPELINE_BEFORE:
pipelineData.pipelines[0].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[0].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[0].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, 0u, 0u, MemoryRequirement::Any, 0u);
pipelineData.pipelines[0].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[0].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[0].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[0].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
pipelineData.pipelines[1].pipeline =
rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[1].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedRaygenAddress);
pipelineData.pipelines[1].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1, 0u, 0u, MemoryRequirement::Any, sbtSavedMissAddress);
pipelineData.pipelines[1].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[1].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, RTCR_SHADER_COUNT, 0u, 0u, MemoryRequirement::Any, sbtSavedHitAddress);
pipelineData.pipelines[1].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[1].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[1].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[1].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[1].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[1].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, RTCR_SHADER_COUNT * shaderGroupHandleSize);
pipelineData.pipelines[1].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
break;
default:
TCU_THROW(InternalError, "Wrong test type");
}
}
}
bool TestShaderBindingTablesConfiguration::verifyImage(const std::vector<uint32_t> &captureResults,
const std::vector<uint32_t> &replayResults, Context &context,
TestParams &testParams)
{
DE_UNREF(context);
uint32_t pipelineCount = (testParams.testType == TEST_PIPELINE_SINGLE) ? 1u : 2u;
uint32_t imageSize = testParams.height * testParams.width;
uint32_t failures = 0;
// verify results - each test case should generate checkerboard pattern
for (uint32_t pipelineNdx = 0; pipelineNdx < pipelineCount; ++pipelineNdx)
for (uint32_t pos = 0; pos < imageSize; ++pos)
{
if (captureResults[pos] != replayResults[pipelineNdx * imageSize + pos])
failures++;
}
return failures == 0;
}
VkFormat TestShaderBindingTablesConfiguration::getResultImageFormat()
{
return VK_FORMAT_R32_UINT;
}
size_t TestShaderBindingTablesConfiguration::getResultImageFormatSize()
{
return sizeof(uint32_t);
}
VkClearValue TestShaderBindingTablesConfiguration::getClearValue()
{
return makeClearValueColorU32(0xFF, 0u, 0u, 0u);
}
class TestAccelerationStructuresConfiguration : public TestConfiguration
{
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;
void initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
bool replay) override;
void initShaderBindingTables(de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context,
const DeviceInterface &vkd, const VkDevice device, TestParams &testParams,
uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment,
PipelineData &pipelineData, bool replay) override;
bool verifyImage(const std::vector<uint32_t> &captureResults, const std::vector<uint32_t> &replayResults,
Context &context, TestParams &testParams) override;
VkFormat getResultImageFormat() override;
size_t getResultImageFormatSize() override;
VkClearValue getClearValue() override;
protected:
VkDeviceAddress sbtSavedRaygenAddress = 0u;
VkDeviceAddress sbtSavedMissAddress = 0u;
VkDeviceAddress sbtSavedHitAddress = 0u;
};
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> TestAccelerationStructuresConfiguration::
initBottomAccelerationStructures(Context &context, TestParams &testParams)
{
DE_UNREF(context);
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> result;
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.topType == TTT_DIFFERENT_INSTANCES)
{
de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure =
makeBottomLevelAccelerationStructure();
bottomLevelAccelerationStructure->setGeometryCount(1u);
de::SharedPtr<RaytracedGeometryBase> geometry;
if (testParams.bottomType == BTT_TRIANGLES)
{
geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, VK_FORMAT_R32G32B32_SFLOAT,
VK_INDEX_TYPE_NONE_KHR);
geometry->addVertex(v0);
geometry->addVertex(v1);
geometry->addVertex(v2);
geometry->addVertex(v2);
geometry->addVertex(v1);
geometry->addVertex(v3);
}
else // m_data.bottomType == BTT_AABBS
{
geometry =
makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, VK_FORMAT_R32G32B32_SFLOAT, VK_INDEX_TYPE_NONE_KHR);
geometry->addVertex(tcu::Vec3(0.0f, 0.0f, -0.1f));
geometry->addVertex(tcu::Vec3(1.0f, 1.0f, 0.1f));
}
bottomLevelAccelerationStructure->addGeometry(geometry);
result.push_back(de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
}
else // m_data.topTestType == TTT_IDENTICAL_INSTANCES
{
// triangle and aabb tests use geometries/aabbs with different vertex positions and the same identity matrix in each instance data
for (uint32_t y = 0; y < testParams.height; ++y)
for (uint32_t 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.bottomType == BTT_TRIANGLES)
{
geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_TRIANGLES_KHR, VK_FORMAT_R32G32B32_SFLOAT,
VK_INDEX_TYPE_NONE_KHR);
geometry->addVertex(xyz + v0);
geometry->addVertex(xyz + v1);
geometry->addVertex(xyz + v2);
geometry->addVertex(xyz + v2);
geometry->addVertex(xyz + v1);
geometry->addVertex(xyz + v3);
}
else // testParams.bottomTestType == BTT_AABBS
{
geometry = makeRaytracedGeometry(VK_GEOMETRY_TYPE_AABBS_KHR, VK_FORMAT_R32G32B32_SFLOAT,
VK_INDEX_TYPE_NONE_KHR);
geometry->addVertex(xyz + tcu::Vec3(0.0f, 0.0f, -0.1f));
geometry->addVertex(xyz + tcu::Vec3(1.0f, 1.0f, 0.1f));
}
bottomLevelAccelerationStructure->addGeometry(geometry);
result.push_back(
de::SharedPtr<BottomLevelAccelerationStructure>(bottomLevelAccelerationStructure.release()));
}
}
return result;
}
de::MovePtr<TopLevelAccelerationStructure> TestAccelerationStructuresConfiguration::initTopAccelerationStructure(
Context &context, TestParams &testParams,
std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> &bottomLevelAccelerationStructures)
{
DE_UNREF(context);
uint32_t instanceCount = testParams.width * testParams.height / 2;
de::MovePtr<TopLevelAccelerationStructure> result = makeTopLevelAccelerationStructure();
result->setInstanceCount(instanceCount);
if (testParams.topType == TTT_DIFFERENT_INSTANCES)
{
for (uint32_t y = 0; y < testParams.height; ++y)
for (uint32_t 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);
}
}
else // testParams.topType == TTT_IDENTICAL_INSTANCES
{
uint32_t currentInstanceIndex = 0;
for (uint32_t y = 0; y < testParams.height; ++y)
for (uint32_t x = 0; x < testParams.width; ++x)
{
if (((x + y) % 2) == 0)
continue;
result->addInstance(bottomLevelAccelerationStructures[currentInstanceIndex++]);
}
}
return result;
}
void TestAccelerationStructuresConfiguration::initRayTracingShaders(de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
Context &context, const DeviceInterface &vkd,
const VkDevice device, TestParams &testParams,
bool replay)
{
DE_UNREF(testParams);
DE_UNREF(replay);
rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0), 0);
rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("chit1"), 0), 1);
rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("chit1"), 0), 2);
rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("isect"), 0), 2);
rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR,
createShaderModule(vkd, device, context.getBinaryCollection().get("miss"), 0), 3);
}
void TestAccelerationStructuresConfiguration::initShaderBindingTables(
de::MovePtr<RayTracingPipeline> &rayTracingPipeline, Context &context, const DeviceInterface &vkd,
const VkDevice device, TestParams &testParams, uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment,
PipelineData &pipelineData, bool replay)
{
DE_UNREF(context);
DE_UNREF(replay);
const VkBufferCreateInfo uniformBufferCreateInfo =
makeBufferCreateInfo(sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
pipelineData.pipelines[0].pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineData.pipelineLayout);
pipelineData.pipelines[0].raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 0, 1);
if (testParams.bottomType == BTT_AABBS)
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 2, 1);
else // testParams.bottomType == BTT_TRIANGLES
pipelineData.pipelines[0].hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 1, 1);
pipelineData.pipelines[0].missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(
vkd, device, *(pipelineData.pipelines[0].pipeline), pipelineData.allocator, shaderGroupHandleSize,
shaderGroupBaseAlignment, 3, 1);
pipelineData.pipelines[0].descriptorSet =
makeDescriptorSet(vkd, device, pipelineData.descriptorPool, pipelineData.descriptorSetLayout);
pipelineData.pipelines[0].uniformBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
vkd, device, pipelineData.allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible));
pipelineData.pipelines[0].raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].raygenShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].missShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(
getBufferDeviceAddress(vkd, device, pipelineData.pipelines[0].hitShaderBindingTable->get(), 0),
shaderGroupHandleSize, shaderGroupHandleSize);
pipelineData.pipelines[0].callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(0, 0, 0);
}
bool TestAccelerationStructuresConfiguration::verifyImage(const std::vector<uint32_t> &captureResults,
const std::vector<uint32_t> &replayResults, Context &context,
TestParams &testParams)
{
DE_UNREF(context);
uint32_t imageSize = testParams.height * testParams.width;
uint32_t failures = 0;
// verify results - each test case should generate checkerboard pattern
for (uint32_t pos = 0; pos < imageSize; ++pos)
{
if (captureResults[pos] != replayResults[pos])
failures++;
}
return failures == 0;
}
VkFormat TestAccelerationStructuresConfiguration::getResultImageFormat()
{
return VK_FORMAT_R32_UINT;
}
size_t TestAccelerationStructuresConfiguration::getResultImageFormatSize()
{
return sizeof(uint32_t);
}
VkClearValue TestAccelerationStructuresConfiguration::getClearValue()
{
return makeClearValueColorU32(0xFF, 0u, 0u, 0u);
}
class RayTracingCaptureReplayTestCase : public TestCase
{
public:
RayTracingCaptureReplayTestCase(tcu::TestContext &context, const char *name, const TestParams &data);
~RayTracingCaptureReplayTestCase(void);
virtual void checkSupport(Context &context) const;
virtual void initPrograms(SourceCollections &programCollection) const;
virtual TestInstance *createInstance(Context &context) const;
private:
TestParams m_data;
};
class RayTracingCaptureReplayTestInstance : public TestInstance
{
public:
RayTracingCaptureReplayTestInstance(Context &context, const TestParams &data);
~RayTracingCaptureReplayTestInstance(void);
tcu::TestStatus iterate(void);
protected:
std::vector<uint32_t> runTest(bool replay);
private:
TestParams m_data;
std::vector<VkDeviceAddress> buildBLASAddresses;
std::vector<VkDeviceAddress> copyBLASAddresses;
VkDeviceAddress buildTLASAddress;
VkDeviceAddress copyTLASAddress;
};
RayTracingCaptureReplayTestCase::RayTracingCaptureReplayTestCase(tcu::TestContext &context, const char *name,
const TestParams &data)
: vkt::TestCase(context, name)
, m_data(data)
{
}
RayTracingCaptureReplayTestCase::~RayTracingCaptureReplayTestCase(void)
{
}
void RayTracingCaptureReplayTestCase::checkSupport(Context &context) const
{
context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
context.getRayTracingPipelineFeatures();
if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
if (m_data.testType == TEST_PIPELINE_BEFORE &&
rayTracingPipelineFeaturesKHR.rayTracingPipelineShaderGroupHandleCaptureReplayMixed == false)
TCU_THROW(
NotSupportedError,
"Requires "
"VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipelineShaderGroupHandleCaptureReplayMixed");
if (m_data.testType != TEST_ACCELERATION_STRUCTURES &&
rayTracingPipelineFeaturesKHR.rayTracingPipelineShaderGroupHandleCaptureReplay == false)
TCU_THROW(
NotSupportedError,
"Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipelineShaderGroupHandleCaptureReplay");
const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
context.getAccelerationStructureFeatures();
if (accelerationStructureFeaturesKHR.accelerationStructure == false)
TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
"VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
if (m_data.testType == TEST_ACCELERATION_STRUCTURES &&
accelerationStructureFeaturesKHR.accelerationStructureCaptureReplay == false)
TCU_THROW(NotSupportedError,
"Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureCaptureReplay");
if (m_data.testType == TEST_ACCELERATION_STRUCTURES &&
m_data.buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR &&
accelerationStructureFeaturesKHR.accelerationStructureHostCommands == false)
TCU_THROW(NotSupportedError,
"Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureHostCommands");
const VkPhysicalDeviceBufferDeviceAddressFeatures &bufferDeviceAddressFeatures =
context.getBufferDeviceAddressFeatures();
if (bufferDeviceAddressFeatures.bufferDeviceAddressCaptureReplay == false)
TCU_THROW(NotSupportedError, "Requires bufferDeviceAddressFeatures.bufferDeviceAddressCaptureReplay");
}
void RayTracingCaptureReplayTestCase::initPrograms(SourceCollections &programCollection) const
{
const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
{
std::stringstream css;
css << "#version 460 core\n"
"#extension GL_EXT_ray_tracing : require\n"
"layout(location = 0) rayPayloadEXT uvec4 hitValue;\n"
"layout(set = 0, binding = 0) uniform UniformParams\n"
"{\n"
" uint targetLayer;\n"
"} uniformParams;\n"
"layout(r32ui, set = 0, binding = 1) uniform uimage3D result;\n"
"layout(set = 0, binding = 2) uniform accelerationStructureEXT topLevelAS;\n"
"\n"
"void main()\n"
"{\n"
" float tmin = 0.0;\n"
" float tmax = 1.0;\n"
" vec3 origin = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 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, uniformParams.targetLayer), hitValue);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(css.str())) << buildOptions;
}
for (uint32_t shaderNdx = 0; shaderNdx < RTCR_SHADER_COUNT; ++shaderNdx)
{
uint32_t colorValue = 2 * (shaderNdx + 1);
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 = uvec4("
<< colorValue
<< ",0,0,1);\n"
"}\n";
std::stringstream shaderName;
shaderName << "chit" << shaderNdx;
programCollection.glslSources.add(shaderName.str())
<< glu::ClosestHitSource(updateRayTracingGLSL(css.str())) << buildOptions;
}
{
std::stringstream css;
css << "#version 460 core\n"
"#extension GL_EXT_ray_tracing : require\n"
"hitAttributeEXT uvec4 hitAttribute;\n"
"void main()\n"
"{\n"
" hitAttribute = uvec4(0,0,0,0);\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"
"layout(location = 0) rayPayloadInEXT uvec4 hitValue;\n"
"void main()\n"
"{\n"
" hitValue = uvec4(1,0,0,1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(css.str())) << buildOptions;
}
}
TestInstance *RayTracingCaptureReplayTestCase::createInstance(Context &context) const
{
return new RayTracingCaptureReplayTestInstance(context, m_data);
}
RayTracingCaptureReplayTestInstance::RayTracingCaptureReplayTestInstance(Context &context, const TestParams &data)
: vkt::TestInstance(context)
, m_data(data)
{
}
RayTracingCaptureReplayTestInstance::~RayTracingCaptureReplayTestInstance(void)
{
}
std::vector<uint32_t> RayTracingCaptureReplayTestInstance::runTest(bool replay)
{
const auto &vki = m_context.getInstanceInterface();
const auto physicalDevice = m_context.getPhysicalDevice();
const auto &vkd = m_context.getDeviceInterface();
const auto device = m_context.getDevice();
auto allocator = &m_context.getDefaultAllocator();
const auto queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const auto queue = m_context.getUniversalQueue();
// Create common pipeline layout for all raytracing pipelines
const Move<VkDescriptorSetLayout> descriptorSetLayout =
DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, ALL_RAY_TRACING_STAGES)
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
.build(vkd, device);
uint32_t pipelineCount =
(!replay || (m_data.testType == TEST_PIPELINE_SINGLE) || (m_data.testType == TEST_ACCELERATION_STRUCTURES)) ?
1u :
2u;
const Move<VkDescriptorPool> descriptorPool =
DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pipelineCount)
.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, pipelineCount)
.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, pipelineCount)
.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, pipelineCount);
const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
// All pipelines will be using the same set of shaders and shader groups.
// Single RayTracingPipeline object will be enough to define it
de::MovePtr<RayTracingPipeline> rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
m_data.testConfiguration->initRayTracingShaders(rayTracingPipeline, m_context, vkd, device, m_data, replay);
// Capture phase ( replay==false ):
// - TEST_ACCELERATION_STRUCTURES:
// - build/copy/compact/serialize structure, record addresses
// - TEST_PIPELINE_SINGLE:
// - TEST_PIPELINE_AFTER:
// - TEST_PIPELINE_BEFORE:
// - single pipeline records addresses and fills test data
// Replay phase ( replay==true ):
// - TEST_ACCELERATION_STRUCTURES:
// - build/copy/compact/serialize structure with addresses captured previously
// - TEST_PIPELINE_SINGLE:
// - single pipeline with addresses captured previously - writes into first image layer
// - TEST_PIPELINE_AFTER:
// - first pipeline with addresses captured previously - writes into first image layer
// - second pipeline created without captured addresses - writes into second image layer
// - TEST_PIPELINE_BEFORE:
// - first pipeline created without captured addresses - writes into first image layer
// - second pipeline with addresses captured previously - writes into second image layer
//
// Comparing results in all tests: all layers must be identical to the layer from capture phase
PipelineData pipelineData(*allocator);
pipelineData.pipelineLayout = *pipelineLayout;
pipelineData.descriptorSetLayout = *descriptorSetLayout;
pipelineData.descriptorPool = *descriptorPool;
const uint32_t shaderGroupHandleSize = getShaderGroupSize(vki, physicalDevice);
const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
m_data.testConfiguration->initShaderBindingTables(rayTracingPipeline, m_context, vkd, device, m_data,
shaderGroupHandleSize, shaderGroupBaseAlignment, pipelineData,
replay);
const VkFormat imageFormat = m_data.testConfiguration->getResultImageFormat();
const VkImageCreateInfo imageCreateInfo =
makeImageCreateInfo(m_data.width, m_data.height, pipelineCount, imageFormat);
const VkImageSubresourceRange imageSubresourceRange =
makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 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 VkDescriptorImageInfo descriptorImageInfo =
makeDescriptorImageInfo(VK_NULL_HANDLE, *imageView, VK_IMAGE_LAYOUT_GENERAL);
const uint32_t pixelCount = m_data.width * m_data.height * pipelineCount;
const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(
pixelCount * m_data.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, pipelineCount), resultBufferImageSubresourceLayers);
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);
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;
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 = m_data.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.testType == TEST_ACCELERATION_STRUCTURES && m_data.operationType == OP_COMPACT &&
m_data.operationTarget == OT_BOTTOM_ACCELERATION;
bool bottomSerial = m_data.testType == TEST_ACCELERATION_STRUCTURES && m_data.operationType == OP_SERIALIZE &&
m_data.operationTarget == OT_BOTTOM_ACCELERATION;
bottomLevelAccelerationStructures =
m_data.testConfiguration->initBottomAccelerationStructures(m_context, m_data);
VkBuildAccelerationStructureFlagsKHR allowCompactionFlag =
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR;
VkBuildAccelerationStructureFlagsKHR emptyCompactionFlag = VkBuildAccelerationStructureFlagsKHR(0);
VkBuildAccelerationStructureFlagsKHR bottomBuildFlags =
(bottomCompact ? allowCompactionFlag : emptyCompactionFlag);
std::vector<VkAccelerationStructureKHR> accelerationStructureHandles;
std::vector<VkDeviceSize> bottomBlasCompactSize;
std::vector<VkDeviceSize> bottomBlasSerialSize;
for (size_t idx = 0; idx < bottomLevelAccelerationStructures.size(); ++idx)
{
bottomLevelAccelerationStructures[idx]->setBuildFlags(bottomBuildFlags);
bottomLevelAccelerationStructures[idx]->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddress =
(m_data.testType == TEST_ACCELERATION_STRUCTURES && replay) ? buildBLASAddresses[idx] : 0u;
if (m_data.testType == TEST_ACCELERATION_STRUCTURES && replay)
bottomLevelAccelerationStructures[idx]->setCreateFlags(
VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
bottomLevelAccelerationStructures[idx]->createAndBuild(vkd, device, *cmdBuffer, *allocator, deviceAddress);
accelerationStructureHandles.push_back(*(bottomLevelAccelerationStructures[idx]->getPtr()));
if (m_data.testType == TEST_ACCELERATION_STRUCTURES && !replay)
buildBLASAddresses.push_back(getAccelerationStructureDeviceAddress(
vkd, device, *(bottomLevelAccelerationStructures[idx]->getPtr())));
}
if (m_data.operationType == OP_COMPACT)
{
uint32_t queryCount = (m_data.operationTarget == OT_BOTTOM_ACCELERATION) ?
uint32_t(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)
{
uint32_t queryCount = (m_data.operationTarget == OT_BOTTOM_ACCELERATION) ?
uint32_t(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, uint32_t(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, uint32_t(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 idx = 0; idx < bottomLevelAccelerationStructures.size(); ++idx)
{
de::MovePtr<BottomLevelAccelerationStructure> asCopy = makeBottomLevelAccelerationStructure();
asCopy->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddress = replay ? copyBLASAddresses[idx] : 0u;
if (replay)
asCopy->setCreateFlags(VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
asCopy->createAndCopyFrom(vkd, device, *cmdBuffer, *allocator,
bottomLevelAccelerationStructures[idx].get(), 0u, deviceAddress);
bottomLevelAccelerationStructureCopies.push_back(
de::SharedPtr<BottomLevelAccelerationStructure>(asCopy.release()));
if (!replay)
copyBLASAddresses.push_back(getAccelerationStructureDeviceAddress(
vkd, device, *(bottomLevelAccelerationStructureCopies[idx]->getPtr())));
}
break;
}
case OP_COMPACT:
{
for (size_t idx = 0; idx < bottomLevelAccelerationStructures.size(); ++idx)
{
de::MovePtr<BottomLevelAccelerationStructure> asCopy = makeBottomLevelAccelerationStructure();
asCopy->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddress = replay ? copyBLASAddresses[idx] : 0u;
if (replay)
asCopy->setCreateFlags(VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
asCopy->createAndCopyFrom(vkd, device, *cmdBuffer, *allocator,
bottomLevelAccelerationStructures[idx].get(), bottomBlasCompactSize[idx],
deviceAddress);
bottomLevelAccelerationStructureCopies.push_back(
de::SharedPtr<BottomLevelAccelerationStructure>(asCopy.release()));
if (!replay)
copyBLASAddresses.push_back(getAccelerationStructureDeviceAddress(
vkd, device, *(bottomLevelAccelerationStructureCopies[idx]->getPtr())));
}
break;
}
case OP_SERIALIZE:
{
for (size_t idx = 0; idx < bottomLevelAccelerationStructures.size(); ++idx)
{
de::SharedPtr<SerialStorage> storage(
new SerialStorage(vkd, device, *allocator, m_data.buildType, bottomBlasSerialSize[idx]));
bottomLevelAccelerationStructures[idx]->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);
VkDeviceAddress deviceAddress = replay ? copyBLASAddresses[idx] : 0u;
if (replay)
asCopy->setCreateFlags(VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
asCopy->createAndDeserializeFrom(vkd, device, *cmdBuffer, *allocator, storage.get(), deviceAddress);
bottomLevelAccelerationStructureCopies.push_back(
de::SharedPtr<BottomLevelAccelerationStructure>(asCopy.release()));
if (!replay)
copyBLASAddresses.push_back(getAccelerationStructureDeviceAddress(
vkd, device, *(bottomLevelAccelerationStructureCopies[idx]->getPtr())));
}
break;
}
default:
DE_ASSERT(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.testType == TEST_ACCELERATION_STRUCTURES && m_data.operationType == OP_COMPACT &&
m_data.operationTarget == OT_TOP_ACCELERATION;
bool topSerial = m_data.testType == TEST_ACCELERATION_STRUCTURES && m_data.operationType == OP_SERIALIZE &&
m_data.operationTarget == OT_TOP_ACCELERATION;
VkBuildAccelerationStructureFlagsKHR topBuildFlags = (topCompact ? allowCompactionFlag : emptyCompactionFlag);
std::vector<VkAccelerationStructureKHR> topLevelStructureHandles;
std::vector<VkDeviceSize> topBlasCompactSize;
std::vector<VkDeviceSize> topBlasSerialSize;
topLevelAccelerationStructure = m_data.testConfiguration->initTopAccelerationStructure(
m_context, m_data, *bottomLevelAccelerationStructuresPtr);
topLevelAccelerationStructure->setBuildFlags(topBuildFlags);
topLevelAccelerationStructure->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddressBuild =
(m_data.testType == TEST_ACCELERATION_STRUCTURES && replay) ? buildTLASAddress : 0u;
if (m_data.testType == TEST_ACCELERATION_STRUCTURES && replay)
topLevelAccelerationStructure->setCreateFlags(
VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
topLevelAccelerationStructure->createAndBuild(vkd, device, *cmdBuffer, *allocator, deviceAddressBuild);
topLevelStructureHandles.push_back(*(topLevelAccelerationStructure->getPtr()));
if (m_data.testType == TEST_ACCELERATION_STRUCTURES && !replay)
buildTLASAddress =
getAccelerationStructureDeviceAddress(vkd, device, *(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, uint32_t(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, uint32_t(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->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddress = replay ? copyTLASAddress : 0u;
if (replay)
topLevelAccelerationStructureCopy->setCreateFlags(
VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
topLevelAccelerationStructureCopy->createAndCopyFrom(
vkd, device, *cmdBuffer, *allocator, topLevelAccelerationStructure.get(), 0u, deviceAddress);
if (!replay)
copyTLASAddress = getAccelerationStructureDeviceAddress(
vkd, device, *(topLevelAccelerationStructureCopy->getPtr()));
break;
}
case OP_COMPACT:
{
topLevelAccelerationStructureCopy = makeTopLevelAccelerationStructure();
topLevelAccelerationStructureCopy->setBuildType(m_data.buildType);
VkDeviceAddress deviceAddress = replay ? copyTLASAddress : 0u;
if (replay)
topLevelAccelerationStructureCopy->setCreateFlags(
VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
topLevelAccelerationStructureCopy->createAndCopyFrom(vkd, device, *cmdBuffer, *allocator,
topLevelAccelerationStructure.get(),
topBlasCompactSize[0], deviceAddress);
if (!replay)
copyTLASAddress = getAccelerationStructureDeviceAddress(
vkd, device, *(topLevelAccelerationStructureCopy->getPtr()));
break;
}
case OP_SERIALIZE:
{
de::SharedPtr<SerialStorage> storage(
new SerialStorage(vkd, device, *allocator, m_data.buildType, topBlasSerialSize[0]));
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);
VkDeviceAddress deviceAddress = replay ? copyTLASAddress : 0u;
if (replay)
topLevelAccelerationStructureCopy->setCreateFlags(
VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR);
topLevelAccelerationStructureCopy->createAndDeserializeFrom(vkd, device, *cmdBuffer, *allocator,
storage.get(), deviceAddress);
if (!replay)
copyTLASAddress = getAccelerationStructureDeviceAddress(
vkd, device, *(topLevelAccelerationStructureCopy->getPtr()));
break;
}
default:
DE_ASSERT(false);
}
topLevelRayTracedPtr = topLevelAccelerationStructureCopy.get();
}
// copy layer index into uniform buffer
for (uint32_t i = 0; i < pipelineCount; ++i)
{
deMemcpy(pipelineData.pipelines[i].uniformBuffer->getAllocation().getHostPtr(), &i, sizeof(uint32_t));
flushMappedMemoryRange(vkd, device, pipelineData.pipelines[i].uniformBuffer->getAllocation().getMemory(),
pipelineData.pipelines[i].uniformBuffer->getAllocation().getOffset(), VK_WHOLE_SIZE);
}
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_RAY_TRACING_SHADER_BIT_KHR, &preTraceMemoryBarrier);
VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
nullptr, // const void* pNext;
1u, // uint32_t accelerationStructureCount;
topLevelRayTracedPtr->getPtr() // const VkAccelerationStructureKHR* pAccelerationStructures;
};
for (uint32_t i = 0; i < pipelineCount; ++i)
{
VkDescriptorBufferInfo uniformBufferInfo =
makeDescriptorBufferInfo(pipelineData.pipelines[i].uniformBuffer->get(), 0ull, sizeof(uint32_t));
DescriptorSetUpdateBuilder()
.writeSingle(*(pipelineData.pipelines[i].descriptorSet),
DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
&uniformBufferInfo)
.writeSingle(*(pipelineData.pipelines[i].descriptorSet),
DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
&descriptorImageInfo)
.writeSingle(*(pipelineData.pipelines[i].descriptorSet),
DescriptorSetUpdateBuilder::Location::binding(2u),
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
.update(vkd, device);
vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
&(pipelineData.pipelines[i].descriptorSet.get()), 0, nullptr);
vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
*(pipelineData.pipelines[i].pipeline));
cmdTraceRays(vkd, *cmdBuffer, &(pipelineData.pipelines[i].raygenShaderBindingTableRegion),
&(pipelineData.pipelines[i].missShaderBindingTableRegion),
&(pipelineData.pipelines[i].hitShaderBindingTableRegion),
&(pipelineData.pipelines[i].callableShaderBindingTableRegion), m_data.width, m_data.height, 1);
}
const VkMemoryBarrier postTraceMemoryBarrier =
makeMemoryBarrier(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_RAY_TRACING_SHADER_BIT_KHR,
VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
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(), pixelCount * sizeof(uint32_t));
std::vector<uint32_t> result(pixelCount);
deMemcpy(result.data(), resultBuffer->getAllocation().getHostPtr(), pixelCount * sizeof(uint32_t));
return result;
}
tcu::TestStatus RayTracingCaptureReplayTestInstance::iterate(void)
{
// run test capturing different elements
const std::vector<uint32_t> captureResults = runTest(false);
// run test that replays different elements
const std::vector<uint32_t> replayResults = runTest(true);
if (!m_data.testConfiguration->verifyImage(captureResults, replayResults, m_context, m_data))
return tcu::TestStatus::fail("Fail");
return tcu::TestStatus::pass("Pass");
}
} // namespace
void addReplayShaderBindingTablesTests(tcu::TestCaseGroup *group)
{
struct
{
SBTReplayTestType testType;
const char *name;
} testTypes[] = {
// Capture-replay scenario with single captured pipeline
{TEST_PIPELINE_SINGLE, "pipeline_single"},
// Not captured pipeline created after captured one
{TEST_PIPELINE_AFTER, "pipeline_after_captured"},
// Not captured pipeline created before captured one
{TEST_PIPELINE_BEFORE, "pipeline_before_captured"},
};
for (size_t testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypeNdx)
{
TestParams testParams{testTypes[testTypeNdx].testType,
OT_NONE,
OP_NONE,
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
BTT_TRIANGLES,
TTT_IDENTICAL_INSTANCES,
RTCR_DEFAULT_SIZE,
RTCR_DEFAULT_SIZE,
de::SharedPtr<TestConfiguration>(new TestShaderBindingTablesConfiguration())};
group->addChild(
new RayTracingCaptureReplayTestCase(group->getTestContext(), testTypes[testTypeNdx].name, testParams));
}
}
void addReplayAccelerationStruturesTests(tcu::TestCaseGroup *group)
{
struct
{
ASOperationType operationType;
const char *name;
} operationTypes[] = {
{OP_NONE, "building"},
{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
{
ASOperationTarget operationTarget;
const char *name;
} operationTargets[] = {
{OT_TOP_ACCELERATION, "top_acceleration_structure"},
{OT_BOTTOM_ACCELERATION, "bottom_acceleration_structure"},
};
struct
{
ASBottomTestType testType;
const char *name;
} bottomTestTypes[] = {
{BTT_TRIANGLES, "triangles"},
{BTT_AABBS, "aabbs"},
};
for (size_t operationTypeNdx = 0; operationTypeNdx < DE_LENGTH_OF_ARRAY(operationTypes); ++operationTypeNdx)
{
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)
{
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)
{
ASTopTestType topTest =
(operationTargets[operationTargetNdx].operationTarget == OT_TOP_ACCELERATION) ?
TTT_DIFFERENT_INSTANCES :
TTT_IDENTICAL_INSTANCES;
TestParams testParams{
TEST_ACCELERATION_STRUCTURES,
operationTargets[operationTargetNdx].operationTarget,
operationTypes[operationTypeNdx].operationType,
buildTypes[buildTypeNdx].buildType,
bottomTestTypes[testTypeNdx].testType,
topTest,
RTCR_DEFAULT_SIZE,
RTCR_DEFAULT_SIZE,
de::SharedPtr<TestConfiguration>(new TestAccelerationStructuresConfiguration())};
operationTargetGroup->addChild(new RayTracingCaptureReplayTestCase(
group->getTestContext(), bottomTestTypes[testTypeNdx].name, testParams));
}
buildGroup->addChild(operationTargetGroup.release());
}
operationTypeGroup->addChild(buildGroup.release());
}
group->addChild(operationTypeGroup.release());
}
}
tcu::TestCaseGroup *createCaptureReplayTests(tcu::TestContext &testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "capture_replay"));
// Test replaying shader binding tables
addTestGroup(group.get(), "shader_binding_tables", addReplayShaderBindingTablesTests);
// Test replaying acceleration structure
addTestGroup(group.get(), "acceleration_structures", addReplayAccelerationStruturesTests);
return group.release();
}
} // namespace RayTracing
} // namespace vkt