[Vulkan] Initialize wgpu objects from raw handles#1609
[Vulkan] Initialize wgpu objects from raw handles#1609bors[bot] merged 1 commit intogfx-rs:masterfrom
Conversation
I think it's OK as long as it's native-only, and it's
This should be nicer once @pythonesque work is finished.
No. Merging them together would make a big mess. It is a very nice boundary between platform-agnostic and platform-specific code right now. |
wgpu-core/src/instance.rs
Outdated
|
|
||
| pub fn from_hal<A: HalApi>(name: &str, raw_instance: A::Instance) -> Self { | ||
| #[cfg(vulkan)] | ||
| let mut vulkan_instance = None; |
There was a problem hiding this comment.
can probably start with let mut this = Self::default() and mutate it, to save a ton of lines
There was a problem hiding this comment.
Ok. The problem I was having here, is that <A as hal::api::Api>::Instance cannot be converted to hal::api::Vulkan::Instance. I'm confused since wgc::Instance::new() seems so be doing just that.
There was a problem hiding this comment.
What I'm thinking is:
let mut this = Self::default();
this.name = name.to_string();
match A::VARIANT {
...
}
Ok(this)There was a problem hiding this comment.
it seems that the problem is that matching by VARIANT doesn't actually constrain the type A. Maybe this could be fixed with full const generics but we don't have that yet. For now I can wrap hal::Instance into an enum.
There was a problem hiding this comment.
right, we can't have this method as generic over A
There was a problem hiding this comment.
hmm, or maybe we can. There is get_surface_mut, which works with generic A. Something similar can be done for instances
There was a problem hiding this comment.
I tried a few more type manipulations but still no luck. The enum solution works.
There was a problem hiding this comment.
I did it, at least I think I did what you suggested. I used the HalApi trait to convert from hal to wgc instance (while get_surface_mut converts a wgc swapchain to hal).
That is good news 🙂 |
kvark
left a comment
There was a problem hiding this comment.
So this is needed for VR, right? Would using VR in any other backend require to pass in a raw hal::Instance to wgpu?
It seems to me that this way of initialization is Vulkan-only, and so we shouldn't try to generalize it (right now).
Yes, most of the code will be reused between backends. |
|
Interesting!
But the current PR passes in |
I just started writing this PR. It still needs support for creating the Adapter, Device, and Texture. I opened this draft PR to get early feedback. (maybe I was not completely clear in the OP). If you are referring specifically to the Another note: while for bevy support we don't need to store the adapter, the wgpu Device requires the AdapterId handle, so we need to construct the adapter (always from the hal objects). |
|
I added support for creating the adapter and device. For creating the device there is some code duplication in wgpu and wgpu-core because I wasn't sure how to rearrange the code.
|
It's a generic abstraction over the fact that some |
|
Thanks! |
|
The code is more or less done, it still needs testing (I don't have an ETA, it depends on various factors). I'm not happy with the |
703a011 to
943a795
Compare
|
The PR is ready for review. I tested this on the Oculus Quest using this modified sample. The drop-safety mechanism seems to work as intended. In the example I linked, there is still the need for dropping some objects manually, but this is because the openxrs crate also needs some sort of drop-safety mechanism. Basically the drop order that must be enforced is: (wgpu textures) --(1)--> (xr swapchain, xr session) --(2)--> (wgpu device, wgpu instance) --(3)--> (xr instance). (1) and (3) are enforced automatically by this PR, (2) is enforced manually in the example. I haven't cleaned up the Global methods but I think that once hubs and inputs are removed they will slim down by their own. |
kvark
left a comment
There was a problem hiding this comment.
We chatted about this on Bevy's discord and agreed that generally this is the only way to go. Just some details to polish are left.
wgpu-core/src/device/mod.rs
Outdated
| } | ||
|
|
||
| fn create_texture( | ||
| fn texture_from_hal( |
There was a problem hiding this comment.
nit: let's start methods with a verb, unless they don't do anything (e.g. pure accessors)
This one can be create_texture_from_hal or create_texture_impl
wgpu-core/src/device/mod.rs
Outdated
| hal_texture: A::Texture, | ||
| self_id: id::DeviceId, | ||
| adapter: &crate::instance::Adapter<A>, | ||
| hal_usage: hal::TextureUses, |
There was a problem hiding this comment.
If we are passing the desc anyway, why do we need to pass hal_usage separately? Is there a problem with just computing the hal_usage based on the desc.usage?
wgpu-core/src/device/mod.rs
Outdated
| /// | ||
| /// - `hal_texture` must be created from `device_id` correspnding raw handle. | ||
| /// - `hal_texture` must be created respecting `desc` | ||
| pub unsafe fn texture_from_hal<A: HalApi>( |
wgpu-core/src/device/mod.rs
Outdated
|
|
||
| /// # Safety | ||
| /// | ||
| /// - `hal_texture` must be created from `device_id` correspnding raw handle. |
| if let Some(ref trace) = device.trace { | ||
| trace | ||
| .lock() | ||
| .add(trace::Action::CreateTexture(fid.id(), desc.clone())); |
There was a problem hiding this comment.
let's add a note/todo about the fact the replay isn't going to be able to see the external changes
wgpu-core/src/hub.rs
Outdated
|
|
||
| pub trait HalApi: hal::Api { | ||
| const VARIANT: Backend; | ||
| fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; |
wgpu-core/src/instance.rs
Outdated
| } | ||
|
|
||
| fn create_device( | ||
| fn device_from_open( |
wgpu-hal/src/vulkan/device.rs
Outdated
|
|
||
| pub fn image_raw_flags(desc: &crate::TextureDescriptor) -> vk::ImageCreateFlags { | ||
| let mut raw_flags = vk::ImageCreateFlags::empty(); | ||
| if desc.dimension == wgt::TextureDimension::D2 && desc.size.depth_or_array_layers % 6 == 0 { |
There was a problem hiding this comment.
this is a dirty hack, but we still need to do our best
let's also check for width == height here
wgpu-hal/src/vulkan/device.rs
Outdated
| }) | ||
| } | ||
|
|
||
| pub fn image_raw_flags(desc: &crate::TextureDescriptor) -> vk::ImageCreateFlags { |
There was a problem hiding this comment.
actually, how about not exposing this at all? I don't think XR cares about cube views, anyway. This function is a hack, and hacks should ideally stay private
wgpu-hal/src/vulkan/mod.rs
Outdated
| pub struct Texture { | ||
| raw: vk::Image, | ||
| handle_is_external: bool, | ||
| _drop_guard: DropGuard, |
There was a problem hiding this comment.
can we combine these two? something like external_drop: Option<DropGuard>
|
I implemented your suggestions. I didn't have the time to throughly test the last commit. If you need anything else I will be available in a couple of days. |
kvark
left a comment
There was a problem hiding this comment.
Thank you! Please squash the commits
4b37b28 to
2657849
Compare
|
Rebased |
|
Build succeeded: |
Connections
This PR is a successor of gfx-rs/gfx#3762
Description
The
handle_is_externalflag mechanism was not enough to ensure safety, when for example the Instance is wrapped inArc<>and a library cannot keep track of all its clones. This is the case with the bevy render rewrite. The solution was to let wgpu be in charge of destroying the handles, but it also has to keep a reference to a "drop guard" which is always dropped after the handle is destroyed. For the OpenXR integration, this drop guard will bexr::Instance.For now this is just a proof of concept. Only instance creation is handled, and there is even type error in
wgc::Instance::from_hal().I have a few concerns:
hal::Instancefrom the wgpu crate? Or should the user pass all the parameters sohal::Instancecan be constructed internally? This second options is more disruptive, since the wgpu-types crate would need to import all platform-specific crates to define the structure/enum to hold the raw handles.hal::Instance, there are 4 indirection calls to save the raw instance. Can this be optimized in any way?Do you think it is possible to merge wgpu-hal into wgpu-core? This could help with reducing the distance from the surface level API to the platform specific APIs even more.
Testing
Vulkan/Android (Oculus Quest) using this sample.