dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.cpu_built.bottom
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.top
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.bottom
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.mix_same_diff_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.mix_same_diff_instances
dEQP-VK.ray_tracing_pipeline.procedural_geometry.object_behind_bounding_boxes
dEQP-VK.ray_tracing_pipeline.procedural_geometry.triangle_in_between
dEQP-VK.ray_tracing_pipeline.indirect.build_structure
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.cpu_built.bottom
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.top
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.bottom
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.mix_same_diff_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.mix_same_diff_instances
dEQP-VK.ray_tracing_pipeline.procedural_geometry.object_behind_bounding_boxes
dEQP-VK.ray_tracing_pipeline.procedural_geometry.triangle_in_between
dEQP-VK.ray_tracing_pipeline.indirect.build_structure
#include "vkQueryUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkBarrierUtil.hpp"
+#include "vkCmdUtil.hpp"
#include "deStringUtil.hpp"
return result;
}
+static inline 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);
+}
+
static inline VkAccelerationStructureGeometryDataKHR makeVkAccelerationStructureGeometryDataKHR (const VkAccelerationStructureGeometryTrianglesDataKHR& triangles)
{
VkAccelerationStructureGeometryDataKHR result;
Allocator& allocator,
const VkAccelerationStructureBuildTypeKHR buildType,
const VkDeviceSize storageSize)
- : m_buildType (buildType)
- , m_storageSize(storageSize)
+ : m_buildType (buildType)
+ , m_storageSize (storageSize)
{
const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(storageSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
try
}
}
+SerialStorage::SerialStorage (const DeviceInterface& vk,
+ const VkDevice device,
+ Allocator& allocator,
+ const VkAccelerationStructureBuildTypeKHR buildType,
+ const SerialInfo& serialInfo)
+ : m_buildType (buildType)
+ , m_storageSize (serialInfo.sizes()[0]) // raise assertion if serialInfo is empty
+ , m_serialInfo (serialInfo)
+{
+ DE_ASSERT(serialInfo.sizes().size() >= 2u);
+
+ // create buffer for top-level acceleration structure
+ {
+ const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(m_storageSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
+ m_buffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::DeviceAddress));
+ }
+
+ // create buffers for bottom-level acceleration structures
+ {
+ std::vector<deUint64> addrs;
+
+ for (std::size_t i = 1; i < serialInfo.addresses().size(); ++i)
+ {
+ const deUint64& lookAddr = serialInfo.addresses()[i];
+ auto end = addrs.end();
+ auto match = std::find_if(addrs.begin(), end, [&](const deUint64& item){ return item == lookAddr; });
+ if (match == end)
+ {
+ addrs.emplace_back(lookAddr);
+ m_bottoms.emplace_back(de::SharedPtr<SerialStorage>(new SerialStorage(vk, device, allocator, buildType, serialInfo.sizes()[i])));
+ }
+ }
+ }
+}
+
VkDeviceOrHostAddressKHR SerialStorage::getAddress (const DeviceInterface& vk,
const VkDevice device)
{
return makeDeviceOrHostAddressKHR(m_buffer->getAllocation().getHostPtr());
}
-VkDeviceOrHostAddressConstKHR SerialStorage::getHostAddressConst()
+SerialStorage::AccelerationStructureHeader* SerialStorage::getASHeader ()
+{
+ return reinterpret_cast<AccelerationStructureHeader*>(getHostAddress().hostAddress);
+}
+
+bool SerialStorage::hasDeepFormat () const
+{
+ return (m_serialInfo.sizes().size() >= 2u);
+}
+
+de::SharedPtr<SerialStorage> SerialStorage::getBottomStorage (deUint32 index) const
+{
+ return m_bottoms[index];
+}
+
+VkDeviceOrHostAddressKHR SerialStorage::getHostAddress (VkDeviceSize offset)
{
- return makeDeviceOrHostAddressConstKHR(m_buffer->getAllocation().getHostPtr());
+ DE_ASSERT(offset < m_storageSize);
+ return makeDeviceOrHostAddressKHR(static_cast<deUint8*>(m_buffer->getAllocation().getHostPtr()) + offset);
+}
+
+VkDeviceOrHostAddressConstKHR SerialStorage::getHostAddressConst (VkDeviceSize offset)
+{
+ return makeDeviceOrHostAddressConstKHR(static_cast<deUint8*>(m_buffer->getAllocation().getHostPtr()) + offset);
}
VkDeviceOrHostAddressConstKHR SerialStorage::getAddressConst (const DeviceInterface& vk,
return getHostAddressConst();
}
-VkDeviceSize SerialStorage::getStorageSize ()
+inline VkDeviceSize SerialStorage::getStorageSize () const
{
return m_storageSize;
}
+inline const SerialInfo& SerialStorage::getSerialInfo () const
+{
+ return m_serialInfo;
+}
+
deUint64 SerialStorage::getDeserializedSize ()
{
deUint64 result = 0;
copyFrom(vk, device, cmdBuffer, accelerationStructure, compactCopySize > 0u);
}
-void TopLevelAccelerationStructure::createAndDeserializeFrom (const DeviceInterface& vk,
+void TopLevelAccelerationStructure::createAndDeserializeFrom (const DeviceInterface& vk,
const VkDevice device,
const VkCommandBuffer cmdBuffer,
Allocator& allocator,
DE_ASSERT(storage != NULL);
DE_ASSERT(storage->getStorageSize() >= SerialStorage::SERIAL_STORAGE_SIZE_MIN);
create(vk, device, allocator, storage->getDeserializedSize(), deviceAddress);
+ if (storage->hasDeepFormat()) createAndDeserializeBottoms(vk, device, cmdBuffer, allocator, storage);
deserialize(vk, device, cmdBuffer, storage);
}
const VkCommandBuffer cmdBuffer,
SerialStorage* storage) override;
+ std::vector<VkDeviceSize> getSerializingSizes (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkQueue queue,
+ const deUint32 queueFamilyIndex) override;
+
+ std::vector<deUint64> getSerializingAddresses (const DeviceInterface& vk,
+ const VkDevice device) const override;
+
+
const VkAccelerationStructureKHR* getPtr (void) const override;
void updateInstanceMatrix (const DeviceInterface& vk,
deUint32 m_indirectBufferStride;
bool m_usePPGeometries;
+
void prepareInstances (const DeviceInterface& vk,
const VkDevice device,
VkAccelerationStructureGeometryKHR& accelerationStructureGeometryKHR,
std::vector<deUint32>& maxPrimitiveCounts);
+
+ void serializeBottoms (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkCommandBuffer cmdBuffer,
+ SerialStorage* storage,
+ VkDeferredOperationKHR deferredOperation);
+
+ void createAndDeserializeBottoms (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkCommandBuffer cmdBuffer,
+ Allocator& allocator,
+ SerialStorage* storage) override;
};
deUint32 TopLevelAccelerationStructureKHR::getRequiredAllocationCount (void)
VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
*(getPtr()), // VkAccelerationStructureKHR src;
- storage->getAddress(vk,device), // VkDeviceOrHostAddressKHR dst;
+ storage->getAddress(vk, device), // VkDeviceOrHostAddressKHR dst;
VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR // VkCopyAccelerationStructureModeKHR mode;
};
if (m_buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR)
{
vk.cmdCopyAccelerationStructureToMemoryKHR(cmdBuffer, ©AccelerationStructureInfo);
+ if (storage->hasDeepFormat()) serializeBottoms(vk, device, cmdBuffer, storage, DE_NULL);
}
else if (!m_deferredOperation)
{
VK_CHECK(vk.copyAccelerationStructureToMemoryKHR(device, DE_NULL, ©AccelerationStructureInfo));
+ if (storage->hasDeepFormat()) serializeBottoms(vk, device, cmdBuffer, storage, DE_NULL);
}
else
{
const VkResult result = vk.copyAccelerationStructureToMemoryKHR(device, deferredOperation, ©AccelerationStructureInfo);
DE_ASSERT(result == VK_OPERATION_DEFERRED_KHR || result == VK_OPERATION_NOT_DEFERRED_KHR || result == VK_SUCCESS);
+ if (storage->hasDeepFormat()) serializeBottoms(vk, device, cmdBuffer, storage, deferredOperation);
finishDeferredOperation(vk, device, deferredOperation, m_workerThreadCount, result == VK_OPERATION_NOT_DEFERRED_KHR);
}
}
}
+void TopLevelAccelerationStructureKHR::serializeBottoms (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkCommandBuffer cmdBuffer,
+ SerialStorage* storage,
+ VkDeferredOperationKHR deferredOperation)
+{
+ DE_UNREF(deferredOperation);
+ DE_ASSERT(storage->hasDeepFormat());
+
+ const std::vector<deUint64>& addresses = storage->getSerialInfo().addresses();
+ const std::size_t cbottoms = m_bottomLevelInstances.size();
+
+ deUint32 storageIndex = 0;
+ std::vector<deUint64> matches;
+
+ for (std::size_t i = 0; i < cbottoms; ++i)
+ {
+ const deUint64& lookAddr = addresses[i+1];
+ auto end = matches.end();
+ auto match = std::find_if(matches.begin(), end, [&](const deUint64& item){ return item == lookAddr; });
+ if (match == end)
+ {
+ matches.emplace_back(lookAddr);
+ m_bottomLevelInstances[i].get()->serialize(vk, device, cmdBuffer, storage->getBottomStorage(storageIndex).get());
+ storageIndex += 1;
+ }
+ }
+}
+
+void TopLevelAccelerationStructureKHR::createAndDeserializeBottoms (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkCommandBuffer cmdBuffer,
+ Allocator& allocator,
+ SerialStorage* storage)
+{
+ DE_ASSERT(storage->hasDeepFormat());
+ DE_ASSERT(m_bottomLevelInstances.size() == 0);
+
+ const std::vector<deUint64>& addresses = storage->getSerialInfo().addresses();
+ const std::size_t cbottoms = addresses.size() - 1;
+ deUint32 storageIndex = 0;
+ std::vector<std::pair<deUint64, std::size_t>> matches;
+
+ for (std::size_t i = 0; i < cbottoms; ++i)
+ {
+ const deUint64& lookAddr = addresses[i+1];
+ auto end = matches.end();
+ auto match = std::find_if(matches.begin(), end, [&](const std::pair<deUint64, deUint32>& item){ return item.first == lookAddr; });
+ if (match != end)
+ {
+ m_bottomLevelInstances .emplace_back(m_bottomLevelInstances[match->second]);
+ }
+ else
+ {
+ de::MovePtr<BottomLevelAccelerationStructure> blas = makeBottomLevelAccelerationStructure();
+ blas->createAndDeserializeFrom(vk, device, cmdBuffer, allocator, storage->getBottomStorage(storageIndex).get());
+ m_bottomLevelInstances.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
+ matches.emplace_back(lookAddr, i);
+ storageIndex += 1;
+ }
+ }
+
+ std::vector<deUint64> newAddresses = getSerializingAddresses(vk, device);
+ DE_ASSERT(addresses.size() == newAddresses.size());
+
+ SerialStorage::AccelerationStructureHeader* header = storage->getASHeader();
+ DE_ASSERT(cbottoms ==header->handleCount);
+
+ // finally update bottom-level AS addresses before top-level AS deserialization
+ for (std::size_t i = 0; i < cbottoms; ++i)
+ {
+ header->handleArray[i] = newAddresses[i+1];
+ }
+}
+
+std::vector<VkDeviceSize> TopLevelAccelerationStructureKHR::getSerializingSizes (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkQueue queue,
+ const deUint32 queueFamilyIndex)
+{
+ const deUint32 queryCount(deUint32(m_bottomLevelInstances.size()) + 1);
+ std::vector<VkAccelerationStructureKHR> handles(queryCount);
+ std::vector<VkDeviceSize> sizes(queryCount);
+
+ handles[0] = m_accelerationStructureKHR.get();
+
+ for (deUint32 h = 1; h < queryCount; ++h)
+ handles[h] = *m_bottomLevelInstances[h-1].get()->getPtr();
+
+ if (VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR == m_buildType)
+ queryAccelerationStructureSize(vk, device, DE_NULL, handles, m_buildType, DE_NULL, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, 0u, sizes);
+ else
+ {
+ const Move<VkCommandPool> cmdPool = createCommandPool(vk, device, 0, queueFamilyIndex);
+ const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+ const Move<VkQueryPool> queryPool = makeQueryPool(vk, device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, queryCount);
+
+ beginCommandBuffer(vk, *cmdBuffer);
+ queryAccelerationStructureSize(vk, device, *cmdBuffer, handles, m_buildType, *queryPool, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, 0u, sizes);
+ endCommandBuffer(vk, *cmdBuffer);
+ submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
+
+ VK_CHECK(vk.getQueryPoolResults(device, *queryPool, 0u, queryCount, queryCount * sizeof(VkDeviceSize), sizes.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT));
+ }
+
+ return sizes;
+}
+
+std::vector<deUint64> TopLevelAccelerationStructureKHR::getSerializingAddresses (const DeviceInterface& vk, const VkDevice device) const
+{
+ std::vector<deUint64> result(m_bottomLevelInstances.size() + 1);
+
+ VkAccelerationStructureDeviceAddressInfoKHR asDeviceAddressInfo =
+ {
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ DE_NULL // VkAccelerationStructureKHR accelerationStructure;
+ };
+
+ if (m_buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR)
+ {
+ asDeviceAddressInfo.accelerationStructure = m_accelerationStructureKHR.get();
+ result[0] = vk.getAccelerationStructureDeviceAddressKHR(device, &asDeviceAddressInfo);
+ }
+ else
+ {
+ result[0] = deUint64(getPtr()->getInternal());
+ }
+
+ for (size_t instanceNdx = 0; instanceNdx < m_bottomLevelInstances.size(); ++instanceNdx)
+ {
+ const BottomLevelAccelerationStructure& bottomLevelAccelerationStructure = *m_bottomLevelInstances[instanceNdx];
+ const VkAccelerationStructureKHR accelerationStructureKHR = *bottomLevelAccelerationStructure.getPtr();
+
+ if (m_buildType == VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR)
+ {
+ asDeviceAddressInfo.accelerationStructure = accelerationStructureKHR;
+ result[instanceNdx+1] = vk.getAccelerationStructureDeviceAddressKHR(device, &asDeviceAddressInfo);
+ }
+ else
+ {
+ result[instanceNdx+1] = deUint64(accelerationStructureKHR.getInternal());
+ }
+ }
+
+ return result;
+}
+
const VkAccelerationStructureKHR* TopLevelAccelerationStructureKHR::getPtr (void) const
{
return &m_accelerationStructureKHR.get();
const VkBuffer buffer,
VkDeviceSize offset );
+// type used for creating a deep serialization/deserialization of top-level acceleration structures
+class SerialInfo
+{
+ std::vector<deUint64> m_addresses;
+ std::vector<VkDeviceSize> m_sizes;
+public:
+
+ SerialInfo() = default;
+
+ // addresses: { (owner-top-level AS address) [, (first bottom_level AS address), (second bottom_level AS address), ...] }
+ // sizes: { (owner-top-level AS serial size) [, (first bottom_level AS serial size), (second bottom_level AS serial size), ...] }
+ SerialInfo(const std::vector<deUint64>& addresses, const std::vector<VkDeviceSize>& sizes)
+ : m_addresses(addresses), m_sizes(sizes)
+ {
+ DE_ASSERT(!addresses.empty() && addresses.size() == sizes.size());
+ }
+
+ const std::vector<deUint64>& addresses () const { return m_addresses; }
+ const std::vector<VkDeviceSize>& sizes () const { return m_sizes; }
+};
+
class SerialStorage
{
public:
SERIAL_STORAGE_SIZE_MIN
};
+ // An old fashion C-style structure that simplifies an access to the AS header
+ struct alignas(16) AccelerationStructureHeader
+ {
+ union {
+ struct {
+ deUint8 driverUUID[VK_UUID_SIZE];
+ deUint8 compactUUID[VK_UUID_SIZE];
+ };
+ deUint8 uuids[VK_UUID_SIZE * 2];
+ };
+ deUint64 serializedSize;
+ deUint64 deserializedSize;
+ deUint64 handleCount;
+ VkDeviceAddress handleArray[1];
+ };
+
SerialStorage () = delete;
SerialStorage (const DeviceInterface& vk,
const VkDevice device,
Allocator& allocator,
const VkAccelerationStructureBuildTypeKHR buildType,
const VkDeviceSize storageSize);
+ // An additional constructor for creating a deep copy of top-level AS's.
+ SerialStorage (const DeviceInterface& vk,
+ const VkDevice device,
+ Allocator& allocator,
+ const VkAccelerationStructureBuildTypeKHR buildType,
+ const SerialInfo& SerialInfo);
- // this method will return host addres if acc was build on cpu and device addres when it was build on gpu
+ // below methods will return host addres if AS was build on cpu and device addres when it was build on gpu
VkDeviceOrHostAddressKHR getAddress (const DeviceInterface& vk,
const VkDevice device);
- // this method retuns host addres regardles of where acc was build
- VkDeviceOrHostAddressConstKHR getHostAddressConst ();
VkDeviceOrHostAddressConstKHR getAddressConst (const DeviceInterface& vk,
const VkDevice device);
- VkDeviceSize getStorageSize ();
+
+ // this methods retun host address regardless of where AS was built
+ VkDeviceOrHostAddressKHR getHostAddress (VkDeviceSize offset = 0);
+ VkDeviceOrHostAddressConstKHR getHostAddressConst (VkDeviceSize offset = 0);
+
+ // works the similar way as getHostAddressConst() but returns more readable/intuitive object
+ AccelerationStructureHeader* getASHeader ();
+ bool hasDeepFormat () const;
+ de::SharedPtr<SerialStorage> getBottomStorage (deUint32 index) const;
+
+ VkDeviceSize getStorageSize () const;
+ const SerialInfo& getSerialInfo () const;
deUint64 getDeserializedSize ();
protected:
- VkAccelerationStructureBuildTypeKHR m_buildType;
- de::MovePtr<BufferWithMemory> m_buffer;
- VkDeviceSize m_storageSize;
-
+ const VkAccelerationStructureBuildTypeKHR m_buildType;
+ const VkDeviceSize m_storageSize;
+ const SerialInfo m_serialInfo;
+ de::MovePtr<BufferWithMemory> m_buffer;
+ std::vector<de::SharedPtr<SerialStorage>> m_bottoms;
};
class BottomLevelAccelerationStructure
const VkCommandBuffer cmdBuffer,
SerialStorage* storage) = DE_NULL;
+ virtual std::vector<VkDeviceSize> getSerializingSizes (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkQueue queue,
+ const deUint32 queueFamilyIndex) = DE_NULL;
+
+ virtual std::vector<deUint64> getSerializingAddresses (const DeviceInterface& vk,
+ const VkDevice device) const = DE_NULL;
+
// helper methods for typical acceleration structure creation tasks
void createAndBuild (const DeviceInterface& vk,
const VkDevice device,
VkDeviceSize m_structureSize;
VkDeviceSize m_updateScratchSize;
VkDeviceSize m_buildScratchSize;
+
+ virtual void createAndDeserializeBottoms (const DeviceInterface& vk,
+ const VkDevice device,
+ const VkCommandBuffer cmdBuffer,
+ Allocator& allocator,
+ SerialStorage* storage) = DE_NULL;
};
de::MovePtr<TopLevelAccelerationStructure> makeTopLevelAccelerationStructure ();
enum TopTestType
{
TTT_IDENTICAL_INSTANCES,
- TTT_DIFFERENT_INSTANCES
+ TTT_DIFFERENT_INSTANCES,
+ TTT_MIX_INSTANCES,
};
enum OperationTarget
getDeviceASCompatibilityKHR (const deUint8* versionInfoData);
std::string getUUIDsString (const deUint8* header) const;
+
+private:
+ const de::SharedPtr<TestParams> m_params;
+};
+
+// Tests for updating botto-level AS(s) address(es) in top-level AS's header
+class RayTracingHeaderBottomAddressTestInstance : public TestInstance
+{
+public:
+ RayTracingHeaderBottomAddressTestInstance (Context& context,
+ const de::SharedPtr<TestParams> params)
+ : TestInstance (context)
+ , m_params (params)
+ {
+ }
+ tcu::TestStatus iterate (void) override;
+
+protected:
+ de::SharedPtr<TopLevelAccelerationStructure> prepareTopAccelerationStructure (const DeviceInterface& vk,
+ VkDevice device,
+ Allocator& allocator,
+ VkCommandBuffer cmdBuffer);
+
+ bool areAddressesTheSame (const std::vector<deUint64>& addresses,
+ const SerialStorage::AccelerationStructureHeader* header);
+
+ bool areAddressesDifferent (const std::vector<deUint64>& addresses1,
+ const std::vector<deUint64>& addresses2);
private:
const de::SharedPtr<TestParams> m_params;
};
de::SharedPtr<TestParams> m_params;
};
+class RayTracingHeaderBottomAddressTestCase : public TestCase
+{
+public:
+ RayTracingHeaderBottomAddressTestCase (tcu::TestContext& ctx, const char* name, const de::SharedPtr<TestParams> params)
+ : TestCase(ctx, name, std::string())
+ , m_params(params)
+ {
+ }
+
+ void checkSupport (Context& context) const override;
+ TestInstance* createInstance (Context& context) const override
+ {
+ return new RayTracingHeaderBottomAddressTestInstance(context, m_params);
+ }
+
+private:
+ de::SharedPtr<TestParams> m_params;
+};
+
void RayTracingDeviceASCompabilityKHRTestCase ::checkSupport (Context& context) const
{
context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
checkAccelerationStructureVertexBufferFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_params->vertexFormat);
}
+void RayTracingHeaderBottomAddressTestCase ::checkSupport (Context& context) const
+{
+ context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
+
+ const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
+ if (m_params->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_params->vertexFormat);
+}
+
VkAccelerationStructureCompatibilityKHR RayTracingDeviceASCompabilityKHRTestInstance::getDeviceASCompatibilityKHR (const deUint8* versionInfoData)
{
const VkDevice device = m_context.getDevice();
return result;
}
+de::SharedPtr<TopLevelAccelerationStructure>
+RayTracingHeaderBottomAddressTestInstance::prepareTopAccelerationStructure (const DeviceInterface& vk,
+ VkDevice device,
+ Allocator& allocator,
+ VkCommandBuffer cmdBuffer)
+{
+ const std::vector<tcu::Vec3> geometryData =
+ {
+ { 0.0, 0.0, 0.0 },
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ };
+
+ std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> bottoms;
+
+ if (TTT_IDENTICAL_INSTANCES == m_params->topTestType)
+ {
+ auto blas = de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
+ blas->setBuildType(m_params->buildType);
+ blas->setGeometryData(geometryData, true, VK_GEOMETRY_OPAQUE_BIT_KHR);
+ blas->createAndBuild(vk, device, cmdBuffer, allocator);
+ for (deUint32 i = 0; i < m_params->width; ++i)
+ {
+ bottoms.emplace_back(blas);
+ }
+ }
+ else if (TTT_DIFFERENT_INSTANCES == m_params->topTestType)
+ {
+ for (deUint32 i = 0; i < m_params->width; ++i)
+ {
+ auto blas = de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
+ blas->setBuildType(m_params->buildType);
+ blas->setGeometryData(geometryData, true, VK_GEOMETRY_OPAQUE_BIT_KHR);
+ blas->createAndBuild(vk, device, cmdBuffer, allocator);
+ bottoms.emplace_back(blas);
+ }
+ }
+ else // TTT_MIX_INSTANCES == m_params->topTestType
+ {
+ for (deUint32 i = 0; i < m_params->width; ++i)
+ {
+ {
+ auto blas1 = de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
+ blas1->setBuildType(m_params->buildType);
+ blas1->setGeometryData(geometryData, true, VK_GEOMETRY_OPAQUE_BIT_KHR);
+ blas1->createAndBuild(vk, device, cmdBuffer, allocator);
+ bottoms.emplace_back(blas1);
+ }
+
+ {
+ auto blas2 = de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
+ blas2->setBuildType(m_params->buildType);
+ blas2->setGeometryData(geometryData, true, VK_GEOMETRY_OPAQUE_BIT_KHR);
+ blas2->createAndBuild(vk, device, cmdBuffer, allocator);
+ bottoms.emplace_back(blas2);
+ }
+ }
+
+ }
+
+ const std::size_t instanceCount = bottoms.size();
+
+ de::MovePtr<TopLevelAccelerationStructure> tlas = makeTopLevelAccelerationStructure();
+ tlas->setBuildType(m_params->buildType);
+ tlas->setInstanceCount(instanceCount);
+
+ for (std::size_t i = 0; i < instanceCount; ++i)
+ {
+ const VkTransformMatrixKHR transformMatrixKHR =
+ {
+ { // float matrix[3][4];
+ { 1.0f, 0.0f, 0.0f, (float)i },
+ { 0.0f, 1.0f, 0.0f, (float)i },
+ { 0.0f, 0.0f, 1.0f, 0.0f },
+ }
+ };
+ tlas->addInstance(bottoms[i], transformMatrixKHR, 0, 0xFFu, 0u, getCullFlags((m_params->cullFlags)));
+ }
+
+ tlas->createAndBuild(vk, device, cmdBuffer, allocator);
+
+ return de::SharedPtr<TopLevelAccelerationStructure>(tlas.release());
+}
+
+tcu::TestStatus RayTracingHeaderBottomAddressTestInstance::iterate (void)
+{
+ const DeviceInterface& vkd = m_context.getDeviceInterface();
+ const VkDevice device = m_context.getDevice();
+ const deUint32 familyIndex = m_context.getUniversalQueueFamilyIndex();
+ const VkQueue queue = m_context.getUniversalQueue();
+ Allocator& allocator = m_context.getDefaultAllocator();
+
+ const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, familyIndex);
+ const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+
+ beginCommandBuffer(vkd, *cmdBuffer, 0);
+ de::SharedPtr<TopLevelAccelerationStructure> src = prepareTopAccelerationStructure(vkd, device, allocator, *cmdBuffer);
+ endCommandBuffer(vkd, *cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
+
+ de::MovePtr<TopLevelAccelerationStructure> dst = makeTopLevelAccelerationStructure();
+
+ const std::vector<deUint64> inAddrs = src->getSerializingAddresses(vkd, device);
+ const std::vector<VkDeviceSize> inSizes = src->getSerializingSizes(vkd, device, queue, familyIndex);
+
+ const SerialInfo serialInfo (inAddrs, inSizes);
+ SerialStorage deepStorage (vkd, device, allocator, m_params->buildType, serialInfo);
+
+ // make deep serialization - top-level AS width bottom-level structures that it owns
+ beginCommandBuffer(vkd, *cmdBuffer, 0);
+ src->serialize(vkd, device, *cmdBuffer, &deepStorage);
+ endCommandBuffer(vkd, *cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
+
+ // deserialize all from the previous step to a new top-level AS
+ // bottom-level structure addresses should be updated when deep data is deserialized
+ beginCommandBuffer(vkd, *cmdBuffer, 0);
+ dst->createAndDeserializeFrom(vkd, device, *cmdBuffer, allocator, &deepStorage);
+ endCommandBuffer(vkd, *cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
+
+ SerialStorage shallowStorage (vkd, device, allocator, m_params->buildType, inSizes[0]);
+
+ // make shallow serialization - only top-level AS without bottom-level structures
+ beginCommandBuffer(vkd, *cmdBuffer, 0);
+ dst->serialize(vkd, device, *cmdBuffer, &shallowStorage);
+ endCommandBuffer(vkd, *cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
+
+ // get data to verification
+ const std::vector<deUint64> outAddrs = dst->getSerializingAddresses(vkd, device);
+ const SerialStorage::AccelerationStructureHeader* header = shallowStorage.getASHeader();
+
+ return (areAddressesDifferent(inAddrs, outAddrs) && areAddressesTheSame(outAddrs, header)) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
+}
+
+bool RayTracingHeaderBottomAddressTestInstance::areAddressesTheSame (const std::vector<deUint64>& addresses, const SerialStorage::AccelerationStructureHeader* header)
+{
+ const deUint32 cbottoms = deUint32(addresses.size() - 1);
+
+ // header should contain the same number of handles as serialized/deserialized top-level AS
+ if (cbottoms != header->handleCount) return false;
+
+ std::set<deUint64> refAddrs;
+ std::set<deUint64> checkAddrs;
+
+ // distinct, squach and sort address list
+ for (deUint32 i = 0; i < cbottoms; ++i)
+ {
+ refAddrs.insert(addresses[i+1]);
+ checkAddrs.insert(header->handleArray[i]);
+ }
+
+ return std::equal(refAddrs.begin(), refAddrs.end(), checkAddrs.begin());
+}
+
+bool RayTracingHeaderBottomAddressTestInstance::areAddressesDifferent (const std::vector<deUint64>& addresses1, const std::vector<deUint64>& addresses2)
+{
+ // the number of addresses must be equal
+ if (addresses1.size() != addresses2.size())
+ return false;
+
+ // adresses of top-level AS must differ
+ if (addresses1[0] == addresses2[0])
+ return false;
+
+ std::set<deUint64> addrs1;
+ std::set<deUint64> addrs2;
+ deUint32 matches = 0;
+ const deUint32 cbottoms = deUint32(addresses1.size() - 1);
+
+ for (deUint32 i = 0; i < cbottoms; ++i)
+ {
+ addrs1.insert(addresses1[i+1]);
+ addrs2.insert(addresses2[i+1]);
+ }
+
+ // the first addresses set must not contain any address from the second addresses set
+ for (auto& addr1 : addrs1)
+ {
+ if (addrs2.end() != addrs2.find(addr1))
+ ++matches;
+ }
+
+ return (matches == 0);
+}
+
} // anonymous
void addBasicBuildingTests(tcu::TestCaseGroup* group)
}
}
+void addUpdateHeaderBottomAddressTests (tcu::TestCaseGroup* group)
+{
+ struct
+ {
+ vk::VkAccelerationStructureBuildTypeKHR buildType;
+ std::string name;
+ }
+ const buildTypes[] =
+ {
+ { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR, "cpu_built" },
+ { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, "gpu_built" },
+ };
+
+ struct
+ {
+ TopTestType type;
+ std::string name;
+ }
+ const instTypes[] =
+ {
+ { TTT_IDENTICAL_INSTANCES, "the_same_instances" },
+ { TTT_DIFFERENT_INSTANCES, "different_instances" },
+ { TTT_MIX_INSTANCES, "mix_same_diff_instances" },
+ };
+
+ auto& ctx = group->getTestContext();
+
+ 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 instTypeIdx = 0; instTypeIdx < DE_LENGTH_OF_ARRAY(instTypes); ++instTypeIdx)
+ {
+ TestParams testParams
+ {
+ buildTypes[buildTypeIdx].buildType, // buildType
+ VK_FORMAT_R32G32B32_SFLOAT, // vertexFormat
+ false, // padVertices
+ VK_INDEX_TYPE_NONE_KHR, // indexType
+ BTT_TRIANGLES, // bottomTestType
+ InstanceCullFlags::NONE, // cullFlags
+ false, // bottomUsesAOP
+ false, // bottomGeneric
+ instTypes[instTypeIdx].type, // topTestType
+ false, // topUsesAOP
+ false, // topGeneric
+ VkBuildAccelerationStructureFlagsKHR(0u), // buildFlags
+ OT_TOP_ACCELERATION, // operationTarget
+ OP_NONE, // operationType
+ RTAS_DEFAULT_SIZE, // width
+ RTAS_DEFAULT_SIZE, // height
+ de::SharedPtr<TestConfiguration>(DE_NULL), // testConfiguration
+ 0u, // workerThreadsCount
+ EmptyAccelerationStructureCase::NOT_EMPTY, // emptyASCase
+ InstanceCustomIndexCase::NONE, // instanceCustomIndexCase
+ };
+ buildTypeGroup->addChild(new RayTracingHeaderBottomAddressTestCase(ctx, instTypes[instTypeIdx].name.c_str(), de::SharedPtr<TestParams>(new TestParams(testParams))));
+ }
+ group->addChild(buildTypeGroup.release());
+ }
+}
+
tcu::TestCaseGroup* createAccelerationStructuresTests(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "acceleration_structures", "Acceleration structure tests"));
addTestGroup(group.get(), "empty", "Test building empty acceleration structures using different methods", addEmptyAccelerationStructureTests);
addTestGroup(group.get(), "instance_index", "Test using different values for the instance index and checking them in shaders", addInstanceIndexTests);
addTestGroup(group.get(), "device_compability_khr", "", addGetDeviceAccelerationStructureCompabilityTests);
+ addTestGroup(group.get(), "header_bottom_address", "", addUpdateHeaderBottomAddressTests);
return group.release();
}
} // RayTracing
} // vkt
+
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.cpu_built.bottom
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.top
dEQP-VK.ray_tracing_pipeline.acceleration_structures.device_compability_khr.gpu_built.bottom
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.cpu_built.mix_same_diff_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.the_same_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.different_instances
+dEQP-VK.ray_tracing_pipeline.acceleration_structures.header_bottom_address.gpu_built.mix_same_diff_instances
dEQP-VK.ray_tracing_pipeline.procedural_geometry.object_behind_bounding_boxes
dEQP-VK.ray_tracing_pipeline.procedural_geometry.triangle_in_between
dEQP-VK.ray_tracing_pipeline.indirect.build_structure