Pipelines
prepare
- loadAssets: 加载模型等资源
- prepareUniformBuffers: VulkanDevice中有创建buffer的函数
- updateUniformBuffers:将MVP矩阵写入UniformBuffers
- setupDescriptorSetLayout
- descriptorSetLayoutBinding:绑定UniformBuffers
- vkCreateDescriptorSetLayout:创建DescriptorSetLayout
- vkCreatePipelineLayout:创建PipelineLayout
- preparePipelines
- 准备的 info 有
- VkPipelineInputAssemblyStateCreateInfo
- VkPipelineRasterizationStateCreateInfo
- VkPipelineColorBlendAttachmentState
- VkPipelineColorBlendStateCreateInfo
- VkPipelineDepthStencilStateCreateInfo
- VkPipelineViewportStateCreateInfo
- VkPipelineMultisampleStateCreateInfo
- VkPipelineDynamicStateCreateInfo
- std::array<VkPipelineShaderStageCreateInfo, 2>
- 将上面的 info 绑定到 VkGraphicsPipelineCreateInfo 中
- vkCreateGraphicsPipelines:因为需要渲染三个不同窗口。因此需要创建三个Pipeline。
- 准备的 info 有
// We are using this pipeline as the base for the other pipelines (derivatives)
// Pipeline derivatives can be used for pipelines that share most of their state
// Depending on the implementation this may result in better performance for pipeline
// switching and faster creation time
pipelineCI.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
// Textured pipeline
// Phong shading pipeline
shaderStages[0] = loadShader(getShadersPath() + "pipelines/phong.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getShadersPath() + "pipelines/phong.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.phong));
// All pipelines created after the base pipeline will be derivatives
pipelineCI.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
// Base pipeline will be our first created pipeline
pipelineCI.basePipelineHandle = pipelines.phong;
// It's only allowed to either use a handle or index for the base pipeline
// As we use the handle, we must set the index to -1 (see section 9.5 of the specification)
pipelineCI.basePipelineIndex = -1;
// Toon shading pipeline
shaderStages[0] = loadShader(getShadersPath() + "pipelines/toon.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getShadersPath() + "pipelines/toon.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.toon));
// Pipeline for wire frame rendering
// Non solid rendering is not a mandatory Vulkan feature
if (deviceFeatures.fillModeNonSolid)
{
rasterizationState.polygonMode = VK_POLYGON_MODE_LINE;
shaderStages[0] = loadShader(getShadersPath() + "pipelines/wireframe.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getShadersPath() + "pipelines/wireframe.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.wireframe));
}
- setupDescriptorPool
- vkCreateDescriptorPool: 暂时池的 Size 为 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER=6
- setupDescriptorSet
- VkDescriptorSetAllocateInfo:需要的已准备的资源有
- descriptorPool
- descriptorSetLayout - vkAllocateDescriptorSets:分配池
- vkUpdateDescriptorSets:将资源写入(UniformBuffers)
- VkDescriptorSetAllocateInfo:需要的已准备的资源有
- buildCommandBuffers
- VkRenderPassBeginInfo
- renderPass
- renderArea
- pClearValues = VkClearValue
- loop drawCmdBuffers:drawCmd次数与frameBuffers个数相关,都等于 swapChain.imageCount
- vkBeginCommandBuffer
- vkCmdBeginRenderPass
- vkCmdSetViewport
- vkCmdSetScissor
- vkCmdBindDescriptorSets
- scene.bindBuffers(drawCmdBuffers[i]);
- 三个视窗渲染命令 loop
- vkCmdSetViewport:更新ViewPort
- vkCmdBindPipeline
- scene.draw(drawCmdBuffers[i]);
- vkCmdSetLineWidth:如果是画线可以设置线宽
- drawUI(drawCmdBuffers[i]);
- vkCmdEndRenderPass
- vkEndCommandBuffer
- VkRenderPassBeginInfo
render
- draw
- VulkanExampleBase::prepareFrame()
- vkQueueSubmit:渲染需要提交的是 drawCmdBuffers
- commandBufferCount
- pCommandBuffers = drawCmdBuffers[currentBuffer]
- VulkanExampleBase::submitFrame()
- updateUniformBuffers
小结
从运行程序的结果来看,Pipelines 主要展示如何使用多个VkPipeline来渲染场景。应用场景是:可以将一个场景以不同风格的方式,同时渲染到屏幕上。
Dynamic Uniform Buffers
prepare
- loadAssets: 加载模型等资源
- prepareUniformBuffers: VulkanDevice中有创建buffer的函数
- updateUniformBuffers:将MVP矩阵写入UniformBuffers
- setupDescriptor
- descriptorSetLayoutBinding:绑定UniformBuffers和 sampler
- vkCreateDescriptorSetLayout:创建DescriptorSetLayout
- vkCreateDescriptorPool: 这里比上一节多了一个Pool
- vkAllocateDescriptorSets
- vkUpdateDescriptorSets
- preparePipelines
- vkCreatePipelineLayout:上一节vkCreatePipelineLayout 在 setupDescriptorSetLayout 中
- 准备的 info 有
- VkPipelineInputAssemblyStateCreateInfo
- VkPipelineRasterizationStateCreateInfo
- VkPipelineColorBlendAttachmentState
- VkPipelineColorBlendStateCreateInfo
- VkPipelineDepthStencilStateCreateInfo
- VkPipelineViewportStateCreateInfo
- VkPipelineMultisampleStateCreateInfo
- VkPipelineDynamicStateCreateInfo
- std::array<VkPipelineShaderStageCreateInfo, 2>
- 将上面的 info 绑定到 VkGraphicsPipelineCreateInfo 中
- vkCreateGraphicsPipelines:这里只创建一个 Pipeline
- setupDescriptorPool
- vkCreateDescriptorPool: 暂时池的 Size 为 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER=6
- setupDescriptorSet
- VkDescriptorSetAllocateInfo:需要的已准备的资源有
- descriptorPool
- descriptorSetLayout - vkAllocateDescriptorSets:分配池
- vkUpdateDescriptorSets:将资源写入(UniformBuffers)
- VkDescriptorSetAllocateInfo:需要的已准备的资源有
- buildCommandBuffers
- VkRenderPassBeginInfo
- renderPass
- renderArea
- pClearValues = VkClearValue
- loop drawCmdBuffers:drawCmd次数与frameBuffers个数相关,都等于 swapChain.imageCount
- vkBeginCommandBuffer
- vkCmdBeginRenderPass
- vkCmdBindPipeline:多了一个绑定的pipline
- vkCmdSetViewport
- vkCmdSetScissor
- //vkCmdBindDescriptorSets 这里移到下面
- scene.bindBuffers(drawCmdBuffers[i]);
- loop 物体数量:重点在这里。使用DescriptorSets可以使用不同的uniform或sample渲染同一个物体
- vkCmdBindDescriptorSets
- model.draw(drawCmdBuffers[i]);
- drawUI(drawCmdBuffers[i]);
- vkCmdEndRenderPass
- vkEndCommandBuffer
- VkRenderPassBeginInfo
render
- draw
- VulkanExampleBase::prepareFrame()
- vkQueueSubmit:渲染需要提交的是 drawCmdBuffers
- commandBufferCount
- pCommandBuffers = drawCmdBuffers[currentBuffer]
- VulkanExampleBase::submitFrame()
- updateUniformBuffers
小结
DescriptorSets可以使用不同的uniform或sample渲染同一个物体,这样处理的好处是,如果场景物体相同,可以只加载一个模型,使用 DescriptorSets 小结方式渲染出所有物体。
Descriptor Sets
prepare
- generateCube: 生成模型等资源
- setupVertexDescriptions:绑定模型资源数据 info
- bindingDescriptions
- attributeDescriptions
- pipelineVertexInputStateCreateInfo
- prepareUniformBuffers
- size_t bufferSize = OBJECT_INSTANCES * dynamicAlignment: 获得所需的 buffer size
//没明白这里的作用,暂时理解为判断sizeof(glm::mat4)是否为够minUboAlignment的字节数 相当于alignas(minUboAlignment) size_t minUboAlignment = vulkanDevice->properties.limits.minUniformBufferOffsetAlignment; dynamicAlignment = sizeof(glm::mat4); if (minUboAlignment > 0) { dynamicAlignment = (dynamicAlignment + minUboAlignment - 1) & ~(minUboAlignment - 1); }
- alignedAlloc:对齐分配
- createBuffer:创建 view 矩阵 uniform 和 dynamic 的 uniform
- updateUniformBuffers: 更新 uniform 的数据
- updateDynamicUniformBuffer: 更新 dynamic 的 uniform 数据
- vkFlushMappedMemoryRanges: 刷新映射范围, 即提交更新
- setupDescriptorSetLayout
- 这里注意setLayoutBindings绑定的时候多出一个 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
- setupDescriptorSet
- writeDescriptorSet: 多出一个 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
- preparePipelines
- 多出 VkPipelineDynamicStateCreateInfo 信息
- setupDescriptorPool
- vkCreateDescriptorPool: 多出 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
- setupDescriptorSet
- writeDescriptorSets中 多出 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
- buildCommandBuffers: drawCmdBuffers具体分配 UNIFORM_BUFFER_DYNAMIC 内容
// Render multiple objects using different model matrices by dynamically offsetting into one uniform buffer
for (uint32_t j = 0; j < OBJECT_INSTANCES; j++)
{
// One dynamic offset per dynamic descriptor to offset into the ubo containing all model matrices
uint32_t dynamicOffset = j * static_cast<uint32_t>(dynamicAlignment);
// Bind the descriptor set for rendering a mesh using the dynamic offset
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 1, &dynamicOffset);
vkCmdDrawIndexed(drawCmdBuffers[i], indexCount, 1, 0, 0, 0);
}
render
- draw: 渲染只需更新uniform信息即可
- VulkanExampleBase::prepareFrame()
- vkQueueSubmit:渲染需要提交的是 drawCmdBuffers
- commandBufferCount
- pCommandBuffers = drawCmdBuffers[currentBuffer]
- VulkanExampleBase::submitFrame()
- updateDynamicUniformBuffer()
小结
Dynamic Uniform Buffers:可以使我们自由绑定任意多个 Uniform;应用场景很多。