Vulkan Samples 阅读 -- Basics(二): Pipelines & Descriptor Sets & Dynamic Uniform Buffers

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。
		// 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)
  • 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

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)
  • 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

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;应用场景很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值