Add a specialized copy command buffer to the vulkan swap chain
This commit is contained in:
parent
86cb40f0c6
commit
f839a1293f
|
@ -187,6 +187,10 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &render_cmd_buffer_);
|
vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &render_cmd_buffer_);
|
||||||
CheckResult(err, "vkCreateCommandBuffer");
|
CheckResult(err, "vkCreateCommandBuffer");
|
||||||
|
|
||||||
|
// Create another command buffer that handles image copies.
|
||||||
|
err = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, ©_cmd_buffer_);
|
||||||
|
CheckResult(err, "vkCreateCommandBuffer");
|
||||||
|
|
||||||
// Create the render pass used to draw to the swap chain.
|
// Create the render pass used to draw to the swap chain.
|
||||||
// The actual framebuffer attached will depend on which image we are drawing
|
// The actual framebuffer attached will depend on which image we are drawing
|
||||||
// into.
|
// into.
|
||||||
|
@ -194,7 +198,7 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
color_attachment.flags = 0;
|
color_attachment.flags = 0;
|
||||||
color_attachment.format = surface_format_;
|
color_attachment.format = surface_format_;
|
||||||
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // CLEAR;
|
||||||
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
@ -388,6 +392,7 @@ bool VulkanSwapChain::Begin() {
|
||||||
|
|
||||||
// Reset all command buffers.
|
// Reset all command buffers.
|
||||||
vkResetCommandBuffer(render_cmd_buffer_, 0);
|
vkResetCommandBuffer(render_cmd_buffer_, 0);
|
||||||
|
vkResetCommandBuffer(copy_cmd_buffer_, 0);
|
||||||
auto& current_buffer = buffers_[current_buffer_index_];
|
auto& current_buffer = buffers_[current_buffer_index_];
|
||||||
|
|
||||||
// Build the command buffer that will execute all queued rendering buffers.
|
// Build the command buffer that will execute all queued rendering buffers.
|
||||||
|
@ -399,14 +404,18 @@ bool VulkanSwapChain::Begin() {
|
||||||
err = vkBeginCommandBuffer(render_cmd_buffer_, &begin_info);
|
err = vkBeginCommandBuffer(render_cmd_buffer_, &begin_info);
|
||||||
CheckResult(err, "vkBeginCommandBuffer");
|
CheckResult(err, "vkBeginCommandBuffer");
|
||||||
|
|
||||||
// Transition the image to a format we can render to.
|
// Start recording the copy command buffer as well.
|
||||||
|
err = vkBeginCommandBuffer(copy_cmd_buffer_, &begin_info);
|
||||||
|
CheckResult(err, "vkBeginCommandBuffer");
|
||||||
|
|
||||||
|
// Transition the image to a format we can copy to.
|
||||||
VkImageMemoryBarrier pre_image_memory_barrier;
|
VkImageMemoryBarrier pre_image_memory_barrier;
|
||||||
pre_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
pre_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
pre_image_memory_barrier.pNext = nullptr;
|
pre_image_memory_barrier.pNext = nullptr;
|
||||||
pre_image_memory_barrier.srcAccessMask = 0;
|
pre_image_memory_barrier.srcAccessMask = 0;
|
||||||
pre_image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
pre_image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
pre_image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
pre_image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
pre_image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
pre_image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
pre_image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
pre_image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
pre_image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
pre_image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
pre_image_memory_barrier.image = current_buffer.image;
|
pre_image_memory_barrier.image = current_buffer.image;
|
||||||
|
@ -416,23 +425,37 @@ bool VulkanSwapChain::Begin() {
|
||||||
pre_image_memory_barrier.subresourceRange.levelCount = 1;
|
pre_image_memory_barrier.subresourceRange.levelCount = 1;
|
||||||
pre_image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
pre_image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
pre_image_memory_barrier.subresourceRange.layerCount = 1;
|
pre_image_memory_barrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(copy_cmd_buffer_, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||||
|
nullptr, 1, &pre_image_memory_barrier);
|
||||||
|
|
||||||
|
// First: Issue a command to clear the render target.
|
||||||
|
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
|
VkClearColorValue clear_color;
|
||||||
|
clear_color.float32[0] = 238 / 255.0f;
|
||||||
|
clear_color.float32[1] = 238 / 255.0f;
|
||||||
|
clear_color.float32[2] = 238 / 255.0f;
|
||||||
|
clear_color.float32[3] = 1.0f;
|
||||||
|
if (FLAGS_vulkan_random_clear_color) {
|
||||||
|
clear_color.float32[0] =
|
||||||
|
rand() / static_cast<float>(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
|
||||||
|
clear_color.float32[1] = 1.0f;
|
||||||
|
clear_color.float32[2] = 0.0f;
|
||||||
|
}
|
||||||
|
vkCmdClearColorImage(copy_cmd_buffer_, current_buffer.image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1,
|
||||||
|
&clear_range);
|
||||||
|
|
||||||
|
// Transition the image to a color attachment target for drawing.
|
||||||
|
pre_image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
pre_image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
pre_image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
pre_image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
vkCmdPipelineBarrier(render_cmd_buffer_, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
vkCmdPipelineBarrier(render_cmd_buffer_, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||||
nullptr, 1, &pre_image_memory_barrier);
|
nullptr, 1, &pre_image_memory_barrier);
|
||||||
|
|
||||||
// Begin render pass.
|
// Begin render pass.
|
||||||
VkClearValue color_clear_value;
|
|
||||||
color_clear_value.color.float32[0] = 238 / 255.0f;
|
|
||||||
color_clear_value.color.float32[1] = 238 / 255.0f;
|
|
||||||
color_clear_value.color.float32[2] = 238 / 255.0f;
|
|
||||||
color_clear_value.color.float32[3] = 1.0f;
|
|
||||||
if (FLAGS_vulkan_random_clear_color) {
|
|
||||||
color_clear_value.color.float32[0] =
|
|
||||||
rand() / static_cast<float>(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
|
|
||||||
color_clear_value.color.float32[1] = 1.0f;
|
|
||||||
color_clear_value.color.float32[2] = 0.0f;
|
|
||||||
}
|
|
||||||
VkClearValue clear_values[] = {color_clear_value};
|
|
||||||
VkRenderPassBeginInfo render_pass_begin_info;
|
VkRenderPassBeginInfo render_pass_begin_info;
|
||||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
render_pass_begin_info.pNext = nullptr;
|
render_pass_begin_info.pNext = nullptr;
|
||||||
|
@ -442,9 +465,8 @@ bool VulkanSwapChain::Begin() {
|
||||||
render_pass_begin_info.renderArea.offset.y = 0;
|
render_pass_begin_info.renderArea.offset.y = 0;
|
||||||
render_pass_begin_info.renderArea.extent.width = surface_width_;
|
render_pass_begin_info.renderArea.extent.width = surface_width_;
|
||||||
render_pass_begin_info.renderArea.extent.height = surface_height_;
|
render_pass_begin_info.renderArea.extent.height = surface_height_;
|
||||||
render_pass_begin_info.clearValueCount =
|
render_pass_begin_info.clearValueCount = 0;
|
||||||
static_cast<uint32_t>(xe::countof(clear_values));
|
render_pass_begin_info.pClearValues = nullptr;
|
||||||
render_pass_begin_info.pClearValues = clear_values;
|
|
||||||
vkCmdBeginRenderPass(render_cmd_buffer_, &render_pass_begin_info,
|
vkCmdBeginRenderPass(render_cmd_buffer_, &render_pass_begin_info,
|
||||||
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
|
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
|
||||||
|
|
||||||
|
@ -458,6 +480,7 @@ bool VulkanSwapChain::End() {
|
||||||
vkCmdEndRenderPass(render_cmd_buffer_);
|
vkCmdEndRenderPass(render_cmd_buffer_);
|
||||||
|
|
||||||
// Transition the image to a format the presentation engine can source from.
|
// Transition the image to a format the presentation engine can source from.
|
||||||
|
// FIXME: Do we need more synchronization here between the copy buffer?
|
||||||
VkImageMemoryBarrier post_image_memory_barrier;
|
VkImageMemoryBarrier post_image_memory_barrier;
|
||||||
post_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
post_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
post_image_memory_barrier.pNext = nullptr;
|
post_image_memory_barrier.pNext = nullptr;
|
||||||
|
@ -483,14 +506,20 @@ bool VulkanSwapChain::End() {
|
||||||
auto err = vkEndCommandBuffer(render_cmd_buffer_);
|
auto err = vkEndCommandBuffer(render_cmd_buffer_);
|
||||||
CheckResult(err, "vkEndCommandBuffer");
|
CheckResult(err, "vkEndCommandBuffer");
|
||||||
|
|
||||||
|
err = vkEndCommandBuffer(copy_cmd_buffer_);
|
||||||
|
CheckResult(err, "vkEndCommandBuffer");
|
||||||
|
|
||||||
|
VkCommandBuffer command_buffers[] = {copy_cmd_buffer_, render_cmd_buffer_};
|
||||||
|
|
||||||
// Submit rendering.
|
// Submit rendering.
|
||||||
VkSubmitInfo render_submit_info;
|
VkSubmitInfo render_submit_info;
|
||||||
render_submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
render_submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
render_submit_info.pNext = nullptr;
|
render_submit_info.pNext = nullptr;
|
||||||
render_submit_info.waitSemaphoreCount = 0;
|
render_submit_info.waitSemaphoreCount = 0;
|
||||||
render_submit_info.pWaitSemaphores = nullptr;
|
render_submit_info.pWaitSemaphores = nullptr;
|
||||||
render_submit_info.commandBufferCount = 1;
|
render_submit_info.commandBufferCount =
|
||||||
render_submit_info.pCommandBuffers = &render_cmd_buffer_;
|
static_cast<uint32_t>(xe::countof(command_buffers));
|
||||||
|
render_submit_info.pCommandBuffers = command_buffers;
|
||||||
render_submit_info.signalSemaphoreCount = 0;
|
render_submit_info.signalSemaphoreCount = 0;
|
||||||
render_submit_info.pSignalSemaphores = nullptr;
|
render_submit_info.pSignalSemaphores = nullptr;
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,11 +35,16 @@ class VulkanSwapChain {
|
||||||
|
|
||||||
uint32_t surface_width() const { return surface_width_; }
|
uint32_t surface_width() const { return surface_width_; }
|
||||||
uint32_t surface_height() const { return surface_height_; }
|
uint32_t surface_height() const { return surface_height_; }
|
||||||
|
VkImage surface_image() const {
|
||||||
|
return buffers_[current_buffer_index_].image;
|
||||||
|
}
|
||||||
|
|
||||||
// Render pass used for compositing.
|
// Render pass used for compositing.
|
||||||
VkRenderPass render_pass() const { return render_pass_; }
|
VkRenderPass render_pass() const { return render_pass_; }
|
||||||
// Render command buffer, active inside the render pass from Begin to End.
|
// Render command buffer, active inside the render pass from Begin to End.
|
||||||
VkCommandBuffer render_cmd_buffer() const { return render_cmd_buffer_; }
|
VkCommandBuffer render_cmd_buffer() const { return render_cmd_buffer_; }
|
||||||
|
// Copy commands, ran before the render command buffer.
|
||||||
|
VkCommandBuffer copy_cmd_buffer() const { return copy_cmd_buffer_; }
|
||||||
|
|
||||||
// Initializes the swap chain with the given WSI surface.
|
// Initializes the swap chain with the given WSI surface.
|
||||||
bool Initialize(VkSurfaceKHR surface);
|
bool Initialize(VkSurfaceKHR surface);
|
||||||
|
@ -74,6 +79,7 @@ class VulkanSwapChain {
|
||||||
uint32_t surface_height_ = 0;
|
uint32_t surface_height_ = 0;
|
||||||
VkFormat surface_format_ = VK_FORMAT_UNDEFINED;
|
VkFormat surface_format_ = VK_FORMAT_UNDEFINED;
|
||||||
VkCommandPool cmd_pool_ = nullptr;
|
VkCommandPool cmd_pool_ = nullptr;
|
||||||
|
VkCommandBuffer copy_cmd_buffer_ = nullptr;
|
||||||
VkCommandBuffer render_cmd_buffer_ = nullptr;
|
VkCommandBuffer render_cmd_buffer_ = nullptr;
|
||||||
VkRenderPass render_pass_ = nullptr;
|
VkRenderPass render_pass_ = nullptr;
|
||||||
VkSemaphore image_available_semaphore_ = nullptr;
|
VkSemaphore image_available_semaphore_ = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue