我希望我能够尽可能清楚地解释我的问题。我正在开发一个使用 Vulkan 的 Rust 应用程序。
我在创建图形管道时遇到了一些麻烦。我发现了这个问题,但我不知道发生了什么以及为什么发生。
首先让我展示一下什么是有效的。为了创建图形管道,我需要创建一个名为
PipelineViewportStateCreateInfo
的东西。然后我用这个结构(以及其他一些结构)来创建一个 GraphicsPipelineCreateInfo
。
swapchain_extent 的
width
和 height
属性分别设置为 1600 和 1200。
let viewports = [Viewport::builder()
.x(0.0)
.y(0.0)
.width(swapchain_extent.width as f32)
.height(swapchain_extent.height as f32)
.min_depth(0.0)
.max_depth(0.0)
.build()];
let scissors = [Rect2D::builder()
.offset(Offset2D::builder().x(0).y(0).build())
.extent(swapchain_extent)
.build()];
let viewport_state_create_info = PipelineViewportStateCreateInfo::builder()
.scissors(&scissors)
.viewports(&viewports)
.build();
let graphics_pipeline_create_infos = [GraphicsPipelineCreateInfo::builder()
.viewport_state(&viewport_state_create_info)
.build()];
这一切都很完美。
为了使我的代码更加结构化,我创建了一个辅助函数来负责创建
PipelineViewPortStateCreateInfo
:
fn create_viewport_state_create_info(extent: Extent2D) -> PipelineViewportStateCreateInfo {
let viewports = [Viewport::builder()
.x(0.0)
.y(0.0)
.width(extent.width as f32)
.height(extent.height as f32)
.min_depth(0.0)
.max_depth(0.0)
.build()];
let scissors = [Rect2D::builder()
.offset(Offset2D::builder().x(0).y(0).build())
.extent(extent)
.build()];
PipelineViewportStateCreateInfo::builder()
.viewports(&viewports)
.scissors(&scissors)
.build()
}
我从我的其他函数中调用它,如下所示:
let viewport_state_create_info = create_viewport_state_create_info(swapchain_extent);
let graphics_pipeline_create_infos = [GraphicsPipelineCreateInfo::builder()
.viewport_state(&viewport_state_create_info)
.build()];
我没有发现这段代码有问题。然而,当我运行此代码时,Vulkan 验证层向我抛出此错误:
VALIDATION [VUID-VkViewport-width-01770 (-1542042715)]: Validation Error: [ VUID-VkViewport-width-01770 ] | MessageID = 0xa4164ba5 | vkCreateGraphicsPipelines(): pCreateInfos[0].pViewportState->pViewports[0].width (0.000000) is not greater than 0.0. The Vulkan spec states: width must be greater than 0.0
即使
swapchain_extent.width
设置为 1600。
在调试器中我看到它确实是1600,但是当我进入
GraphicsPipelineCreateInfoBuilder
的构建功能时,宽度和高度突然变成0.0🤔
这是范围界定问题吗?如果是的话,编译器不是应该保护我免受它的侵害吗?
是的,您的假设是正确的。这是一个范围界定问题。
问题在于
PipelineViewportStateCreateInfo
保留指向 viewports
和 scissors
的指针(而不是引用)。然而,当 create_viewport_state_create_info()
返回时,viewports
和 scissors
都会被丢弃。所以PipelineViewportStateCreateInfo
中的指针现在无效了。
编译器无法捕捉到这一点的原因。是因为当调用
build()
时,它返回一个不再引用任何生命周期的 PipelineViewportStateCreateInfo
。理论上可以。然而,ask
只是镜像了VkPipelineViewportStateCreateInfo
的定义。
(docs.rs当前已关闭,因此我无法链接到参考文献,稍后我将在其启动时更新答案)