-
Notifications
You must be signed in to change notification settings - Fork 946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Vulkan] Initialize wgpu objects from raw handles #1609
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
@@ -118,6 +118,46 @@ impl Instance { | |||
} | |||
} | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, we can't have this method as generic over A
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried a few more type manipulations but still no luck. The enum solution works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -517,10 +517,12 @@ impl<A: HalApi> Device<A> { | |||
}) | |||
} | |||
|
|||
fn create_texture( | |||
fn texture_from_hal( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
self_id: id::DeviceId, | ||
adapter: &crate::instance::Adapter<A>, | ||
hal_usage: hal::TextureUses, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, need a verb
wgpu-core/src/device/mod.rs
Outdated
@@ -2976,6 +2987,64 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> { | |||
(id, Some(error)) | |||
} | |||
|
|||
/// # Safety | |||
/// | |||
/// - `hal_texture` must be created from `device_id` correspnding raw handle. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo "correspnding"
if let Some(ref trace) = device.trace { | ||
trace | ||
.lock() | ||
.add(trace::Action::CreateTexture(fid.id(), desc.clone())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -933,13 +949,21 @@ impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> { | |||
|
|||
pub trait HalApi: hal::Api { | |||
const VARIANT: Backend; | |||
fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also naming concern
wgpu-core/src/instance.rs
Outdated
@@ -248,9 +249,10 @@ impl<A: HalApi> Adapter<A> { | |||
} | |||
} | |||
|
|||
fn create_device( | |||
fn device_from_open( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be create_device_from_hal
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -535,6 +535,40 @@ impl super::Device { | |||
config: config.clone(), | |||
}) | |||
} | |||
|
|||
pub fn image_raw_flags(desc: &crate::TextureDescriptor) -> vk::ImageCreateFlags { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -257,6 +260,8 @@ pub struct Buffer { | |||
#[derive(Debug)] | |||
pub struct Texture { | |||
raw: vk::Image, | |||
handle_is_external: bool, | |||
_drop_guard: DropGuard, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Please squash the commits
4b37b28
to
2657849
Compare
Rebased |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bors r+
Build succeeded: |
Connections
This PR is a successor of gfx-rs/gfx#3762
Description
The
handle_is_external
flag 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::Instance
from the wgpu crate? Or should the user pass all the parameters sohal::Instance
can 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.