Vulkan学习--5.创建命令缓冲区

基本命令缓冲区操作

在其他图形API中,应用程序可以通过进行API调用来设置诸如线宽之类的属性glLineWidth()。在幕后,驱动程序将此API调用转换为特定于GPU的命令,并将命令放入命令缓冲区。驱动程序还通过在应用程序视图之外创建和销毁命令缓冲区来管理命令缓冲区。最终,驱动程序将命令缓冲区“提交”到GPU以处理命令。

在Vulkan中,您创建一个命令缓冲区并进行类似的Vulkan API调用vkCmdSetLineWidth()以向命令缓冲区添加命令。由于每个GPU都有自己的“指令集”,因此驱动程序仍需要做一些工作来生成GPU特定的指令来设置线宽。
在这里插入图片描述
这里,驱动程序确定要插入命令缓冲区的适当二进制GPU指令,以指示GPU使用5的线宽来绘制后续行。您不需要查看实际的命令缓冲区内容,因为驱动程序正在为您执行这部分GPU编程。

命令缓冲池

由于创建和销毁单个命令缓冲区可能很昂贵,因此Vulkan使用命令缓冲池来管理命令缓冲区。使用命令缓冲池的动机包括:
1.某些应用程序使用短命令命令缓冲区,这意味着它们经常被创建和销毁。专用池分配器通常可以更有效地处理这些分配模式。
2.命令缓冲区内存的特殊之处在于它必须对CPU和GPU都可见。在许多系统中,内存到处理器(CPU或GPU)的映射只能使用大粒度来完成,这意味着小的命令缓冲区可能会浪费大量内存。
3.内存映射很昂贵,因为它通常涉及修改页表和使TLB缓存无效。最好映射一个较大的命令缓冲池并在其中分配单个命令缓冲区,而不是单独映射每个命令缓冲区。

命令缓冲池和队列系列
驱动程序使用适合于读取命令缓冲存储器的GPU硬件的内存分配属性来分配命令缓冲池。此类属性的示例包括内存对齐要求和缓存行为。

如果GPU硬件中存在多个硬件队列(如物理设备队列系列所述),则驱动程序可能需要分配具有不同内存分配属性的命令缓冲池,这些属性特定于每个GPU硬件队列。只要驱动程序知道包含命令缓冲区将使用的队列的队列系列,驱动程序就会为您处理这些详细信息。

使用命令缓冲区
创建命令缓冲区后,通过调用开始“录制” vkBeginCommandBuffer()。调用此函数会将命令缓冲区置于“记录”状态,并允许您调用将命令插入命令缓冲区的许多“vkCmd *”函数之一。您已经vkCmdSetLineWidth()在本节中看到了此示例。另一个例子是vkCmdDraw(),它告诉GPU绘制一些顶点。当您完成将命令插入命令缓冲区后,您将调用 vkEndCommandBuffer()以指示您已完成并将命令缓冲区从记录状态中取出并使其可供使用。

您将在后面的部分中看到实际填充命令缓冲区的代码。

完成命令缓冲区记录不会使GPU做任何事情。为了让GPU处理命令缓冲区,您必须使用它将其提交到GPU的队列中vkQueueSubmit()。在向GPU提交命令缓冲区之前,还有很多事情需要设置,这将在本教程的最后一节中进行

创建命令缓冲区

    ///5.创建命令缓冲区
    //使用创建设备时要使用的队列
    //实际上,您必须为应用程序打算使用的每个唯一队列系列创建命令缓冲池。
    //由于在创建设备时仅指定了一个队列系列,因此一个命令缓冲池足以满足这些样本的要求
    uint32_t graphics_queue_family_index=queue_info.queueFamilyIndex;
    //命令缓冲池只能与一个队列系列相关联,构建命令缓冲区信息
    VkCommandPoolCreateInfo cmd_pool_info = {};
    cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    cmd_pool_info.pNext = NULL;
    //指定队列系列索
    cmd_pool_info.queueFamilyIndex = graphics_queue_family_index;
    cmd_pool_info.flags = 0;
    VkCommandPool cmd_pool;
    //创建命令缓冲池
    res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &cmd_pool);
    assert(res == VK_SUCCESS);

    //从命令缓冲池中分配命令缓冲区
    VkCommandBufferAllocateInfo cmd = {};
    cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    cmd.pNext = NULL;
    cmd.commandPool = cmd_pool;
    cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    cmd.commandBufferCount = 1;//个数
    VkCommandBuffer cmdBuffer;
    //创建命令缓冲区
    res = vkAllocateCommandBuffers(device, &cmd, &cmdBuffer);
    assert(res == VK_SUCCESS);

    VkCommandBuffer cmd_bufs[1] = {cmdBuffer};
    vkFreeCommandBuffers(device, cmd_pool, 1, cmd_bufs);//释放资源
    vkDestroyCommandPool(device, cmd_pool, NULL);//销毁资源

原文url:https://vulkan.lunarg.com/doc/sdk/1.1.101.0/windows/tutorial/html/03-init_device.html

猜你喜欢

转载自blog.csdn.net/yuxing55555/article/details/88870428
今日推荐