简体   繁体   English

处理 C++ 中 vulkan 的设备、表面和交换链中 object 生命周期的第 22 个问题?

[英]Dealing with the catch 22 of object lifetimes in vulkan's device, surface, and swapchain in C++?

Background:背景:

In order to even display to the screen you need to enable a "KHR" (khronos group extension) extension for presentation surfaces.为了在屏幕上显示,您需要为演示表面启用“KHR”(khronos 组扩展)扩展。

A surface, as far as I understand, is an abstraction of the windows/places images are displayed returned by your window software.据我了解,表面是 window 软件返回的窗口/位置图像的抽象。

In vulkan you have a VkSurface (returned by your window software, ie GLFW), which has certain properties在 vulkan 中,您有一个 VkSurface(由您的 window 软件返回,即 GLFW),它具有某些属性

These properties are needed in order to know if a Device is compatible with it.需要这些属性才能知道设备是否与其兼容。 In other words, before a VkDevice is created (the actual logical view of the GPU which you can actually use to submit commands to), it needs to know about the Surface if you are going to use it, specifically in order to create a device with presentation queues that support that surface with the properties it has.换句话说,在创建 VkDevice 之前(实际可以用来提交命令的 GPU 的实际逻辑视图),如果要使用它,它需要了解 Surface,特别是为了创建设备具有支持该表面及其具有的属性的表示队列。

Once the device is created, you can create the swapchain, which is basically a series of buffers/attachments you actually use to render to.创建设备后,您可以创建交换链,它基本上是您实际用于渲染的一系列缓冲区/附件。

Swapchain's however have a 1:1 relationship with surfaces.然而,交换链与表面具有 1:1 的关系。 There can only ever be a single swapchain per surface at max.每个表面最多只能有一个交换链。

Problem:问题:

This is where I start running into issues.这是我开始遇到问题的地方。 In my code-base, I codify this relationship in a member variable .在我的代码库中,我将这种关系编码在一个成员变量中。 A surface has a swapchain, which guarantees that you as the programmer can't accidentally create multiple swapchains per surface if you use my wrapper.一个表面有一个交换链,如果你使用我的包装器,它可以保证你作为程序员不会意外地为每个表面创建多个交换链。

But, if we use this abstraction the following happens:但是,如果我们使用这种抽象,会发生以下情况:

my::Surface surface = window.create_surface(...); //VkSurface wrapper
auto queue_family = physical_device.find_queue_family_that_matches(surface,...); 
auto queue_create_list = {{queue_family, priority},...}; 
my::Device device = physical_device.create_device(...,queue_create_list,...);
my::swapchain_builder.swapchain_builder(device); 
 swapchain_builder.builder_pattern_x(...).builder_pattern_x(...)....; 

surface.create_swapchain(swapchain_builder); 

...
render loop{
}
...
//end of program
return 0; 

//ERROR! device no longer exists to destroy swapchain!
}

Because the surface is created before the device, and because the swapchain is a member of the surface, on destruction the device is destroyed before the swapchain.因为表面是在设备之前创建的,并且因为交换链是表面的成员,所以在销毁时,设备在交换链之前被销毁。

The "solution" I came up with in the mean time was this:我同时提出的“解决方案”是这样的:

my::Device device; //device default constructible, but becomes a VK_NULL_HANDLE underneath
my::Surface surface = ...;
...
device = physical_device.create_device(...,queue_create_list,...);
...
surface.create_swapchain(swapchain_builder);

And this certainly works.这当然有效。 The surface is destroyed before the device is, and thus so is the swapchain.表面在设备之前被破坏,因此交换链也是如此。 But it leaves a bad taste in my mouth.但它在我的嘴里留下了不好的味道。

The whole reason I made swapchain a member was to eliminate bugs caused by multiple swapchains being created, my eliminating the option for the bug to exist in the first place, and remove the need for the user to think about the Vulkan Spec by encoding that requirement into my wrapper itself.我让交换链成为成员的全部原因是为了消除由创建多个交换链引起的错误,我首先消除了错误存在的选项,并消除了用户通过编码该要求来考虑 Vulkan 规范的需要进入我的包装本身。

But Now the user has to remember to default initialize the device first... or they will get an esoteric error (not as good as the one I show here) unless they use validation layers.但是现在用户必须记住首先默认初始化设备......否则他们会得到一个深奥的错误(不如我在这里展示的那么好),除非他们使用验证层。

Question:问题:

Is there some way to encode this object relationship at compile time with out runtime declaration order issues?有没有办法在编译时编码这个 object 关系而没有运行时声明顺序问题? , is there maybe a better way to codify a 1:1 relationship in this scenario, such that the surface object could exist on it's own and RAII order would handle this? ,在这种情况下是否有更好的方法来编码 1:1 关系,这样表面 object 可以自己存在并且 RAII 订单可以处理这个问题?

Swapchain's however have a 1:1 relationship with surfaces.然而,交换链与表面具有 1:1 的关系。 There can only ever be a single swapchain per surface at max.每个表面最多只能有一个交换链。

That is not true.不是真的。 From the standard : 从标准

A native window cannot be associated with more than one non-retired swapchain at a time.原生 window一次不能与多个非退休交换链关联。

You can create multiple swapchains for a surface.您可以为一个表面创建多个交换链。 However, when you create a new one, you have to provide the old one, and the old one becomes "retired".但是,当您创建一个新的时,您必须提供旧的,而旧的会“退休”。 Images you have previously acquired from the retired swapchain can still be presented, but you cannot acquire images more from the swapchain.您之前从已停用的交换链中获取的图像仍然可以显示,但您无法从交换链中获取更多图像。

This moves nicely into the next point: the user needs to be able to recreate the swapchain for a surface.这很好地进入了下一点:用户需要能够为表面重新创建交换链。

Swapchains can become invalid, perhaps due to user rescaling of a window or other things.交换链可能会变得无效,这可能是由于用户重新调整 window 或其他原因。 When this happens, the user needs to recreate them.发生这种情况时,用户需要重新创建它们。 Whether you retire the old one or not, you're going to have to call the function to create one.无论您是否淘汰旧的,您都必须调用 function 来创建一个。

So if you want your surface class to store a swapchain, your API needs a way for the user to create a swapchain.所以如果你想让你的表面 class 存储一个交换链,你的 API需要一种方法让用户创建一个交换链。

In short, your goal is wrong;简而言之,你的目标是错误的; users need the function you're trying to get rid of.用户需要您尝试摆脱的 function。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM