Vulkan大闷锅之结局

到这里,该创建该准备的,都基本就绪了。接下来就是绘图过程。
如果没有出错,结束的之后,你可以看到这个:

我们先初始化和准备一些信息:

// start command buffer
VkCommandBufferBeginInfo cmd_buf_info = {};
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmd_buf_info.pNext = nullptr;
cmd_buf_info.flags = 0;
cmd_buf_info.pInheritanceInfo = nullptr;

res = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
assert(res == VK_SUCCESS);
//
// init device queue
VkQueue graphics_queue = {};
VkQueue present_queue = {};
vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue);
if (graphics_queue_family_index == present_queue_family_index) {
  present_queue = graphics_queue;
} else {
  vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue);
}

提交数据之前,我们需要显式启用Command Buffer。这里顺便指定提交的队列。
接下来的安全做法是先同步数据:

VkSemaphore imageAcquiredSemaphore;
VkSemaphoreCreateInfo imageAcquiredSemaphoreCreateInfo;
imageAcquiredSemaphoreCreateInfo.sType =
    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
imageAcquiredSemaphoreCreateInfo.pNext = nullptr;
imageAcquiredSemaphoreCreateInfo.flags = 0;

res = vkCreateSemaphore(device, &imageAcquiredSemaphoreCreateInfo, nullptr,
                        &imageAcquiredSemaphore);
assert(res == VK_SUCCESS);
res = vkAcquireNextImageKHR(device, swap_chain, UINT64_MAX,
                            imageAcquiredSemaphore, VK_NULL_HANDLE,
                            &current_buffer);

assert(res == VK_SUCCESS);

这个Semephore用来同步Swapchain中可用的Image。这里还需要一组Clear数据:

VkClearValue clear_values[2];
clear_values[0].color.float32[0] = 0.2f;
clear_values[0].color.float32[1] = 0.2f;
clear_values[0].color.float32[2] = 0.2f;
clear_values[0].color.float32[3] = 0.2f;
clear_values[1].depthStencil.depth = 1.0f;
clear_values[1].depthStencil.stencil = 0;

这里将背景调成了灰色。
接下来显式启用Render Pass:

VkRenderPassBeginInfo rp_begin;
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.pNext = nullptr;
rp_begin.renderPass = render_pass;
rp_begin.framebuffer = framebuffers[current_buffer];
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = WIDTH;
rp_begin.renderArea.extent.height = HEIGHT;
rp_begin.clearValueCount = 2;
rp_begin.pClearValues = clear_values;
//use command buffer created earlier
vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);

这里终于用到了创建已久的Command Buffer。之前创建的组建也可以分别绑定了:

vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
                        pipeline_layout, 0, 1, desc_set.data(), 0, nullptr);
const VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vertex_buffer.buf, offsets);

之前指定的动态数据也可在这里设置:

VkViewport viewport = {};
viewport.height = (float)WIDTH;
viewport.width = (float)HEIGHT;
viewport.minDepth = (float)0.0f;
viewport.maxDepth = (float)1.0f;
viewport.x = 0;
viewport.y = 0;
vkCmdSetViewport(cmd_buf, 0, 1, &viewport);

VkRect2D scissor = {};
scissor.extent.width = WIDTH;
scissor.extent.height = HEIGHT;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdSetScissor(cmd_buf, 0, 1, &scissor);

接下来就是万众期待的绘图了:

vkCmdDraw(cmd_buf, 3 * 2 * 6, 1, 0, 0);

我们的图形是一个长方体,每一面由2个三角组成,6个面,也就是3 * 2 * 6个顶点。
在绘图之后,还需要将数据输出到GUI窗口,在这之前先关闭Command Buffer和提交数据:

// end command
res = vkEndCommandBuffer(cmd_buf);
assert(res == VK_SUCCESS);
// queue command
const VkCommandBuffer cmd_bufs[] = {cmd_buf};
VkFenceCreateInfo fenceInfo;
VkFence drawFence;
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr;
fenceInfo.flags = 0;
vkCreateFence(device, &fenceInfo, nullptr, &drawFence);

VkPipelineStageFlags pipe_stage_flags =
    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info[1] = {};
submit_info[0].pNext = nullptr;
submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info[0].waitSemaphoreCount = 1;
submit_info[0].pWaitSemaphores = &imageAcquiredSemaphore;
submit_info[0].pWaitDstStageMask = &pipe_stage_flags;
submit_info[0].commandBufferCount = 1;
submit_info[0].pCommandBuffers = cmd_bufs;
submit_info[0].signalSemaphoreCount = 0;
submit_info[0].pSignalSemaphores = nullptr;

res = vkQueueSubmit(graphics_queue, 1, submit_info, drawFence);
assert(!res);

接下来Present,输出图形:

VkPresentInfoKHR present;
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.pNext = nullptr;
present.swapchainCount = 1;
present.pSwapchains = &swap_chain;
present.pImageIndices = &current_buffer;
present.pWaitSemaphores = nullptr;
present.waitSemaphoreCount = 0;
present.pResults = nullptr;

do {
  res = vkWaitForFences(device, 1, &drawFence, VK_TRUE, 100000000);
} while (res == VK_TIMEOUT);
assert(res == VK_SUCCESS);
res = vkQueuePresentKHR(present_queue, &present);
assert(res == VK_SUCCESS);

这里的Fence同样是用来同步GPU的数据。
到此Vulkan大闷锅就结束了,但后续还会有相关的博文,敬请关注。

Leave a Reply

Your email address will not be published. Required fields are marked *