diff --git a/config/Sources.cmake b/config/Sources.cmake index 83228a385367472751cf0b30f1ed4801841c90bc..4cae57fd99c284a93f7522da18af020a33d6406e 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -145,6 +145,9 @@ set(vkcv_sources ${vkcv_include}/vkcv/VertexData.hpp ${vkcv_source}/vkcv/VertexData.cpp + ${vkcv_include}/vkcv/GeometryData.hpp + ${vkcv_source}/vkcv/GeometryData.cpp + ${vkcv_include}/vkcv/Result.hpp ${vkcv_include}/vkcv/RayTracingPipelineConfig.hpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index d9749947ee27520fb8fc0f8513c13ef76a7758ea..d7d850f7190c6cc8bf49501df932a53744cec1f0 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -19,6 +19,7 @@ #include "Drawcall.hpp" #include "Event.hpp" #include "EventFunctionTypes.hpp" +#include "GeometryData.hpp" #include "GraphicsPipelineConfig.hpp" #include "Handles.hpp" #include "ImageConfig.hpp" @@ -959,5 +960,35 @@ namespace vkcv { * @return Vulkan device memory */ [[nodiscard]] vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle &handle) const; + + /** + * @brief Creates an acceleration structure handle built with a given list of geometry data. + * + * @param[in] geometryData List of geometry data + * @return Acceleration structure handle + */ + AccelerationStructureHandle createAccelerationStructure( + const std::vector<GeometryData> &geometryData); + + /** + * @brief the underlying vulkan handle for an acceleration structure + * by its given acceleration structure handle. + * + * @param[in] handle Acceleration structure handle + * @return Vulkan acceleration structure + */ + [[nodiscard]] vk::AccelerationStructureKHR getVulkanAccelerationStructure( + const AccelerationStructureHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for an acceleration + * structure by its given acceleration structure handle. + * + * @param[in] handle Acceleration structure handle + * @return Vulkan buffer + */ + [[nodiscard]] vk::Buffer getVulkanBuffer( + const vkcv::AccelerationStructureHandle &handle) const; + }; } // namespace vkcv diff --git a/include/vkcv/GeometryData.hpp b/include/vkcv/GeometryData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0dcea5be480b47f8246e47ccb55d66490ec00a20 --- /dev/null +++ b/include/vkcv/GeometryData.hpp @@ -0,0 +1,127 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/GeometryData.hpp + * @brief Types to configure geometry data for acceleration structure building. + */ + +#include "VertexData.hpp" + +namespace vkcv { + + /** + * @brief Enum class to specify the format of vertex in geometry. + */ + enum class GeometryVertexType { + POSITION_FLOAT3, + UNDEFINED + }; + + /** + * @brief Class to store the details of geometry data for acceleration structure building + */ + class GeometryData { + private: + VertexBufferBinding m_vertexBinding; + uint32_t m_vertexStride; + GeometryVertexType m_vertexType; + BufferHandle m_indices; + IndexBitCount m_indexBitCount; + size_t m_count; + + public: + /** + * @brief Default constructor of invalid geometry data. + */ + GeometryData(); + + /** + * @brief Constructor of geometry data by providing an vertex buffer binding, + * the used stride for vertex elements and its geometry vertex type. + * + * @param[in] binding Geometry buffer binding + * @param[in] stride Vertex element stride + * @param[in] geometryVertexType Geometry vertex type + */ + explicit GeometryData(const VertexBufferBinding &binding, + uint32_t stride = sizeof(float) * 3, + GeometryVertexType geometryVertexType = + GeometryVertexType::POSITION_FLOAT3); + + GeometryData(const GeometryData &other) = default; + GeometryData(GeometryData &&other) noexcept = default; + + ~GeometryData() = default; + + GeometryData &operator=(const GeometryData &other) = default; + GeometryData &operator=(GeometryData &&other) noexcept = default; + + /** + * @brief Return whether the geometry is valid to use. + * + * @return True if the geometry data is valid, otherwise false. + */ + [[nodiscard]] bool isValid() const; + + /** + * @brief Return the used vertex buffer binding of the geometry data. + * + * @return Vertex buffer binding + */ + [[nodiscard]] const VertexBufferBinding &getVertexBufferBinding() const; + + /** + * @brief Return the stride of vertex elements of the geometry data. + * + * @return Vertex stride + */ + [[nodiscard]] uint32_t getVertexStride() const; + + /** + * @brief Return the geometry vertex type of the geometry data. + * + * @return Geometry vertex type + */ + [[nodiscard]] GeometryVertexType getGeometryVertexType() const; + + /** + * @brief Set the optional index buffer and its used index bit count. + * + * @param[in] indices Index buffer handle + * @param[in] indexBitCount Index bit count + */ + void setIndexBuffer(const BufferHandle &indices, + IndexBitCount indexBitCount = IndexBitCount::Bit16); + + /** + * @brief Return the handle from the used index buffer of the vertex + * data. + * + * @return Index buffer handle + */ + [[nodiscard]] const BufferHandle &getIndexBuffer() const; + + /** + * @brief Return the index bit count of the indices used in the + * vertex data. + * + * @return Index bit count + */ + [[nodiscard]] IndexBitCount getIndexBitCount() const; + + /** + * @brief Set the count of elements to use by the vertex data. + * + * @param count Count of vertex elements + */ + void setCount(size_t count); + + /** + * @brief Return the count of elements in use by the vertex data. + * + * @return Count of vertex elements + */ + [[nodiscard]] size_t getCount() const; + }; + +} // namespace vkcv diff --git a/modules/geometry/include/vkcv/geometry/Geometry.hpp b/modules/geometry/include/vkcv/geometry/Geometry.hpp index cf2b6eb5132e46883a81dc6d45eae18f51f48bea..ea006b009e45c3147b914890039f7a86bf39e519 100644 --- a/modules/geometry/include/vkcv/geometry/Geometry.hpp +++ b/modules/geometry/include/vkcv/geometry/Geometry.hpp @@ -111,6 +111,17 @@ namespace vkcv::geometry { [[nodiscard]] virtual VertexData generateVertexData(Core& core) const = 0; + /** + * Extracts a geometry data structure from its own + * generated vertex data, which can be used for + * building bottom level acceleration structures. + * + * @param[in, out] vertexData Vertex data with generated geometry + * @return Geometry data from generated vertex data + */ + [[nodiscard]] + virtual GeometryData extractGeometryData(const VertexData &vertexData) const; + }; /** @} */ diff --git a/modules/geometry/src/vkcv/geometry/Geometry.cpp b/modules/geometry/src/vkcv/geometry/Geometry.cpp index feaa84a04f2e180b08fd92977d6494ac997af6b2..ec0d56e06ccf9d5cf5d9dd92192f930715adc055 100644 --- a/modules/geometry/src/vkcv/geometry/Geometry.cpp +++ b/modules/geometry/src/vkcv/geometry/Geometry.cpp @@ -28,4 +28,17 @@ namespace vkcv::geometry { )); } + GeometryData Geometry::extractGeometryData(const vkcv::VertexData &vertexData) const { + GeometryData data ( + vertexData.getVertexBufferBindings()[0], + sizeof(glm::vec3), + GeometryVertexType::POSITION_FLOAT3 + ); + + data.setIndexBuffer(vertexData.getIndexBuffer(), vertexData.getIndexBitCount()); + data.setCount(vertexData.getCount()); + + return data; + } + } diff --git a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit index 95e3d6acba8dcb05d61c87c737a4aeb3a9fe6fce..03806c4f498f7dcd751078216628774a50fa82bd 100644 --- a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit +++ b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit @@ -11,8 +11,6 @@ layout(location = 0) rayPayloadInEXT Payload { vec3 worldNormal; } payload; -layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure - layout(binding = 2, set = 0, scalar) buffer rtxVertices { float vertices[]; diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp index 55bbcff533c59aa53b2df43c82f0bd9f24583aab..b18cb3455f98d294ef46a9d306c7bacedd19d7b8 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp @@ -23,14 +23,7 @@ namespace vkcv::rtx { // destroy every BLAS, its data containers and free used memory blocks for (size_t i=0; i < m_bottomLevelAccelerationStructures.size(); i++) { BottomLevelAccelerationStructure blas = m_bottomLevelAccelerationStructures[i]; - m_core->getContext().getDevice().destroyAccelerationStructureKHR(blas.vulkanHandle, nullptr, m_rtxDispatcher); - m_core->getContext().getDevice().destroy(blas.accelerationBuffer.vulkanHandle); - m_core->getContext().getDevice().destroy(blas.indexBuffer.vulkanHandle); - m_core->getContext().getDevice().destroy(blas.vertexBuffer.vulkanHandle); - - m_core->getContext().getDevice().freeMemory(blas.accelerationBuffer.deviceMemory); - m_core->getContext().getDevice().freeMemory(blas.indexBuffer.deviceMemory); - m_core->getContext().getDevice().freeMemory(blas.vertexBuffer.deviceMemory); + //m_core->getContext().getDevice().destroyAccelerationStructureKHR(blas.vulkanHandle, nullptr, m_rtxDispatcher); } // destroy the TLAS, its data containers and free used memory blocks @@ -163,43 +156,17 @@ namespace vkcv::rtx { const auto& originalVertexBuffer = vertexData.getVertexBufferBindings()[0].buffer; const auto& originalIndexBuffer = vertexData.getIndexBuffer(); - std::vector<float> vertices; - std::vector<uint16_t> indices; - - vertices.resize( - m_core->getBufferSize(originalVertexBuffer) / sizeof(float) - ); - - const float *raw_vertices = reinterpret_cast<float*>( - m_core->mapBuffer(originalVertexBuffer, 0, 0) - ); - - memcpy(vertices.data(), raw_vertices, vertices.size() * sizeof(float)); - m_core->unmapBuffer(originalVertexBuffer); - - indices.resize( - m_core->getBufferSize(originalIndexBuffer) / sizeof(uint16_t) - ); - - const uint16_t *raw_indices = reinterpret_cast<uint16_t*>( - m_core->mapBuffer(originalIndexBuffer, 0, 0) - ); - - memcpy(indices.data(), raw_indices, indices.size() * sizeof(uint16_t)); - m_core->unmapBuffer(originalIndexBuffer); - - auto vertexBuffer = makeBufferFromData(vertices); - auto indexBuffer = makeBufferFromData(indices); + const auto vbSize = m_core->getBufferSize(originalVertexBuffer); - vk::DeviceAddress vertexBufferAddress = getBufferDeviceAddress(vertexBuffer.vulkanHandle); - vk::DeviceAddress indexBufferAddress = getBufferDeviceAddress(indexBuffer.vulkanHandle); + vk::DeviceAddress vertexBufferAddress = m_core->getBufferDeviceAddress(originalVertexBuffer);//getBufferDeviceAddress(vertexBuffer.vulkanHandle); + vk::DeviceAddress indexBufferAddress = m_core->getBufferDeviceAddress(originalIndexBuffer);//getBufferDeviceAddress(indexBuffer.vulkanHandle); // triangle mesh data vk::AccelerationStructureGeometryTrianglesDataKHR asTriangles( vk::Format::eR32G32B32Sfloat, // vertex format vertexBufferAddress, // vertex buffer address (vk::DeviceOrHostAddressConstKHR) 3 * sizeof(float), // vertex stride (vk::DeviceSize) - uint32_t(vertices.size() / 3 - 1), // maxVertex (uint32_t) + uint32_t(vbSize / (3 * sizeof(float)) - 1), // maxVertex (uint32_t) vk::IndexType::eUint16, // indexType (vk::IndexType) --> INFO: UINT16 oder UINT32! indexBufferAddress, // indexData (vk::DeviceOrHostAddressConstKHR) {} // transformData (vk::DeviceOrHostAddressConstKHR) @@ -214,7 +181,7 @@ namespace vkcv::rtx { // Ranges for data lists vk::AccelerationStructureBuildRangeInfoKHR asRangeInfo( - uint32_t(indices.size() / 3), // the primitiveCount (uint32_t) + uint32_t(vertexData.getCount() / 3), // the primitiveCount (uint32_t) 0, // primitiveOffset (uint32_t) 0, // firstVertex (uint32_t) 0 // transformOffset (uint32_t) @@ -300,13 +267,24 @@ namespace vkcv::rtx { m_core->getContext().getDevice().freeMemory(scratchBuffer.deviceMemory, nullptr, m_rtxDispatcher); BottomLevelAccelerationStructure blas = { - vertexBuffer, - indexBuffer, - blasBuffer, + vertexData.getVertexBufferBindings()[0].buffer, + vertexData.getIndexBuffer(), + nullptr, blasKHR }; m_bottomLevelAccelerationStructures.push_back(blas); } + + void ASManager::add(const vkcv::GeometryData &geometryData, const vkcv::AccelerationStructureHandle &blas) { + BottomLevelAccelerationStructure blasEntry = { + geometryData.getVertexBufferBinding().buffer, + geometryData.getIndexBuffer(), + m_core->getVulkanBuffer(blas), + m_core->getVulkanAccelerationStructure(blas) + }; + + m_bottomLevelAccelerationStructures.push_back(blasEntry); + } void ASManager::buildTLAS() { // TODO: organize hierarchical structure of multiple BLAS diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp index 7124ce8914161154cd3047ad70d4f0e750d24506..825d5e651d34262e9b60a6345c95512a17132e31 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp +++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp @@ -32,9 +32,9 @@ namespace vkcv::rtx { * @brief Used as a container to handle bottom-level acceleration structure (BLAS) construction and destruction. */ struct BottomLevelAccelerationStructure { - RTXBuffer vertexBuffer; - RTXBuffer indexBuffer; - RTXBuffer accelerationBuffer; + vkcv::BufferHandle vertexBuffer; + vkcv::BufferHandle indexBuffer; + vk::Buffer accelerationBuffer; vk::AccelerationStructureKHR vulkanHandle; }; @@ -156,6 +156,8 @@ namespace vkcv::rtx { * @param[in] vertexData The vertex data. */ void buildBLAS(const vkcv::VertexData &vertexData); + + void add(const vkcv::GeometryData &geometryData, const vkcv::AccelerationStructureHandle &blas); /** * @brief Build a Top Level Acceleration Structure (TLAS) object from the created diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp index 2065d131569101716faf98f3662c4d9ba090a279..4fd33be9bc0b253766cba92e2d1498acac91290b 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp @@ -1,63 +1,30 @@ #include "RTX.hpp" namespace vkcv::rtx { - - RTXModule::RTXModule(Core* core, + + RTXModule::RTXModule(Core* core, ASManager* asManager, - const vkcv::VertexData &vertexData, std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles){ - m_core = core; - m_asManager = asManager; - // build acceleration structures BLAS then TLAS --> see ASManager - m_asManager->buildBLAS(vertexData); - m_asManager->buildTLAS(); - RTXDescriptors(descriptorSetHandles); - } - - - RTXModule::~RTXModule() - {} - - - void RTXModule::RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles) - { - //TLAS-Descriptor-Write + m_core = core; + m_asManager = asManager; + // build acceleration structures BLAS then TLAS --> see ASManager + m_asManager->buildTLAS(); + RTXDescriptors(descriptorSetHandles); + } + + + RTXModule::~RTXModule() + {} + + + void RTXModule::RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles) + { + //TLAS-Descriptor-Write { vkcv::DescriptorWrites writes; writes.writeAcceleration(1, { m_asManager->getTLAS().vulkanHandle }); m_core->writeDescriptorSet(descriptorSetHandles[0], writes); } - - //INDEX & VERTEX BUFFER - BottomLevelAccelerationStructure blas = m_asManager->getBLAS(0);//HARD CODED - - //VERTEX BUFFER - vk::DescriptorBufferInfo vertexInfo = {}; - vertexInfo.setBuffer(blas.vertexBuffer.vulkanHandle); - vertexInfo.setOffset(0); - vertexInfo.setRange(blas.vertexBuffer.deviceSize); //maybe check if size is correct - - vk::WriteDescriptorSet vertexWrite; - vertexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0])); - vertexWrite.setDstBinding(2); - vertexWrite.setDescriptorCount(1); - vertexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); - vertexWrite.setPBufferInfo(&vertexInfo); - m_core->getContext().getDevice().updateDescriptorSets(vertexWrite, nullptr); - - //INDEXBUFFER - vk::DescriptorBufferInfo indexInfo = {}; - indexInfo.setBuffer(blas.indexBuffer.vulkanHandle); - indexInfo.setOffset(0); - indexInfo.setRange(blas.indexBuffer.deviceSize); //maybe check if size is correct - - vk::WriteDescriptorSet indexWrite; - indexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0])); - indexWrite.setDstBinding(3); - indexWrite.setDescriptorCount(1); - indexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); - indexWrite.setPBufferInfo(&indexInfo); - m_core->getContext().getDevice().updateDescriptorSets(indexWrite, nullptr); - } + } } \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp index 3b731480670ca13a985e1dd07c82fee0f2cc7288..9a71bc170b881cad9a767c63f94e3a6388971aaf 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp @@ -36,7 +36,6 @@ namespace vkcv::rtx { */ RTXModule(Core* core, ASManager* asManager, - const vkcv::VertexData &vertexData, std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles); /** diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index 0992d457a294b48590280d06ad8c7321a73f2ee4..1c491097d5cc1db970653c18d18fe3d75ec38451 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -55,6 +55,7 @@ int main(int argc, const char** argv) { vkcv::geometry::Teapot teapot (glm::vec3(0.0f), 1.0f); vkcv::VertexData vertexData = teapot.generateVertexData(core); + vkcv::GeometryData geometryData = teapot.extractGeometryData(vertexData); vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); @@ -87,14 +88,24 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetHandle rtxShaderDescriptorSet = core.createDescriptorSet(rtxShaderDescriptorSetLayout); descriptorSetHandles.push_back(rtxShaderDescriptorSet); descriptorSetLayoutHandles.push_back(rtxShaderDescriptorSetLayout); + + vkcv::AccelerationStructureHandle blas = core.createAccelerationStructure({ geometryData }); + + asManager.add(geometryData, blas); // init RTXModule vkcv::rtx::RTXModule rtxModule ( &core, &asManager, - vertexData, descriptorSetHandles ); + + { + vkcv::DescriptorWrites writes; + writes.writeStorageBuffer(2, geometryData.getVertexBufferBinding().buffer); + writes.writeStorageBuffer(3, geometryData.getIndexBuffer()); + core.writeDescriptorSet(descriptorSetHandles[0], writes); + } struct RaytracingPushConstantData { glm::vec4 camera_position; // as origin for ray generation diff --git a/src/vkcv/AccelerationStructureManager.cpp b/src/vkcv/AccelerationStructureManager.cpp index 1cc6cf4659fbaf50e370e7206c88669d9ed2ef18..b0b213d48a052b53b0ee1fb939791760fd0a3e00 100644 --- a/src/vkcv/AccelerationStructureManager.cpp +++ b/src/vkcv/AccelerationStructureManager.cpp @@ -36,6 +36,10 @@ namespace vkcv { accelerationStructure.m_accelerationStructure = nullptr; } + + if (accelerationStructure.m_storageBuffer) { + accelerationStructure.m_storageBuffer = BufferHandle(); + } } const BufferManager &AccelerationStructureManager::getBufferManager() const { @@ -54,4 +58,227 @@ namespace vkcv { clear(); } + vk::AccelerationStructureKHR + AccelerationStructureManager::getVulkanAccelerationStructure( + const AccelerationStructureHandle &handle) const { + auto &accelerationStructure = (*this) [handle]; + return accelerationStructure.m_accelerationStructure; + } + + vk::Buffer AccelerationStructureManager::getVulkanBuffer( + const AccelerationStructureHandle &handle) const { + auto &accelerationStructure = (*this) [handle]; + return getBufferManager().getBuffer(accelerationStructure.m_storageBuffer); + } + + static vk::Format getVertexFormat(GeometryVertexType vertexType) { + switch (vertexType) { + case GeometryVertexType::POSITION_FLOAT3: + return vk::Format::eR32G32B32Sfloat; + case GeometryVertexType::UNDEFINED: + return vk::Format::eUndefined; + default: + vkcv_log(LogLevel::ERROR, "unknown Enum"); + return vk::Format::eUndefined; + } + } + + static vk::IndexType getIndexType(IndexBitCount indexByteCount) { + switch (indexByteCount) { + case IndexBitCount::Bit8: + return vk::IndexType::eUint8EXT; + case IndexBitCount::Bit16: + return vk::IndexType::eUint16; + case IndexBitCount::Bit32: + return vk::IndexType::eUint32; + default: + vkcv_log(LogLevel::ERROR, "unknown Enum"); + return vk::IndexType::eNoneKHR; + } + } + + AccelerationStructureHandle AccelerationStructureManager::createAccelerationStructure( + const std::vector<GeometryData> &geometryData) { + std::vector<vk::AccelerationStructureGeometryKHR> geometries; + std::vector<vk::AccelerationStructureBuildGeometryInfoKHR> geometryInfos; + std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>> rangeInfos; + + auto& bufferManager = getBufferManager(); + + vk::DeviceSize accelerationStructureSize = 0; + vk::DeviceSize scratchBufferSize = 0; + + const auto &dynamicDispatch = getCore().getContext().getDispatchLoaderDynamic(); + + geometries.reserve(geometryData.size()); + + for (const GeometryData &data : geometryData) { + const auto vertexBufferAddress = bufferManager.getBufferDeviceAddress( + data.getVertexBufferBinding().buffer + ) + data.getVertexBufferBinding().offset; + + const auto indexBufferAddress = bufferManager.getBufferDeviceAddress( + data.getIndexBuffer() + ); + + const auto vertexStride = data.getVertexStride(); + const auto vertexBufferSize = bufferManager.getBufferSize( + data.getVertexBufferBinding().buffer + ); + + const auto vertexCount = (vertexBufferSize / vertexStride); + + const vk::Format vertexFormat = getVertexFormat(data.getGeometryVertexType()); + + const vk::IndexType indexType = getIndexType(data.getIndexBitCount()); + + const vk::AccelerationStructureGeometryTrianglesDataKHR asTrianglesData ( + vertexFormat, + vertexBufferAddress, + vertexStride, + static_cast<uint32_t>(vertexCount - 1), + indexType, + indexBufferAddress, + {} + ); + + const vk::AccelerationStructureGeometryKHR asGeometry ( + vk::GeometryTypeKHR::eTriangles, + asTrianglesData, + vk::GeometryFlagBitsKHR::eOpaque + ); + + geometries.push_back(asGeometry); + } + + geometryInfos.reserve(geometries.size()); + rangeInfos.reserve(geometries.size()); + + for (size_t i = 0; i < geometries.size(); i++) { + const vk::AccelerationStructureBuildGeometryInfoKHR asBuildGeometryInfo( + vk::AccelerationStructureTypeKHR::eBottomLevel, + vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace, + vk::BuildAccelerationStructureModeKHR::eBuild, + {}, + {}, + 1, + &(geometries[i]) + ); + + geometryInfos.push_back(asBuildGeometryInfo); + + const vk::AccelerationStructureBuildRangeInfoKHR asBuildRangeInfo ( + static_cast<uint32_t>(geometryData[i].getCount() / 3), + 0, + 0, + 0 + ); + + rangeInfos.push_back({ asBuildRangeInfo }); + + vk::AccelerationStructureBuildSizesInfoKHR asBuildSizesInfo; + getCore().getContext().getDevice().getAccelerationStructureBuildSizesKHR( + vk::AccelerationStructureBuildTypeKHR::eDevice, + &(asBuildGeometryInfo), + &(asBuildRangeInfo.primitiveCount), + &(asBuildSizesInfo), + dynamicDispatch + ); + + accelerationStructureSize += asBuildSizesInfo.accelerationStructureSize; + scratchBufferSize = std::max(scratchBufferSize, asBuildSizesInfo.buildScratchSize); + } + + const BufferHandle &asStorageBuffer = bufferManager.createBuffer( + typeGuard<uint8_t>(), + BufferType::ACCELERATION_STRUCTURE_STORAGE, + BufferMemoryType::DEVICE_LOCAL, + accelerationStructureSize, + false + ); + + vk::PhysicalDeviceAccelerationStructurePropertiesKHR accelerationStructureProperties; + + vk::PhysicalDeviceProperties2 physicalProperties2; + physicalProperties2.pNext = &accelerationStructureProperties; + + getCore().getContext().getPhysicalDevice().getProperties2(&physicalProperties2); + + const auto minScratchAlignment = ( + accelerationStructureProperties.minAccelerationStructureScratchOffsetAlignment + ); + + const BufferHandle &asScratchBuffer = bufferManager.createBuffer( + vkcv::TypeGuard(minScratchAlignment), + BufferType::STORAGE, + BufferMemoryType::DEVICE_LOCAL, + (scratchBufferSize + minScratchAlignment - 1) / minScratchAlignment, + false + ); + + if ((!asStorageBuffer) || (!asScratchBuffer)) { + return {}; + } + + const vk::AccelerationStructureCreateInfoKHR asCreateInfo ( + vk::AccelerationStructureCreateFlagsKHR(), + bufferManager.getBuffer(asStorageBuffer), + 0, + accelerationStructureSize, + vk::AccelerationStructureTypeKHR::eBottomLevel + ); + + vk::AccelerationStructureKHR accelerationStructure; + const vk::Result result = getCore().getContext().getDevice().createAccelerationStructureKHR( + &asCreateInfo, + nullptr, + &accelerationStructure, + dynamicDispatch + ); + + if (result != vk::Result::eSuccess) { + return {}; + } + + vk::DeviceAddress scratchBufferAddress = bufferManager.getBufferDeviceAddress( + asScratchBuffer + ); + + if (scratchBufferAddress % minScratchAlignment != 0) { + scratchBufferAddress += ( + minScratchAlignment - (scratchBufferAddress % minScratchAlignment) + ); + } + + for (auto& geometryInfo : geometryInfos) { + geometryInfo.setDstAccelerationStructure(accelerationStructure); + geometryInfo.setScratchData(scratchBufferAddress); + } + + std::vector<vk::AccelerationStructureBuildRangeInfoKHR*> pRangeInfos; + pRangeInfos.resize(rangeInfos.size()); + + for (size_t i = 0; i < rangeInfos.size(); i++) { + pRangeInfos[i] = rangeInfos[i].data(); + } + + auto cmdStream = getCore().createCommandStream(vkcv::QueueType::Compute); + + getCore().recordCommandsToStream( + cmdStream, + [&geometryInfos, &pRangeInfos, &dynamicDispatch]( + const vk::CommandBuffer &cmdBuffer) { + cmdBuffer.buildAccelerationStructuresKHR( + static_cast<uint32_t>(geometryInfos.size()), + geometryInfos.data(), + pRangeInfos.data(), + dynamicDispatch + ); + }, nullptr); + + getCore().submitCommandStream(cmdStream, false); + + return add({ accelerationStructure, asStorageBuffer }); + } + } diff --git a/src/vkcv/AccelerationStructureManager.hpp b/src/vkcv/AccelerationStructureManager.hpp index fff2b12521c6100c6f14796e5fba128039b2c93b..155b576761c4a47e6480404fe5b08fd55bf229d0 100644 --- a/src/vkcv/AccelerationStructureManager.hpp +++ b/src/vkcv/AccelerationStructureManager.hpp @@ -12,12 +12,15 @@ #include <vulkan/vulkan.hpp> #include "BufferManager.hpp" + #include "vkcv/Handles.hpp" +#include "vkcv/GeometryData.hpp" namespace vkcv { struct AccelerationStructureEntry { vk::AccelerationStructureKHR m_accelerationStructure; + vkcv::BufferHandle m_storageBuffer; }; /** @@ -56,6 +59,14 @@ namespace vkcv { ~AccelerationStructureManager() noexcept override; + [[nodiscard]] vk::AccelerationStructureKHR getVulkanAccelerationStructure( + const AccelerationStructureHandle &handle) const; + + [[nodiscard]] vk::Buffer getVulkanBuffer(const AccelerationStructureHandle &handle) const; + + [[nodiscard]] AccelerationStructureHandle createAccelerationStructure( + const std::vector<GeometryData> &geometryData); + }; } \ No newline at end of file diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index a6c15b7b3f9ea15bb8a1f969d02b081d64ecff3f..b77325884d5ab636930c3fe5e862bf16ccce47ca 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -56,6 +56,15 @@ namespace vkcv { } else { m_resizableBar = false; } + + m_shaderDeviceAddress = getCore().getContext().getFeatureManager().checkFeatures< + vk::PhysicalDeviceBufferDeviceAddressFeatures + >( + vk::StructureType::ePhysicalDeviceBufferDeviceAddressFeatures, + [](const vk::PhysicalDeviceBufferDeviceAddressFeatures &features) { + return features.bufferDeviceAddress; + } + ); m_stagingBuffer = createBuffer( TypeGuard(1), @@ -96,6 +105,7 @@ namespace vkcv { BufferManager::BufferManager() noexcept : HandleManager<BufferEntry, BufferHandle>(), m_resizableBar(false), + m_shaderDeviceAddress(false), m_stagingBuffer(BufferHandle()) {} BufferManager::~BufferManager() noexcept { @@ -110,7 +120,9 @@ namespace vkcv { switch (type) { case BufferType::VERTEX: - usageFlags = vk::BufferUsageFlagBits::eVertexBuffer; + usageFlags = vk::BufferUsageFlagBits::eVertexBuffer + | vk::BufferUsageFlagBits::eStorageBuffer + | vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR; break; case BufferType::UNIFORM: usageFlags = vk::BufferUsageFlagBits::eUniformBuffer; @@ -123,23 +135,22 @@ namespace vkcv { | vk::BufferUsageFlagBits::eTransferDst; break; case BufferType::INDEX: - usageFlags = vk::BufferUsageFlagBits::eIndexBuffer; + usageFlags = vk::BufferUsageFlagBits::eIndexBuffer + | vk::BufferUsageFlagBits::eStorageBuffer + | vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR; break; case BufferType::INDIRECT: usageFlags = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer; break; case BufferType::SHADER_BINDING: - usageFlags = vk::BufferUsageFlagBits::eShaderBindingTableKHR - | vk::BufferUsageFlagBits::eShaderDeviceAddress; + usageFlags = vk::BufferUsageFlagBits::eShaderBindingTableKHR; break; case BufferType::ACCELERATION_STRUCTURE_INPUT: - usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR - | vk::BufferUsageFlagBits::eShaderDeviceAddress; + usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR; break; case BufferType::ACCELERATION_STRUCTURE_STORAGE: usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR - | vk::BufferUsageFlagBits::eShaderDeviceAddress | vk::BufferUsageFlagBits::eStorageBuffer; break; default: @@ -154,6 +165,10 @@ namespace vkcv { if (readable) { usageFlags |= vk::BufferUsageFlagBits::eTransferSrc; } + + if (m_shaderDeviceAddress) { + usageFlags |= vk::BufferUsageFlagBits::eShaderDeviceAddress; + } const vma::Allocator &allocator = getCore().getContext().getAllocator(); diff --git a/src/vkcv/BufferManager.hpp b/src/vkcv/BufferManager.hpp index 620e062bb7ada4ede0047503456c250e243ee0ad..818c907c1981cab94a4ac932e18f5517c822f540 100644 --- a/src/vkcv/BufferManager.hpp +++ b/src/vkcv/BufferManager.hpp @@ -45,6 +45,8 @@ namespace vkcv { std::allocator<char> m_allocator; bool m_resizableBar; + bool m_shaderDeviceAddress; + BufferHandle m_stagingBuffer; bool init(Core &core) override; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index b063e0743b8ddc362086ce97d51b8db49f5d4ecc..db8cdf53b1a8929e7650e33687cbaf6d601d07b7 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -358,7 +358,7 @@ namespace vkcv { cmdBuffer.setScissor(0, 1, &dynamicScissor); } - vk::IndexType getIndexType(IndexBitCount indexByteCount) { + static vk::IndexType getIndexType(IndexBitCount indexByteCount) { switch (indexByteCount) { case IndexBitCount::Bit8: return vk::IndexType::eUint8EXT; @@ -1350,5 +1350,17 @@ namespace vkcv { vk::DeviceMemory Core::getVulkanDeviceMemory(const ImageHandle &handle) const { return m_ImageManager->getVulkanDeviceMemory(handle); } - + + AccelerationStructureHandle Core::createAccelerationStructure(const std::vector<GeometryData> &geometryData) { + return m_AccelerationStructureManager->createAccelerationStructure(geometryData); + } + + vk::AccelerationStructureKHR Core::getVulkanAccelerationStructure(const AccelerationStructureHandle &handle) const { + return m_AccelerationStructureManager->getVulkanAccelerationStructure(handle); + } + + vk::Buffer Core::getVulkanBuffer(const vkcv::AccelerationStructureHandle &handle) const { + return m_AccelerationStructureManager->getVulkanBuffer(handle); + } + } // namespace vkcv diff --git a/src/vkcv/GeometryData.cpp b/src/vkcv/GeometryData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a5cc5771817de4ae9624a3b80c34f5869480e60 --- /dev/null +++ b/src/vkcv/GeometryData.cpp @@ -0,0 +1,61 @@ + +#include "vkcv/GeometryData.hpp" + +namespace vkcv { + + GeometryData::GeometryData() : + m_vertexBinding({}), + m_vertexStride(0), + m_vertexType(GeometryVertexType::UNDEFINED), + m_indices(), + m_indexBitCount(IndexBitCount::Bit16), + m_count(0) {} + + GeometryData::GeometryData(const VertexBufferBinding &binding, + uint32_t stride, + GeometryVertexType geometryVertexType) : + m_vertexBinding(binding), + m_vertexStride(stride), + m_vertexType(geometryVertexType), + m_indices(), + m_indexBitCount(IndexBitCount::Bit16), + m_count(0) {} + + bool GeometryData::isValid() const { + return m_vertexType == GeometryVertexType::UNDEFINED; + } + + const VertexBufferBinding &GeometryData::getVertexBufferBinding() const { + return m_vertexBinding; + } + + uint32_t GeometryData::getVertexStride() const { + return m_vertexStride; + } + + GeometryVertexType GeometryData::getGeometryVertexType() const { + return m_vertexType; + } + + void GeometryData::setIndexBuffer(const BufferHandle &indices, IndexBitCount indexBitCount) { + m_indices = indices; + m_indexBitCount = indexBitCount; + } + + const BufferHandle &GeometryData::getIndexBuffer() const { + return m_indices; + } + + IndexBitCount GeometryData::getIndexBitCount() const { + return m_indexBitCount; + } + + void GeometryData::setCount(size_t count) { + m_count = count; + } + + size_t GeometryData::getCount() const { + return m_count; + } + +} diff --git a/src/vkcv/RayTracingPipelineManager.cpp b/src/vkcv/RayTracingPipelineManager.cpp index f33fd4543766c07a341c568582341864483bafd8..70f05b98f719112befafd103ab3b24549a398e79 100644 --- a/src/vkcv/RayTracingPipelineManager.cpp +++ b/src/vkcv/RayTracingPipelineManager.cpp @@ -391,8 +391,10 @@ namespace vkcv { return {}; } + const auto baseAlignment = rayTracingPipelineProperties.shaderGroupBaseAlignment; + const size_t tableSizeAlignment = std::max( - rayTracingPipelineProperties.shaderGroupBaseAlignment, + baseAlignment, rayTracingPipelineProperties.shaderGroupHandleSize ); @@ -400,14 +402,27 @@ namespace vkcv { tableSizeAlignment * shaderGroups.size() ); - const BufferHandle &shaderBindingTable = getCore().createBuffer( + const BufferHandle &shaderBindingTable = bufferManager.createBuffer( + TypeGuard(baseAlignment), BufferType::SHADER_BINDING, - shaderBindingTableSize + BufferMemoryType::DEVICE_LOCAL, + (shaderBindingTableSize + baseAlignment - 1) / baseAlignment, + false + ); + + vk::DeviceAddress bufferBaseAddress = bufferManager.getBufferDeviceAddress( + shaderBindingTable ); + size_t bufferBaseOffset = 0; + if (bufferBaseAddress % baseAlignment != 0) { + bufferBaseOffset = (baseAlignment - (bufferBaseAddress % baseAlignment)); + bufferBaseAddress += bufferBaseOffset; + } + void* mappedBindingTable = bufferManager.mapBuffer( shaderBindingTable, - 0, + bufferBaseOffset, shaderBindingTableSize ); @@ -429,10 +444,6 @@ namespace vkcv { bufferManager.unmapBuffer(shaderBindingTable); - const vk::DeviceAddress bufferBaseAddress = bufferManager.getBufferDeviceAddress( - shaderBindingTable - ); - vk::StridedDeviceAddressRegionKHR rayGenAddress {}; vk::StridedDeviceAddressRegionKHR rayMissAddress {}; vk::StridedDeviceAddressRegionKHR rayHitAddress {};