Add a specialized copy command buffer to the vulkan swap chain

This commit is contained in:
Dr. Chat 2016-03-10 12:59:48 -06:00
parent 86cb40f0c6
commit f839a1293f
2 changed files with 56 additions and 21 deletions

View File

@ -187,6 +187,10 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &render_cmd_buffer_);
CheckResult(err, "vkCreateCommandBuffer");
// Create another command buffer that handles image copies.
err = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &copy_cmd_buffer_);
CheckResult(err, "vkCreateCommandBuffer");
// Create the render pass used to draw to the swap chain.
// The actual framebuffer attached will depend on which image we are drawing
// into.
@ -194,7 +198,7 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
color_attachment.flags = 0;
color_attachment.format = surface_format_;
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.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@ -388,6 +392,7 @@ bool VulkanSwapChain::Begin() {
// Reset all command buffers.
vkResetCommandBuffer(render_cmd_buffer_, 0);
vkResetCommandBuffer(copy_cmd_buffer_, 0);
auto& current_buffer = buffers_[current_buffer_index_];
// 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);
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;
pre_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
pre_image_memory_barrier.pNext = nullptr;
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.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.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
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.baseArrayLayer = 0;
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,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &pre_image_memory_barrier);
// 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;
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
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.extent.width = surface_width_;
render_pass_begin_info.renderArea.extent.height = surface_height_;
render_pass_begin_info.clearValueCount =
static_cast<uint32_t>(xe::countof(clear_values));
render_pass_begin_info.pClearValues = clear_values;
render_pass_begin_info.clearValueCount = 0;
render_pass_begin_info.pClearValues = nullptr;
vkCmdBeginRenderPass(render_cmd_buffer_, &render_pass_begin_info,
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
@ -458,6 +480,7 @@ bool VulkanSwapChain::End() {
vkCmdEndRenderPass(render_cmd_buffer_);
// 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;
post_image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
post_image_memory_barrier.pNext = nullptr;
@ -483,14 +506,20 @@ bool VulkanSwapChain::End() {
auto err = vkEndCommandBuffer(render_cmd_buffer_);
CheckResult(err, "vkEndCommandBuffer");
err = vkEndCommandBuffer(copy_cmd_buffer_);
CheckResult(err, "vkEndCommandBuffer");
VkCommandBuffer command_buffers[] = {copy_cmd_buffer_, render_cmd_buffer_};
// Submit rendering.
VkSubmitInfo render_submit_info;
render_submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
render_submit_info.pNext = nullptr;
render_submit_info.waitSemaphoreCount = 0;
render_submit_info.pWaitSemaphores = nullptr;
render_submit_info.commandBufferCount = 1;
render_submit_info.pCommandBuffers = &render_cmd_buffer_;
render_submit_info.commandBufferCount =
static_cast<uint32_t>(xe::countof(command_buffers));
render_submit_info.pCommandBuffers = command_buffers;
render_submit_info.signalSemaphoreCount = 0;
render_submit_info.pSignalSemaphores = nullptr;
{

View File

@ -35,11 +35,16 @@ class VulkanSwapChain {
uint32_t surface_width() const { return surface_width_; }
uint32_t surface_height() const { return surface_height_; }
VkImage surface_image() const {
return buffers_[current_buffer_index_].image;
}
// Render pass used for compositing.
VkRenderPass render_pass() const { return render_pass_; }
// Render command buffer, active inside the render pass from Begin to End.
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.
bool Initialize(VkSurfaceKHR surface);
@ -74,6 +79,7 @@ class VulkanSwapChain {
uint32_t surface_height_ = 0;
VkFormat surface_format_ = VK_FORMAT_UNDEFINED;
VkCommandPool cmd_pool_ = nullptr;
VkCommandBuffer copy_cmd_buffer_ = nullptr;
VkCommandBuffer render_cmd_buffer_ = nullptr;
VkRenderPass render_pass_ = nullptr;
VkSemaphore image_available_semaphore_ = nullptr;