https://nvpro-samples.github.io/vk_mini_path_tracer/
https://github.com/nvpro-samples/vk_mini_path_tracer
"Execution of Work"
vkCmdDraw(command_buffer, ...);
vkQueueSubmit(...);
VkCommandPoolCreateInfo cmdPoolInfo = nvvk::make<VkCommandPoolCreateInfo>();
cmdPoolInfo.queueFamilyIndex = context.m_queueGCT;
VkCommandPool cmdPool;
NVVK_CHECK(vkCreateCommandPool(context, &cmdPoolInfo, nullptr, &cmdPool));NVVK_CHECK() macro is for checking return values of Vulkan functions
If a function doesn't return void, it returns `VkResult` which is an enum
Returning `VK_SUCCESS` signals that the function didn't fail
VK_NULL_HANDLE is a type alias for 0. This is used when there is no 'valid' handle to use
However, in C++`nullptr` can be used instead
VkCommandBufferAllocateInfo cmdAllocInfo = nvvk::make<VkCommandBufferAllocateInfo>();
cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmdAllocInfo.commandPool = cmdPool;
cmdAllocInfo.commandBufferCount = 1;
VkCommandBuffer cmdBuffer;
NVVK_CHECK(vkAllocateCommandBuffers(context, &cmdAllocInfo, &cmdBuffer));VkCommandBufferBeginInfo beginInfo = nvvk::make<VkCommandBufferBeginInfo>();
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
NVVK_CHECK(vkBeginCommandBuffer(cmdBuffer, &beginInfo));const float fillValue = 0.5f;
const uint32_t& fillValueU32 = reinterpret_cast<const uint32_t&>(fillValue);
vkCmdFillBuffer(cmdBuffer, buffer.buffer, 0, bufferSizeBytes, fillValueU32);Meaning: Our 'Fill GPU Buffer' command might not finish before we start reading from it on the CPU
Consecutive commands in a command buffer may work in any order they like, so long as they follow manually defined 'synchronization points'
Meaning: Use pipeline barriers to insert the desired order everything must happen in.
// Add a command that says "Make it so that memory writes by the vkCmdFillBuffer call
// are available to read from the CPU." (In other words, "Flush the GPU caches
// so the CPU can read the data.") To do this, we use a memory barrier.
VkMemoryBarrier memoryBarrier = nvvk::make<VkMemoryBarrier>();
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; // Make transfer writes
memoryBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; // Readable by the CPU
vkCmdPipelineBarrier(cmdBuffer, // The command buffer
VK_PIPELINE_STAGE_TRANSFER_BIT, // From the transfer stage
VK_PIPELINE_STAGE_HOST_BIT, // To the CPU
0, // No special flags
1, &memoryBarrier, // An array of memory barriers
0, nullptr, 0, nullptr); // No other barriersMakes the command buffer ready to be submitted and executed
NVVK_CHECK(vkEndCommandBuffer(cmdBuffer));Now to submit it!
VkSubmitInfo submitInfo = nvvk::make<VkSubmitInfo>();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
NVVK_CHECK(vkQueueSubmit(context.m_queueGCT, 1, &submitInfo, VK_NULL_HANDLE));vkQueueSubmit performance note:
This call is expensive. If you can, throw multiple 'command buffers' into the same submit when possible.
vkQueueWaitIdle(context.m_queueGCT);
Delete the Command Pool once we are done
vkDestroyCommandPool(context, cmdPool, nullptr);Can delete the Command Buffer individually, but easier to delete the pool
Output should now be:
First four elements: 0.500000, 0.500000, 0.500000, 0.500000
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <fileformats/stb_image_write.h>float* fltData = reinterpret_cast<float*>(data);
stbi_write_hdr("out.hdr",
render_width, render_height, 3, reinterpret_cast<float*>(data));3 is for 3 channels, for RGB