Skip to content
Snippets Groups Projects
Commit d4730c67 authored by Vanessa Karolek's avatar Vanessa Karolek
Browse files

[#92] clean up memory allocation, add useful structs for convenience, resolve errors

parent 6103cdcd
No related branches found
No related tags found
1 merge request!75Resolve "RTX-Module"
Pipeline #27059 passed
...@@ -4,35 +4,83 @@ ...@@ -4,35 +4,83 @@
namespace vkcv::rtx { namespace vkcv::rtx {
enum class RTXBufferType {
CPU,
GPU,
ACCELERATION
};
struct RTXBuffer {
RTXBufferType bufferType;
void* data;
vk::DeviceSize deviceSize;
vk::DeviceMemory deviceMemory;
vk::BufferUsageFlags bufferUsageFlagBits;
vk::MemoryPropertyFlags memoryPropertyFlagBits;
vk::Buffer vulkanHandle;
};
struct AccelerationStructure {
RTXBuffer vertexBuffer;
RTXBuffer indexBuffer;
RTXBuffer accelerationBuffer;
vk::AccelerationStructureKHR vulkanHandle;
};
class ASManager { class ASManager {
private: private:
Core* m_core; Core* m_core;
std::vector<AccelerationStructure> m_accelerationStructures;
vk::DispatchLoaderDynamic m_rtxDispatcher;
/**
* @brief Returns a #RTXBuffer object holding data of type uint16_t from given @p data of type uint8_t.
* @param data The input data of type uint8_t.
* @return A #RTXBuffer object holding @p data.
*/
RTXBuffer makeBufferFromData(std::vector<uint8_t> &data);
/**
* @brief A helper function used by #ASManager::makeBufferFromData. Creates a fully initialized #RTXBuffer object
* from partially specified @p buffer. All missing data of @p buffer will be completed by this function.
* @param buffer The partially specified #RTXBuffer holding that part of information which is required for
* successfully creating a vk::Buffer object.
*/
void createBuffer(RTXBuffer &buffer);
/**
* @brief Copies @p cpuBuffer data into a @p gpuBuffer. Typical use case is a staging buffer (namely,
* @p cpuBuffer) used to fill a @p gpuBuffer with vk::MemoryPropertyFlagBits::eDeviceLocal flag set.
* @param cpuBuffer
* @param gpuBuffer
*/
void copyFromCPUToGPU(RTXBuffer &cpuBuffer, RTXBuffer &gpuBuffer);
public: public:
/** /**
* @brief TODO * @brief Constructor of #ASManager .
* @param core
*/ */
ASManager(vkcv::Core *core); ASManager(vkcv::Core *core);
/** /**
* @brief TODO * @brief Default destructor of #ASManager.
* TODO: kill AS, kill buffers, free memory of buffers
*/ */
~ASManager() {}; ~ASManager();
/** /**
* @brief Build a Bottom Level Acceleration Structure object from given @p vertices and @p indices. * @brief Build a Bottom Level Acceleration Structure (BLAS) object from given @p vertices and @p indices.
* @param[in] vertices The vertex data of type uint8_t. * @param[in] vertices The vertex data of type uint8_t.
* @param[in] indices The index data of type uint8_t. * @param[in] indices The index data of type uint8_t.
*/ */
void buildBLAS(std::vector<uint8_t> &vertices, std::vector<uint8_t> &indices); void buildBLAS(std::vector<uint8_t> &vertices, std::vector<uint8_t> &indices);
/** /**
* @brief TODO * @brief Build a Top Level Acceleration Structure (TLAS) object from the created
* @param data * #ASManager::m_accelerationStructures objects.
* @return
*/ */
vk::Buffer makeBuffer(std::vector<uint8_t> &data); void buildTLAS();
}; };
} }
\ No newline at end of file
...@@ -4,32 +4,48 @@ namespace vkcv::rtx { ...@@ -4,32 +4,48 @@ namespace vkcv::rtx {
ASManager::ASManager(vkcv::Core *core) : ASManager::ASManager(vkcv::Core *core) :
m_core(core) { m_core(core) {
// INFO: It seems that we need a dynamic dispatch loader because Vulkan is an ASs ...
m_rtxDispatcher = vk::DispatchLoaderDynamic( (PFN_vkGetInstanceProcAddr) m_core->getContext().getInstance().getProcAddr("vkGetInstanceProcAddr") );
m_rtxDispatcher.init(m_core->getContext().getInstance());
// SUGGESTION: recursive call of buildBLAS etc. // SUGGESTION: recursive call of buildBLAS etc.
}
ASManager::~ASManager() noexcept {
// destroy every acceleration structure, its data containers and free used memory blocks
for (size_t i=0; i < m_accelerationStructures.size(); i++) {
AccelerationStructure as = m_accelerationStructures[i];
m_core->getContext().getDevice().destroy(as.vulkanHandle, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().destroy(as.accelerationBuffer.vulkanHandle, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().destroy(as.indexBuffer.vulkanHandle, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().destroy(as.vertexBuffer.vulkanHandle, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().freeMemory(as.accelerationBuffer.deviceMemory, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().freeMemory(as.indexBuffer.deviceMemory, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().freeMemory(as.vertexBuffer.deviceMemory, nullptr, m_rtxDispatcher);
}
}
void ASManager::buildTLAS() {
// TODO
} }
void ASManager::buildBLAS(std::vector<uint8_t> &vertices, std::vector<uint8_t> &indices) { void ASManager::buildBLAS(std::vector<uint8_t> &vertices, std::vector<uint8_t> &indices) {
uint32_t vertexCount = vertices.size(); uint32_t vertexCount = vertices.size();
uint32_t indexCount = indices.size(); uint32_t indexCount = indices.size();
vk::Buffer vertexBuffer = makeBuffer(vertices); RTXBuffer vertexBuffer = makeBufferFromData(vertices);
vk::Buffer indexBuffer = makeBuffer(indices); RTXBuffer indexBuffer = makeBufferFromData(indices);
// INFO: It seems that we need a dynamic dispatch loader because Vulkan is an ASs ...
vk::DispatchLoaderDynamic dld( (PFN_vkGetInstanceProcAddr) m_core->getContext().getInstance().getProcAddr("vkGetInstanceProcAddr") );
dld.init(m_core->getContext().getInstance());
vk::BufferDeviceAddressInfo vertexBufferDeviceAddressInfo(vertexBuffer); vk::BufferDeviceAddressInfo vertexBufferDeviceAddressInfo(vertexBuffer.vulkanHandle);
vk::DeviceAddress vertexBufferAddress = m_core->getContext().getDevice().getBufferAddressKHR(vertexBufferDeviceAddressInfo, dld); vk::DeviceAddress vertexBufferAddress = m_core->getContext().getDevice().getBufferAddressKHR(vertexBufferDeviceAddressInfo, m_rtxDispatcher);
vk::DeviceOrHostAddressConstKHR vertexDeviceOrHostAddressConst(vertexBufferAddress); vk::DeviceOrHostAddressConstKHR vertexDeviceOrHostAddressConst(vertexBufferAddress);
vk::BufferDeviceAddressInfo indexBufferDeviceAddressInfo(indexBuffer); vk::BufferDeviceAddressInfo indexBufferDeviceAddressInfo(indexBuffer.vulkanHandle);
vk::DeviceAddress indexBufferAddress = m_core->getContext().getDevice().getBufferAddressKHR(indexBufferDeviceAddressInfo, dld); vk::DeviceAddress indexBufferAddress = m_core->getContext().getDevice().getBufferAddressKHR(indexBufferDeviceAddressInfo, m_rtxDispatcher);
vk::DeviceOrHostAddressConstKHR indexDeviceOrHostAddressConst(indexBufferAddress); vk::DeviceOrHostAddressConstKHR indexDeviceOrHostAddressConst(indexBufferAddress);
// Specify triangle mesh data // TODO: Check if valid entries ... // Specify triangle mesh data
vk::AccelerationStructureGeometryTrianglesDataKHR asTriangles( vk::AccelerationStructureGeometryTrianglesDataKHR asTriangles(
vk::Format::eR32G32B32Sfloat, // vertex format vk::Format::eR32G32B32Sfloat, // vertex format
vertexDeviceOrHostAddressConst, // vertex buffer address (vk::DeviceOrHostAddressConstKHR) vertexDeviceOrHostAddressConst, // vertex buffer address (vk::DeviceOrHostAddressConstKHR)
...@@ -71,39 +87,53 @@ namespace vkcv::rtx { ...@@ -71,39 +87,53 @@ namespace vkcv::rtx {
&asBuildInfo, // pointer to build info &asBuildInfo, // pointer to build info
&asRangeInfo.primitiveCount, // array of number of primitives per geometry &asRangeInfo.primitiveCount, // array of number of primitives per geometry
&asBuildSizesInfo, // output pointer to store sizes &asBuildSizesInfo, // output pointer to store sizes
dld m_rtxDispatcher
); );
// Allocate the AS TODO: which type do we need for the buffer?? !!! // create buffer for acceleration structure
Buffer<vk::AccelerationStructureKHR> asBuffer = m_core->createBuffer<vk::AccelerationStructureKHR>(BufferType::RT_ACCELERATION_VERTEX, asBuildSizesInfo.accelerationStructureSize, BufferMemoryType::DEVICE_LOCAL); RTXBuffer accelerationBuffer;
// core->createBuffer<>() accelerationBuffer.bufferType = RTXBufferType::ACCELERATION;
accelerationBuffer.deviceSize = asBuildSizesInfo.accelerationStructureSize;
accelerationBuffer.data = nullptr;
accelerationBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR
| vk::BufferUsageFlagBits::eShaderDeviceAddress
| vk::BufferUsageFlagBits::eStorageBuffer;
accelerationBuffer.memoryPropertyFlagBits = {};
createBuffer(accelerationBuffer); // TODO: is this on GPU?
// Create an empty AS object // Create an empty AS object
vk::AccelerationStructureCreateInfoKHR asCreateInfo( vk::AccelerationStructureCreateInfoKHR asCreateInfo(
{}, // creation flags {}, // creation flags
asBuffer.getVulkanHandle(), // allocated AS buffer. accelerationBuffer.vulkanHandle, // allocated AS buffer.
0, 0,
asBuildSizesInfo.accelerationStructureSize, // size of the AS asBuildSizesInfo.accelerationStructureSize, // size of the AS
asBuildInfo.type // type of the AS asBuildInfo.type // type of the AS
); );
// Create the intended AS object // Create the intended AS object
vk::AccelerationStructureKHR blas; vk::AccelerationStructureKHR blasKHR;
vk::Result res = m_core->getContext().getDevice().createAccelerationStructureKHR( vk::Result res = m_core->getContext().getDevice().createAccelerationStructureKHR(
&asCreateInfo, // AS create info &asCreateInfo, // AS create info
nullptr, // allocator callbacks nullptr, // allocator callbacks
&blas, // the AS &blasKHR, // the AS
dld m_rtxDispatcher
); );
if(res != vk::Result::eSuccess) { if(res != vk::Result::eSuccess) {
vkcv_log(vkcv::LogLevel::ERROR, "The Bottom Level Acceleration Structure could not be builded!"); vkcv_log(vkcv::LogLevel::ERROR, "The Bottom Level Acceleration Structure could not be builded!");
} }
asBuildInfo.setDstAccelerationStructure(blas); asBuildInfo.setDstAccelerationStructure(blasKHR);
// TODO: destroy accelerationstructure when closing app AccelerationStructure blas = {
vertexBuffer,
indexBuffer,
accelerationBuffer,
blasKHR
};
m_accelerationStructures.push_back(blas);
} }
vk::Buffer ASManager::makeBuffer(std::vector<uint8_t> &data) { RTXBuffer ASManager::makeBufferFromData(std::vector<uint8_t> &data) {
// convert uint8_t data into unit16_t // convert uint8_t data into unit16_t
std::vector<uint16_t> data_converted; std::vector<uint16_t> data_converted;
for (size_t i=0; i<data.size(); i++) { for (size_t i=0; i<data.size(); i++) {
...@@ -111,29 +141,54 @@ namespace vkcv::rtx { ...@@ -111,29 +141,54 @@ namespace vkcv::rtx {
} }
// now create a vk::Buffer of type uint16_t for the data // now create a vk::Buffer of type uint16_t for the data
vk::Device device = m_core->getContext().getDevice();
// first: Staging Buffer creation // first: Staging Buffer creation
vk::DeviceSize deviceSize = sizeof(data_converted[0]) * data_converted.size(); RTXBuffer cpuBuffer;
vk::BufferUsageFlags bufferUsageFlagBits = vk::BufferUsageFlagBits::eTransferSrc; cpuBuffer.bufferType = RTXBufferType::CPU;
cpuBuffer.deviceSize = sizeof(data_converted[0]) * data_converted.size();
cpuBuffer.data = data.data();
cpuBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eTransferSrc;
cpuBuffer.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
createBuffer(cpuBuffer);
// second: create AS Buffer
RTXBuffer gpuBuffer;
gpuBuffer.bufferType = RTXBufferType::GPU;
gpuBuffer.deviceSize = sizeof(data_converted[0]) * data_converted.size();
gpuBuffer.data = data.data();
gpuBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR
| vk::BufferUsageFlagBits::eTransferDst
| vk::BufferUsageFlagBits::eStorageBuffer
| vk::BufferUsageFlagBits::eShaderDeviceAddressKHR;
gpuBuffer.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eDeviceLocal;
createBuffer(gpuBuffer);
// copy from CPU to GPU
copyFromCPUToGPU(cpuBuffer, gpuBuffer);
return gpuBuffer;
}
void ASManager::createBuffer(RTXBuffer &buffer) {
vk::BufferCreateInfo bufferCreateInfo( vk::BufferCreateInfo bufferCreateInfo(
vk::BufferCreateFlags(), // vk::BufferCreateFlags vk::BufferCreateFlags(), // vk::BufferCreateFlags
deviceSize, // vk::DeviceSize buffer.deviceSize, // vk::DeviceSize
bufferUsageFlagBits, // vk::BufferUsageFlags buffer.bufferUsageFlagBits, // vk::BufferUsageFlags
vk::SharingMode::eExclusive, // vk::SharingMode vk::SharingMode::eExclusive, // vk::SharingMode
{}, // uint32_t queueFamilyIndexCount {}, // uint32_t queueFamilyIndexCount
{} // uint32_t* queueFamilyIndices {} // uint32_t* queueFamilyIndices
); );
vk::Buffer stagingBuffer = device.createBuffer(bufferCreateInfo, nullptr); buffer.vulkanHandle = m_core->getContext().getDevice().createBuffer(bufferCreateInfo);
vk::MemoryRequirements memoryRequirements = device.getBufferMemoryRequirements(stagingBuffer); vk::MemoryRequirements memoryRequirements = m_core->getContext().getDevice().getBufferMemoryRequirements(buffer.vulkanHandle);
vk::PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties = m_core->getContext().getPhysicalDevice().getMemoryProperties(); vk::PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties = m_core->getContext().getPhysicalDevice().getMemoryProperties();
vk::MemoryPropertyFlags memoryPropertyFlags = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
uint32_t memoryTypeIndex = -1; uint32_t memoryTypeIndex = -1;
for (int x = 0; x < physicalDeviceMemoryProperties.memoryTypeCount; x++) { for (int x = 0; x < physicalDeviceMemoryProperties.memoryTypeCount; x++) {
if ((memoryRequirements.memoryTypeBits & (1 << x)) && (physicalDeviceMemoryProperties.memoryTypes[x].propertyFlags & memoryPropertyFlags) == memoryPropertyFlags) { if ((memoryRequirements.memoryTypeBits & (1 << x)) && (physicalDeviceMemoryProperties.memoryTypes[x].propertyFlags & buffer.memoryPropertyFlagBits) == buffer.memoryPropertyFlagBits) {
memoryTypeIndex = x; memoryTypeIndex = x;
break; break;
} }
...@@ -142,69 +197,31 @@ namespace vkcv::rtx { ...@@ -142,69 +197,31 @@ namespace vkcv::rtx {
vk::MemoryAllocateInfo memoryAllocateInfo( vk::MemoryAllocateInfo memoryAllocateInfo(
memoryRequirements.size, // size of allocation in bytes memoryRequirements.size, // size of allocation in bytes
memoryTypeIndex // index identifying a memory type from the memoryTypes array of the vk::PhysicalDeviceMemoryProperties structure. memoryTypeIndex // index identifying a memory type from the memoryTypes array of the vk::PhysicalDeviceMemoryProperties structure.
); );
vk::MemoryAllocateFlagsInfo allocateFlagsInfo( vk::MemoryAllocateFlagsInfo allocateFlagsInfo(
vk::MemoryAllocateFlagBitsKHR::eDeviceAddress // vk::MemoryAllocateFlags vk::MemoryAllocateFlagBitsKHR::eDeviceAddress // vk::MemoryAllocateFlags
); );
memoryAllocateInfo.setPNext(&allocateFlagsInfo); // extend memory allocate info with allocate flag info memoryAllocateInfo.setPNext(&allocateFlagsInfo); // extend memory allocate info with allocate flag info
vk::DeviceMemory deviceMemory = device.allocateMemory(memoryAllocateInfo); buffer.deviceMemory = m_core->getContext().getDevice().allocateMemory(memoryAllocateInfo);
uint32_t memoryOffset = 0; uint32_t memoryOffset = 0;
device.bindBufferMemory(stagingBuffer, deviceMemory, memoryOffset); m_core->getContext().getDevice().bindBufferMemory(buffer.vulkanHandle, buffer.deviceMemory, memoryOffset);
// fill staging buffer // only fill data in case of CPU buffer TODO: what about acceleration structure buffer?
void* mapped = device.mapMemory(deviceMemory, memoryOffset, deviceSize); if (buffer.bufferType == RTXBufferType::CPU) {
std::memcpy(mapped, data_converted.data(), deviceSize); void* mapped = m_core->getContext().getDevice().mapMemory(buffer.deviceMemory, memoryOffset, buffer.deviceSize);
device.unmapMemory(deviceMemory); std::memcpy(mapped, buffer.data, buffer.deviceSize);
m_core->getContext().getDevice().unmapMemory(buffer.deviceMemory);
// second: GPU Buffer creation
vk::BufferUsageFlags bufferUsageFlagBits2 = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR
| vk::BufferUsageFlagBits::eTransferDst
| vk::BufferUsageFlagBits::eStorageBuffer
| vk::BufferUsageFlagBits::eShaderDeviceAddressKHR;
vk::BufferCreateInfo bufferCreateInfo2(
vk::BufferCreateFlags(), // vk::BufferCreateFlags
deviceSize, // vk::DeviceSize
bufferUsageFlagBits2, // vk::BufferUsageFlags
vk::SharingMode::eExclusive, // vk::SharingMode
{}, // uint32_t queueFamilyIndexCount
{} // uint32_t* queueFamilyIndices
);
vk::Buffer dataBuffer = device.createBuffer(bufferCreateInfo2, nullptr);
vk::MemoryRequirements memoryRequirements2 = device.getBufferMemoryRequirements(dataBuffer);
vk::PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties2 = m_core->getContext().getPhysicalDevice().getMemoryProperties();
vk::MemoryPropertyFlags memoryPropertyFlags2 = vk::MemoryPropertyFlagBits::eDeviceLocal;
uint32_t memoryTypeIndex2 = -1;
for (int x = 0; x < physicalDeviceMemoryProperties.memoryTypeCount; x++) {
if ((memoryRequirements2.memoryTypeBits & (1 << x)) && (physicalDeviceMemoryProperties2.memoryTypes[x].propertyFlags & memoryPropertyFlags2) == memoryPropertyFlags2) {
memoryTypeIndex2 = x;
break;
}
} }
}
vk::MemoryAllocateInfo memoryAllocateInfo2( void ASManager::copyFromCPUToGPU(RTXBuffer &cpuBuffer, RTXBuffer &gpuBuffer) {
memoryRequirements2.size, // size of allocation in bytes
memoryTypeIndex2 // index identifying a memory type from the memoryTypes array of the vk::PhysicalDeviceMemoryProperties structure.
);
vk::MemoryAllocateFlagsInfo allocateFlagsInfo2(
vk::MemoryAllocateFlagBitsKHR::eDeviceAddress // vk::MemoryAllocateFlags
);
memoryAllocateInfo2.setPNext(&allocateFlagsInfo2); // extend memory allocate info with allocate flag info
vk::DeviceMemory deviceMemory2 = device.allocateMemory(memoryAllocateInfo2);
uint32_t memoryOffset2 = 0;
device.bindBufferMemory(dataBuffer, deviceMemory2, memoryOffset2);
// copy data from stagingBuffer to dataBuffer
vk::CommandPool commandPool; vk::CommandPool commandPool;
vk::CommandPoolCreateInfo commandPoolCreateInfo; vk::CommandPoolCreateInfo commandPoolCreateInfo;
commandPoolCreateInfo.queueFamilyIndex = m_core->getContext().getQueueManager().getGraphicsQueues()[0].familyIndex; commandPoolCreateInfo.queueFamilyIndex = m_core->getContext().getQueueManager().getGraphicsQueues()[0].familyIndex;
if (device.createCommandPool(&commandPoolCreateInfo, nullptr, &commandPool) != vk::Result::eSuccess) { if (m_core->getContext().getDevice().createCommandPool(&commandPoolCreateInfo, nullptr, &commandPool) != vk::Result::eSuccess) {
vkcv_log(LogLevel::ERROR, "ASManager: command pool could not be created."); vkcv_log(LogLevel::ERROR, "ASManager: command pool could not be created.");
} }
...@@ -214,14 +231,14 @@ namespace vkcv::rtx { ...@@ -214,14 +231,14 @@ namespace vkcv::rtx {
bufferAllocateInfo.commandBufferCount = 1; bufferAllocateInfo.commandBufferCount = 1;
vk::CommandBuffer commandBuffer; vk::CommandBuffer commandBuffer;
if (device.allocateCommandBuffers(&bufferAllocateInfo, &commandBuffer) != vk::Result::eSuccess) { if (m_core->getContext().getDevice().allocateCommandBuffers(&bufferAllocateInfo, &commandBuffer) != vk::Result::eSuccess) {
vkcv_log(LogLevel::ERROR, "ASManager: command buffer could not be allocated."); vkcv_log(LogLevel::ERROR, "ASManager: command buffer could not be allocated.");
} }
beginCommandBuffer(commandBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); beginCommandBuffer(commandBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
vk::BufferCopy bufferCopy; vk::BufferCopy bufferCopy;
bufferCopy.size = deviceSize; bufferCopy.size = cpuBuffer.deviceSize;
commandBuffer.copyBuffer(stagingBuffer, dataBuffer, 1, &bufferCopy); commandBuffer.copyBuffer(cpuBuffer.vulkanHandle, gpuBuffer.vulkanHandle, 1, &bufferCopy);
commandBuffer.end(); commandBuffer.end();
vk::SubmitInfo submitInfo; vk::SubmitInfo submitInfo;
...@@ -233,11 +250,10 @@ namespace vkcv::rtx { ...@@ -233,11 +250,10 @@ namespace vkcv::rtx {
graphicsQueue.handle.submit(submitInfo); graphicsQueue.handle.submit(submitInfo);
graphicsQueue.handle.waitIdle(); graphicsQueue.handle.waitIdle();
device.freeCommandBuffers(commandPool, 1, &commandBuffer); m_core->getContext().getDevice().freeCommandBuffers(commandPool, 1, &commandBuffer, m_rtxDispatcher);
device.destroyBuffer(stagingBuffer); m_core->getContext().getDevice().destroyCommandPool(commandPool, nullptr, m_rtxDispatcher);
device.freeMemory(deviceMemory); m_core->getContext().getDevice().destroyBuffer(cpuBuffer.vulkanHandle, nullptr, m_rtxDispatcher);
m_core->getContext().getDevice().freeMemory(cpuBuffer.deviceMemory, nullptr, m_rtxDispatcher);
return dataBuffer;
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment