简体   繁体   中英

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.

A surface, as far as I understand, is an abstraction of the windows/places images are displayed returned by your window software.

In vulkan you have a VkSurface (returned by your window software, ie GLFW), which has certain properties

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.

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. 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.

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? , 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?

Swapchain's however have a 1:1 relationship with surfaces. 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.

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. 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.

So if you want your surface class to store a swapchain, your API needs a way for the user to create a swapchain.

In short, your goal is wrong; users need the function you're trying to get rid of.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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