Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save romualdo97/b9deeb1735d9f4fc726c23d956bbf83a to your computer and use it in GitHub Desktop.
Save romualdo97/b9deeb1735d9f4fc726c23d956bbf83a to your computer and use it in GitHub Desktop.
Snippet from Vulkan and Unreal VulkanRHI studies outlining a command buffer that clears an image and is submitted into GPU for processing then the result is presented, this will become more abstract as we advance in the RHI API studies, here we see the plain Vulkan API
void FVulkanDynamicRHI::DoExperimentsSetup()
{
// Create a swap chain and its surface
std::vector<VkImage> Images;
const FVulkanSwapChain SwapChain{Instance, *Device, GetWindowHandle(), 300, 300, Images};
// Create a command memory pool
const VkCommandPoolCreateInfo CommandPoolCreateInfo
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
nullptr,
0,
Device->PresentQueue->GetFamilyIndex()
};
VkCommandPool CommandPool;
if (VulkanRHI::vkCreateCommandPool(Device->GetInstanceHandle(), &CommandPoolCreateInfo, nullptr, &CommandPool) != VK_SUCCESS)
{
std::cerr << "Failed to create a command pool" << std::endl;
return;
}
// Allocate a command buffer for each image
const VkCommandBufferAllocateInfo CommandBufferAllocateInfo
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr,
CommandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(Images.size())
};
std::vector<VkCommandBuffer> CommandBuffers{ Images.size() };
VulkanRHI::vkAllocateCommandBuffers(Device->GetInstanceHandle(), &CommandBufferAllocateInfo, CommandBuffers.data());
for (uint32_t Index = 0; Index < CommandBuffers.size(); ++Index)
{
// Cmd: Begin recording
constexpr VkCommandBufferBeginInfo CommandBufferBeginInfo
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
nullptr
};
VulkanRHI::vkBeginCommandBuffer(CommandBuffers[Index], &CommandBufferBeginInfo);
// Cmd: Transition image layout from presentation to transfer
constexpr VkImageSubresourceRange ImageSubresourceRange
{
VK_IMAGE_ASPECT_COLOR_BIT,
0, 1,
0, 1
};
const VkImageMemoryBarrier BarrierFromPresentToClear
{
VK_STRUCTURE_TYPE_MEMORY_BARRIER,
nullptr,
VK_ACCESS_MEMORY_READ_BIT,
VK_ACCESS_MEMORY_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
Device->GetPresentQueue()->GetFamilyIndex(),
Device->GetPresentQueue()->GetFamilyIndex(),
Images[Index],
ImageSubresourceRange
};
VulkanRHI::vkCmdPipelineBarrier(
CommandBuffers[Index],
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&BarrierFromPresentToClear);
// Cmd: Clear color
VkClearColorValue ClearColorValue = { { 1.0f, 0.67f, 0.5f, 0.0f } };
VulkanRHI::vkCmdClearColorImage(CommandBuffers[Index], Images[Index], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &ClearColorValue, 1, &ImageSubresourceRange);
// Cmd: Transition image layout from transfer to presentation
const VkImageMemoryBarrier BarrierFromClearToPresent
{
VK_STRUCTURE_TYPE_MEMORY_BARRIER,
nullptr,
VK_ACCESS_MEMORY_WRITE_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
Device->GetPresentQueue()->GetFamilyIndex(),
Device->GetPresentQueue()->GetFamilyIndex(),
Images[Index],
ImageSubresourceRange
};
VulkanRHI::vkCmdPipelineBarrier(
CommandBuffers[Index],
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&BarrierFromClearToPresent);
// Cmd: End recording
if (VulkanRHI::vkEndCommandBuffer(CommandBuffers[Index]) != VK_SUCCESS) {
std::cerr << "Could not record command buffers!" << std::endl;
return;
}
}
// Create a semaphore to signal when rendering is finished (Rendering means the commands in the command buffer above)
constexpr VkSemaphoreCreateInfo SemaphoreCreateInfo
{
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr,
VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM
};
VkSemaphore RenderingFinishedSemaphore;
VulkanRHI::vkCreateSemaphore(Device->GetInstanceHandle(), &SemaphoreCreateInfo, nullptr, &RenderingFinishedSemaphore);
// Create a semaphore to signal when an image is available to be acquired from the presentation engine
VkSemaphore ImageAvailableSemaphore;
VulkanRHI::vkCreateSemaphore(Device->GetInstanceHandle(), &SemaphoreCreateInfo, nullptr, &ImageAvailableSemaphore);
// Setup experiments globals
GExperimentsData.CommandPool = CommandPool;
GExperimentsData.CommandBuffers = CommandBuffers;
GExperimentsData.RenderingFinishedSemaphore = RenderingFinishedSemaphore;
GExperimentsData.ImageAvailableSemaphore = ImageAvailableSemaphore;
GExperimentsData.SwapChain = SwapChain.GetInstanceHandle();
}
void FVulkanDynamicRHI::DoExperimentsTick()
{
// Acquire an image from the presentation engine
uint32_t AcquiredImageIndex;
VulkanRHI::vkAcquireNextImageKHR(
Device->GetInstanceHandle(),
GExperimentsData.SwapChain,
UINT64_MAX,
GExperimentsData.ImageAvailableSemaphore, // Signaled when an image is available
VK_NULL_HANDLE,
&AcquiredImageIndex);
// Submit a CommandBuffer after ImageAvailableSemaphore is signaled
VkPipelineStageFlags WaitDstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
const VkSubmitInfo SubmitInfo
{
VK_STRUCTURE_TYPE_SUBMIT_INFO,
nullptr,
1, &GExperimentsData.ImageAvailableSemaphore, // Wait for semaphore signaled
&WaitDstStageMask,
1, &GExperimentsData.CommandBuffers[AcquiredImageIndex],
1, &GExperimentsData.RenderingFinishedSemaphore // Signal semaphore
};
VulkanRHI::vkQueueSubmit(Device->PresentQueue->GetHandle(), 1, &SubmitInfo, VK_NULL_HANDLE);
VkResult Results;
const VkPresentInfoKHR PresentInfo
{
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
nullptr,
1, &GExperimentsData.RenderingFinishedSemaphore,
1, &GExperimentsData.SwapChain,
&AcquiredImageIndex, &Results
};
VulkanRHI::vkQueuePresentKHR(Device->GetPresentQueue()->GetHandle(), &PresentInfo);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment