分配指令缓冲

现在,我们可以开始分配指令缓冲对象,使用它记录绘制指令。由于绘制操作是在帧缓冲上进行的,我们需要为交换链中的每一个图像分配一个指令缓冲对象。为此,我们添加了一个数组作为成员变量来存储创建的VkCommandBuffer对象。指令缓冲对象会在指令池对象被清除时自动被清除,不需要我们自己显式地清除它。

std::vector<VkCommandBuffer> commandBuffers;

添加一个叫做createCommandBuffers的函数为交换链中的每一个图像创建指令缓冲对象:

void initVulkan() {
    createInstance();
    setupDebugCallback();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createRenderPass();
    createGraphicsPipeline();
    createFramebuffers();
    createCommandPool();
    createCommandBuffers();
}

        ...

void createCommandBuffers() {
    commandBuffers.resize(swapChainFramebuffers.size());
}

指令缓冲对象可以通过调用vkAllocateCommandBuffers函数分配得到。调用这一函数需要填写VkCommandBufferAllocateInfo结构体来指定分配使用的指令池和需要分配的指令缓冲对象个数:

VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t) commandBuffers.size();

if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
    throw std::runtime_error("failed to allocate command buffers!");
}

level成员变量用于指定分配的指令缓冲对象是主要指令缓冲对象还是辅助指令缓冲对象:

  • VK_COMMAND_BUFFER_LEVEL_PRIMARY:可以被提交到队列进行执行,但不能被其它指令缓冲对象调用。

  • VK_COMMAND_BUFFER_LEVEL_SECONDARY:不能直接被提交到队列进行执行,但可以被主要指令缓冲对象调用执行。

在这里,我们没有使用辅助指令缓冲对象,但辅助治理给缓冲对象的好处是显而易见的,我们可以把一些常用的指令存储在辅助指令缓冲对象,然后在主要指令缓冲对象中调用执行。