管线动态状态

概述

创建图形 VkPipeline 对象时,设置状态的逻辑流程是

// Using viewport state as an example
VkViewport viewport = {0.0, 0.0, 32.0, 32.0, 0.0, 1.0};

// Set value of state
VkPipelineViewportStateCreateInfo viewportStateCreateInfo;
viewportStateCreateInfo.pViewports = &viewport;
viewportStateCreateInfo.viewportCount = 1;

// Create the pipeline with the state value set
VkGraphicsPipelineCreateInfo pipelineCreateInfo;
pipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
vkCreateGraphicsPipelines(pipelineCreateInfo, &pipeline);

vkBeginCommandBuffer();
// Select the pipeline and draw with the state's static value
vkCmdBindPipeline(pipeline);
vkCmdDraw();
vkEndCommandBuffer();

VkPipeline 使用 动态状态 时,一些管线信息可以在创建时省略,而是在记录命令缓冲区期间设置。新的逻辑流程是

// Using viewport state as an example
VkViewport viewport = {0.0, 0.0, 32.0, 32.0, 0.0, 1.0};
VkDynamicState dynamicState = VK_DYNAMIC_STATE_VIEWPORT;

// not used now
VkPipelineViewportStateCreateInfo viewportStateCreateInfo;
viewportStateCreateInfo.pViewports = nullptr;
// still need to say how many viewports will be used here
viewportStateCreateInfo.viewportCount = 1;

// Set the state as being dynamic
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo;
dynamicStateCreateInfo.dynamicStateCount = 1;
dynamicStateCreateInfo.pDynamicStates = &dynamicState;

// Create the pipeline with state value not known
VkGraphicsPipelineCreateInfo pipelineCreateInfo;
pipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
pipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
vkCreateGraphicsPipelines(pipelineCreateInfo, &pipeline);

vkBeginCommandBuffer();
vkCmdBindPipeline(pipeline);
// Set the state for the pipeline at recording time
vkCmdSetViewport(viewport);
vkCmdDraw();
viewport.height = 64.0;
// set a new state value between draws
vkCmdSetViewport(viewport);
vkCmdDraw();
vkEndCommandBuffer();

何时使用动态状态

Vulkan 是一种工具,所以和大多数事物一样,没有一个确定的答案。

某些实现可能会在使用某些 VkDynamicState 状态而不是静态值时出现性能损失,但动态状态可能会阻止应用程序不得不创建许多管线对象的排列组合,这可能是应用程序更大的需求。

动态状态生命周期

规范讨论了 动态状态生命周期。以下是一些例子,可以最好地描述它

// example 1 - valid
vkCmdSetViewport()
vkCmdBindPipeline() // static state
vkCmdDraw()

// example 2 - valid
vkCmdBindPipeline() // static state
vkCmdSetViewport()
vkCmdBindPipeline() // dynamic state
vkCmdDraw()

// example 3 - invalid (VUID-vkCmdDraw-None-07831)
vkCmdBindPipeline() // static state
vkCmdBindPipeline() // dynamic state
vkCmdDraw()

// example 4 - invalid (VUID-vkCmdDraw-None-08608)
vkCmdBindPipeline() // dynamic state
vkCmdBindPipeline() // static state
vkCmdSetViewport()
vkCmdDraw()

// example 5 - invalid (VUID-vkCmdDraw-None-07831)
vkCmdSetViewport()
vkCmdBindPipeline() // static state
vkCmdBindPipeline() // dynamic state
vkCmdDraw()

// example 6 - invalid (VUID-vkCmdDraw-None-07831)
vkCmdSetViewport()
vkCmdBindPipeline() // static state
vkCmdDraw()
vkCmdBindPipeline() // dynamic state
vkCmdDraw()

哪些状态是动态的

可以在 VkDynamicState 中找到所有可能的动态状态的完整列表。

添加 VK_EXT_extended_dynamic_stateVK_EXT_extended_dynamic_state2VK_EXT_extended_dynamic_state3VK_EXT_vertex_input_dynamic_stateVK_EXT_attachment_feedback_loop_dynamic_stateVK_EXT_color_write_enable 扩展的目的是为了支持需要减少它们编译和绑定的管线状态对象数量的应用程序。