vulkan学习笔记十九

创建指令缓冲对象VkCommandBuffer

在之前的内容中,已经创建好了顶点、加载图片,现在可以创建VkCommandBuffer了,每一帧的绘制命令需要记录到VkCommandBuffer上。

先在SceneWidget.h中添加一个函数bool CreateCommandBuffers()进行创建操作,并添加成员变量std::vector<VkCommandBuffer> m_commandBuffers,保存每帧的VkCommandBuffer对象。

在SceneWidget.cpp文件中实现bool CreateCommandBuffers(),

先对m_commandBuffers进行空间分配,由于是记录的每帧对应的VkCommandBuffer对象,所以这里,可以使用m_frameBuffers的数量来进行分配:

m_commandBuffers.resize(m_frameBuffers.size()).

VkCommandBuffer的创建是通过vkAllocateCommandBuffers函数来申请空间。调用vkAllocateCommandBuffers并判断返回值:

VkResult result = vkAllocateCommandBuffers();函数其参数如下:

第一个参数:逻辑设备m_device

第二个参数:VkCommandBufferAllocateInfo结构的指针,所以需定义变量VkCommandBufferAllocateInfo allocateInfo = {};传入& allocateInfo

第三个参数:需要申请空间的VkCommandBuffer数组,这里是m_commandBuffers.data()

补齐allocateInfo的属性

固定写法

allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;

allocateInfo.pNext = nullptr;

之前创建的commandPool

allocateInfo.commandPool = m_commandPool;

这个demo里没有VK_COMMAND_BUFFER_LEVEL_SECONDARY。

allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;

要申请的VkCommandBuffer的数目

allocateInfo.commandBufferCount = m_commandBuffers.size();

对m_commandBuffers进行循环,在每次的循环中进行命令的记录。

记录时,调用vkBeginCommandBuffer函数,重置命令缓冲对象,此函数参数:

第一个参数:对应的m_commandBuffers[i],要记录命令的VkCommandBuffer

第二个参数:VkCommandBufferBeginInfo类型的对象指针。所以需要定义一个变量:VkCommandBufferBeginInfo beginInfo = {};

beginInfo属性赋值:

固定写法

beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;;

保持默认

beginInfo.pNext = nullptr;

beginInfo.flags = 0;

beginInfo.pInheritanceInfo = nullptr;

下面开始渲染流程,调用vkCmdBeginRenderPass函数,开始一个渲染流程。其参数:

第一个参数:m_commandBuffers[i]

第二个参数:VkRenderPassBeginInfo类型的变量renderPassInfo = {},输入引用。

第三个参数:VkSubpassContents枚举类型,其值为:VK_SUBPASS_CONTENTS_INLINE将命令嵌入到主命令,不执行辅助命令。

renderPassInfo属性赋值:

固定写法

renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;

renderPassInfo.pNext = nullptr;

之前创建过的。

renderPassInfo.renderPass = m_renderPass;

对应的帧缓存

renderPassInfo.framebuffer = m_frameBuffers[i];

不偏移

renderPassInfo.renderArea.offset = {0, 0};

当前的窗口大小

renderPassInfo.renderArea.extent = m_capabilities.currentExtent;

需要补一个std::vector<VkClearValue> clearValues的变量,存清除的颜色,类似于openGL中的背景色。

renderPassInfo.clearValueCount = clearValues.size();

给深度赋初始值

renderPassInfo.pClearValues = clearValues.data();

clearValues的值:

设置背景色

VkClearValue clearColor = {0.5f, 0.3f, 0.1f, 0.0f};

重置深度

VkClearValue clearDepth = {1.0f, 0.0f};

绑定之前创建的pipeline调用vkCmdBindPipeline函数,其参数:

第一个参数:m_commandBuffers[i],

第二个参数:作用到图形管线 VK_PIPELINE_BIND_POINT_GRAPHICS,

第三个参数:m_graphicsPipeline,使用之前创建好的。

绑定vertexBuffer调用 vkCmdBindVertexBuffers函数,其参数:

第一个参数:m_commandBuffers[i]

第二个参数:vertexBuffer可能有多个,从第几个开始,这里是0

第三个参数:从开始位置起用几个buffer,这里是1

第四个参数:vertexBuffer的指针。对于这个demo,这里可直接写&m_vertexBuffer。

第五个参数:数据在数组中的偏移,这里是一个VkDeviceSize类型的指针,所以需要定义一个VkDeviceSize offset = 0,并填入&offset。

绑定描述符集vkCmdBindDescriptorSets,函数参数:

第一个参数:m_commandBuffers[i]

第二个参数:绑定到graphics上,VK_PIPELINE_BIND_POINT_GRAPHICS

第三个参数:之前创建的m_pipelineLayout

第四个参数:第一个VkDescriptorSet的索引,0

第五个参数:DescriptorSet的数量

第六个参数:DescriptorSet的数组指针

第七个参数:不需要偏移数组,所以为0

第八个参数:动态偏移数组,不需要。nullptr

调用绘制函数,进行绘制,绘制方式有两种,一种是根据真实的顶点数据,进行绘制,一种是根据索引,在顶点数据中查找数据进行绘制。

在这个demo,没有输入索引数据,所以按顶点数据进行绘制。

调用vkCmdDraw进行顶点的绘制,其参数:

第一个参数:m_commandBuffers[i]

第二个参数:顶点的数量m_vertexs.size()

第三个参数:教程中说明这个参数为要渲染的instance,没有时,写1.这里写1

第四个参数:第一个顶点的索引,这里写0

第五个参数:第一个instance的索引,这里写0

到这里已经渲染完了,所以要结束渲染vkCmdEndRenderPass(m_commandBuffers[i])

然后结束命令缓存的记录vkEndCommandBuffer(m_commandBuffers[i])之前调用的vkCmd开始的函数,都返回void类型的,而这个vkEndCommandBuffer是有返回值,所以还是要判断一下有没有执行成功。

在SceneWidget::Init中添加调用,并在SceneWidget::UnInit中添加清理函数。

vkFreeCommandBuffers(m_device, m_commandPool, m_commandBuffers.size(), m_commandBuffers.data());

最后执行一下程序,看一下结果

没有报错。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值