Updated to full hpp headers

This commit is contained in:
Alejandro Saucedo 2020-08-12 07:45:05 +01:00
parent 52cb64db99
commit 79168e2de9

View file

@ -55,6 +55,7 @@ class VulkanCompute
vk::ShaderModule mShaderModule; vk::ShaderModule mShaderModule;
vk::Pipeline mPipeline; vk::Pipeline mPipeline;
vk::CommandPool mCommandPool; vk::CommandPool mCommandPool;
vk::CommandBuffer mCommandBuffer;
uint32_t mComputeQueueFamilyIndex; uint32_t mComputeQueueFamilyIndex;
@ -64,8 +65,7 @@ class VulkanCompute
const vk::MemoryPropertyFlags& aMemoryPropertyFlags, const vk::MemoryPropertyFlags& aMemoryPropertyFlags,
vk::Buffer* aBuffer, vk::Buffer* aBuffer,
vk::DeviceMemory* aMemory, vk::DeviceMemory* aMemory,
vk::DeviceSize aSize, vk::DeviceSize aSize) const
void* aData = nullptr) const
{ {
SPDLOG_DEBUG("Creating buffer: {}, {}, {}", SPDLOG_DEBUG("Creating buffer: {}, {}, {}",
vk::to_string(aUsageFlags), vk::to_string(aUsageFlags),
@ -105,38 +105,9 @@ class VulkanCompute
*aMemory = this->mDevice.allocateMemory(memoryAllocateInfo); *aMemory = this->mDevice.allocateMemory(memoryAllocateInfo);
if (aData != nullptr) {
vk::DeviceSize offset = 0;
void* mapped = this->mDevice.mapMemory(
*aMemory, offset, aSize, vk::MemoryMapFlags());
memcpy(mapped, aData, aSize);
this->mDevice.unmapMemory(*aMemory);
}
this->mDevice.bindBufferMemory(*aBuffer, *aMemory, 0); this->mDevice.bindBufferMemory(*aBuffer, *aMemory, 0);
} }
/*
* C API
*/
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
// uint32_t queueFamilyIndex;
VkPipelineCache pipelineCache;
VkQueue queue;
VkCommandPool commandPool;
VkCommandBuffer commandBuffer;
VkFence fence;
VkDescriptorPool descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
VkDescriptorSet descriptorSet;
VkPipelineLayout pipelineLayout;
VkPipeline pipeline;
VkShaderModule shaderModule;
// VkDebugReportCallbackEXT debugReportCallback{};
VulkanCompute() VulkanCompute()
{ {
LOG("Running headless compute example\n"); LOG("Running headless compute example\n");
@ -286,8 +257,7 @@ class VulkanCompute
vk::MemoryPropertyFlagBits::eHostVisible, vk::MemoryPropertyFlagBits::eHostVisible,
&hostBuffer, &hostBuffer,
&hostMemory, &hostMemory,
bufferSize, bufferSize);
computeInput.data());
createBuffer(vk::BufferUsageFlagBits::eStorageBuffer | createBuffer(vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferSrc |
@ -298,6 +268,17 @@ class VulkanCompute
bufferSize); bufferSize);
} }
{
// Copy data to host memory
vk::DeviceSize offset = 0;
void* mapped = this->mDevice.mapMemory(
hostMemory, offset, bufferSize, vk::MemoryMapFlags());
memcpy(mapped, computeInput.data(), computeInput.size());
vk::MappedMemoryRange mappedRange(hostMemory, 0, bufferSize);
this->mDevice.flushMappedMemoryRanges(1, &mappedRange);
this->mDevice.unmapMemory(hostMemory);
}
{ {
std::vector<vk::DescriptorPoolSize> poolSizes = { std::vector<vk::DescriptorPoolSize> poolSizes = {
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1) vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1)
@ -379,19 +360,6 @@ class VulkanCompute
shadersPath + "computeheadless.comp.spv"; shadersPath + "computeheadless.comp.spv";
spdlog::info("Shader file path: {}", shaderFilePath); spdlog::info("Shader file path: {}", shaderFilePath);
// std::ifstream file(shaderFilePath, std::ios::binary);
// file.unsetf(std::ios::skipws);
// std::streampos fileSize;
// file.seekg(0, std::ios::end);
// fileSize = file.tellg();
// file.seekg(0, std::ios::beg);
// std::vector<uint8_t> fileData;
// fileData.reserve(fileSize);
// fileData.insert(fileData.begin(),
// std::istream_iterator<uint8_t>(file),
// std::istream_iterator<uint8_t>()); file.close();
SPDLOG_DEBUG("Reading file"); SPDLOG_DEBUG("Reading file");
std::ifstream fileStream( std::ifstream fileStream(
shaderFilePath, std::ios::binary | std::ios::in | std::ios::ate); shaderFilePath, std::ios::binary | std::ios::in | std::ios::ate);
@ -449,223 +417,146 @@ class VulkanCompute
} }
{ {
spdlog::info("Allocating rest of components for backwards compat"); vk::CommandBufferAllocateInfo cmdBufferAllocInfo(
this->instance = static_cast<VkInstance>(this->mInstance); this->mCommandPool, vk::CommandBufferLevel::ePrimary, 1);
this->physicalDevice = this->mPhysicalDevice;
this->device = this->mDevice; std::vector<vk::CommandBuffer> cmdBuffers =
this->queue = this->mComputeQueue; this->mDevice.allocateCommandBuffers(cmdBufferAllocInfo);
this->descriptorSetLayout = this->mDescriptorSetLayout;
this->pipelineLayout = this->mPipelineLayout; this->mCommandBuffer = cmdBuffers[0];
this->descriptorPool = this->mDescriptorPool; this->mCommandBuffer.begin(vk::CommandBufferBeginInfo());
this->descriptorSet = this->mDescriptorSet; {
this->shaderModule = this->mShaderModule; // Barrier to ensure input transfer is finished before compute
this->pipeline = this->mPipeline; // shader reads from it
this->commandPool = this->mCommandPool; vk::BufferMemoryBarrier bufferMemoryBarrier;
bufferMemoryBarrier.buffer = deviceBuffer;
bufferMemoryBarrier.size = VK_WHOLE_SIZE;
bufferMemoryBarrier.srcAccessMask =
vk::AccessFlagBits::eHostWrite;
bufferMemoryBarrier.dstAccessMask =
vk::AccessFlagBits::eShaderRead;
bufferMemoryBarrier.srcQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
bufferMemoryBarrier.dstQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
this->mCommandBuffer.pipelineBarrier(
vk::PipelineStageFlagBits::eHost,
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags(),
nullptr,
bufferMemoryBarrier,
nullptr);
this->mCommandBuffer.bindPipeline(
vk::PipelineBindPoint::eCompute, this->mPipeline);
this->mCommandBuffer.bindDescriptorSets(
vk::PipelineBindPoint::eCompute,
this->mPipelineLayout,
0,
this->mDescriptorSet,
nullptr);
this->mCommandBuffer.dispatch(BUFFER_ELEMENTS, 1, 1);
// Barrier to ensure that shader writes are finished before
// buffer is read back from GPU
bufferMemoryBarrier.srcAccessMask =
vk::AccessFlagBits::eShaderWrite;
bufferMemoryBarrier.dstAccessMask =
vk::AccessFlagBits::eTransferRead;
this->mCommandBuffer.pipelineBarrier(
vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlags(),
nullptr,
bufferMemoryBarrier,
nullptr);
// Read back to host visible buffer
vk::BufferCopy copyRegion(0, 0, bufferSize);
this->mCommandBuffer.copyBuffer(
deviceBuffer, hostBuffer, copyRegion);
// Barrier to ensure that buffer copy is finished before host
// reading from it
bufferMemoryBarrier.srcAccessMask =
vk::AccessFlagBits::eTransferWrite;
bufferMemoryBarrier.dstAccessMask =
vk::AccessFlagBits::eHostRead;
bufferMemoryBarrier.buffer = hostBuffer;
this->mCommandBuffer.pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eHost,
vk::DependencyFlags(),
nullptr,
bufferMemoryBarrier,
nullptr);
}
this->mCommandBuffer.end();
} }
{ {
vk::Fence fence = this->mDevice.createFence(vk::FenceCreateInfo());
// Create a command buffer for compute operations const vk::PipelineStageFlags waitStageMask =
VkCommandBufferAllocateInfo cmdBufAllocateInfo = vk::PipelineStageFlagBits::eTransfer;
vks::initializers::commandBufferAllocateInfo(
this->commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
VK_CHECK_RESULT(vkAllocateCommandBuffers(
this->device, &cmdBufAllocateInfo, &this->commandBuffer));
// Fence for compute CB sync vk::SubmitInfo computeSubmitInfo(
VkFenceCreateInfo fenceCreateInfo = 0, nullptr, &waitStageMask, 1, &this->mCommandBuffer);
vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT);
VK_CHECK_RESULT(vkCreateFence( this->mComputeQueue.submit(computeSubmitInfo, fence);
this->device, &fenceCreateInfo, nullptr, &this->fence));
this->mDevice.waitForFences(fence, VK_TRUE, UINT64_MAX);
this->mDevice.destroy(fence);
} }
{ {
// Flush writes to host visible buffer // Make device writes visible to host
void* mapped; void* mapped = this->mDevice.mapMemory(hostMemory, 0, VK_WHOLE_SIZE, vk::MemoryMapFlags());
vkMapMemory(this->device, hostMemory, 0, VK_WHOLE_SIZE, 0, &mapped); vk::MappedMemoryRange mappedMemoryRange(hostMemory, 0, VK_WHOLE_SIZE);
VkMappedMemoryRange mappedRange = this->mDevice.invalidateMappedMemoryRanges(mappedMemoryRange);
vks::initializers::mappedMemoryRange(); memcpy(computeOutput.data(), hostBuffer, bufferSize);
mappedRange.memory = hostMemory; this->mDevice.unmapMemory(hostMemory);
mappedRange.offset = 0;
mappedRange.size = VK_WHOLE_SIZE;
vkFlushMappedMemoryRanges(this->device, 1, &mappedRange);
vkUnmapMemory(this->device, hostMemory);
} }
/*
Command buffer creation (for compute work submission)
*/
{ {
VkCommandBufferBeginInfo cmdBufInfo = this->mComputeQueue.waitIdle();
vks::initializers::commandBufferBeginInfo();
VK_CHECK_RESULT( spdlog::info("Compute input: {}", computeInput);
vkBeginCommandBuffer(this->commandBuffer, &cmdBufInfo)); spdlog::info("Compute output: {}", computeInput);
VkBufferCopy copyRegion = {};
copyRegion.size = bufferSize;
vkCmdCopyBuffer(
this->commandBuffer, hostBuffer, deviceBuffer, 1, &copyRegion);
// Barrier to ensure that input buffer transfer is finished before
// compute shader reads from it
VkBufferMemoryBarrier bufferBarrier =
vks::initializers::bufferMemoryBarrier();
bufferBarrier.buffer = deviceBuffer;
bufferBarrier.size = VK_WHOLE_SIZE;
bufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(this->commandBuffer,
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_FLAGS_NONE,
0,
nullptr,
1,
&bufferBarrier,
0,
nullptr);
vkCmdBindPipeline(this->commandBuffer,
VK_PIPELINE_BIND_POINT_COMPUTE,
this->pipeline);
vkCmdBindDescriptorSets(this->commandBuffer,
VK_PIPELINE_BIND_POINT_COMPUTE,
this->pipelineLayout,
0,
1,
&this->descriptorSet,
0,
0);
vkCmdDispatch(this->commandBuffer, BUFFER_ELEMENTS / 4, 1, 1);
// Barrier to ensure that shader writes are finished before buffer
// is read back from GPU
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
bufferBarrier.buffer = deviceBuffer;
bufferBarrier.size = VK_WHOLE_SIZE;
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(this->commandBuffer,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_FLAGS_NONE,
0,
nullptr,
1,
&bufferBarrier,
0,
nullptr);
// Read back to host visible buffer
copyRegion = {};
copyRegion.size = bufferSize;
vkCmdCopyBuffer(
this->commandBuffer, deviceBuffer, hostBuffer, 1, &copyRegion);
// Barrier to ensure that buffer copy is finished before host
// reading from it
bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
bufferBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
bufferBarrier.buffer = hostBuffer;
bufferBarrier.size = VK_WHOLE_SIZE;
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(this->commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT,
VK_FLAGS_NONE,
0,
nullptr,
1,
&bufferBarrier,
0,
nullptr);
VK_CHECK_RESULT(vkEndCommandBuffer(this->commandBuffer));
// Submit compute work
vkResetFences(this->device, 1, &this->fence);
const VkPipelineStageFlags waitStageMask =
VK_PIPELINE_STAGE_TRANSFER_BIT;
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.pWaitDstStageMask = &waitStageMask;
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &this->commandBuffer;
VK_CHECK_RESULT(
vkQueueSubmit(this->queue, 1, &computeSubmitInfo, this->fence));
VK_CHECK_RESULT(vkWaitForFences(
this->device, 1, &this->fence, VK_TRUE, UINT64_MAX));
// Make this->device writes visible to the host
void* mapped;
vkMapMemory(this->device, hostMemory, 0, VK_WHOLE_SIZE, 0, &mapped);
VkMappedMemoryRange mappedRange =
vks::initializers::mappedMemoryRange();
mappedRange.memory = hostMemory;
mappedRange.offset = 0;
mappedRange.size = VK_WHOLE_SIZE;
vkInvalidateMappedMemoryRanges(this->device, 1, &mappedRange);
// Copy to output
memcpy(computeOutput.data(), mapped, bufferSize);
vkUnmapMemory(this->device, hostMemory);
} }
vkQueueWaitIdle(this->queue); {
this->mDevice.destroy(deviceBuffer);
// Output buffer contents this->mDevice.freeMemory(deviceMemory);
LOG("Compute input:\n"); this->mDevice.destroy(hostBuffer);
for (auto v : computeInput) { this->mDevice.freeMemory(hostMemory);
LOG("%d ", v);
} }
std::cout << std::endl;
LOG("Compute output:\n");
for (auto v : computeOutput) {
LOG("%d ", v);
}
std::cout << std::endl;
// Clean up
vkDestroyBuffer(this->device, deviceBuffer, nullptr);
vkFreeMemory(this->device, deviceMemory, nullptr);
vkDestroyBuffer(this->device, hostBuffer, nullptr);
vkFreeMemory(this->device, hostMemory, nullptr);
} }
~VulkanCompute() ~VulkanCompute()
{ {
vkDestroyPipelineLayout(this->device, this->pipelineLayout, nullptr); this->mDevice.destroy(this->mPipelineLayout);
vkDestroyDescriptorSetLayout( this->mDevice.destroy(this->mDescriptorSetLayout);
this->device, this->descriptorSetLayout, nullptr); this->mDevice.destroy(this->mDescriptorPool);
vkDestroyDescriptorPool(this->device, this->descriptorPool, nullptr); this->mDevice.destroy(this->mPipeline);
vkDestroyPipeline(this->device, this->pipeline, nullptr); this->mDevice.destroy(this->mPipelineCache);
vkDestroyPipelineCache(this->device, this->pipelineCache, nullptr); this->mDevice.destroy(this->mCommandPool);
vkDestroyFence(this->device, this->fence, nullptr); this->mDevice.destroy(this->mShaderModule);
vkDestroyCommandPool(this->device, this->commandPool, nullptr); this->mDevice.destroy();
vkDestroyShaderModule(this->device, this->shaderModule, nullptr);
vkDestroyDevice(this->device, nullptr);
#if DEBUG #if DEBUG
if (this->mDebugReportCallback) { if (this->mDebugReportCallback) {
// TODO: Migrate thsi to hpp headers
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback = PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback =
reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>( reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
vkGetInstanceProcAddr(this->instance, vkGetInstanceProcAddr(this->mInstance,
"vkDestroyDebugReportCallbackEXT")); "vkDestroyDebugReportCallbackEXT"));
assert(vkDestroyDebugReportCallback); assert(vkDestroyDebugReportCallback);
vkDestroyDebugReportCallback( this->mInstance.destroyDebugReportCallbackEXT(this->mDebugReportCallback);
this->instance, this->mDebugReportCallback, nullptr);
} }
#endif #endif
vkDestroyInstance(this->instance, nullptr); this->mInstance.destroy();
} }
}; };