Skip to content
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

Merged
merged 1 commit into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 87 additions & 16 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,14 +517,17 @@ impl<A: HalApi> Device<A> {
})
}

fn create_texture(
fn create_texture_from_hal(
&self,
hal_texture: A::Texture,
self_id: id::DeviceId,
adapter: &crate::instance::Adapter<A>,
desc: &resource::TextureDescriptor,
) -> Result<resource::Texture<A>, resource::CreateTextureError> {
debug_assert_eq!(self_id.backend(), A::VARIANT);

let hal_usage = conv::map_texture_usage(desc.usage, desc.format.into());

let format_features = self
.describe_format_features(adapter, desc.format)
.map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
Expand Down Expand Up @@ -566,6 +569,29 @@ impl<A: HalApi> Device<A> {
return Err(resource::CreateTextureError::InvalidMipLevelCount(mips));
}

Ok(resource::Texture {
raw: Some(hal_texture),
device_id: Stored {
value: id::Valid(self_id),
ref_count: self.life_guard.add_ref(),
},
desc: desc.map_label(|_| ()),
hal_usage,
format_features,
full_range: TextureSelector {
levels: 0..desc.mip_level_count,
layers: 0..desc.array_layer_count(),
},
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
})
}

fn create_texture(
&self,
self_id: id::DeviceId,
adapter: &crate::instance::Adapter<A>,
desc: &resource::TextureDescriptor,
) -> Result<resource::Texture<A>, resource::CreateTextureError> {
let hal_usage = conv::map_texture_usage(desc.usage, desc.format.into());
let hal_desc = hal::TextureDescriptor {
label: desc.label.borrow_option(),
Expand All @@ -583,21 +609,7 @@ impl<A: HalApi> Device<A> {
.map_err(DeviceError::from)?
};

Ok(resource::Texture {
raw: Some(raw),
device_id: Stored {
value: id::Valid(self_id),
ref_count: self.life_guard.add_ref(),
},
desc: desc.map_label(|_| ()),
hal_usage,
format_features,
full_range: TextureSelector {
levels: 0..desc.mip_level_count,
layers: 0..desc.array_layer_count(),
},
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
})
self.create_texture_from_hal(raw, self_id, adapter, desc)
}

fn create_texture_view(
Expand Down Expand Up @@ -2976,6 +2988,65 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
(id, Some(error))
}

/// # Safety
///
/// - `hal_texture` must be created from `device_id` corresponding raw handle.
/// - `hal_texture` must be created respecting `desc`
pub unsafe fn create_texture_from_hal<A: HalApi>(
&self,
hal_texture: A::Texture,
device_id: id::DeviceId,
desc: &resource::TextureDescriptor,
id_in: Input<G, id::TextureId>,
) -> (id::TextureId, Option<resource::CreateTextureError>) {
profiling::scope!("create_texture", "Device");

let hub = A::hub(self);
let mut token = Token::root();
let fid = hub.textures.prepare(id_in);

let (adapter_guard, mut token) = hub.adapters.read(&mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let error = loop {
let device = match device_guard.get(device_id) {
Ok(device) => device,
Err(_) => break DeviceError::Invalid.into(),
};

// NB: Any change done through the raw texture handle will not be recorded in the replay
#[cfg(feature = "trace")]
if let Some(ref trace) = device.trace {
trace
.lock()
.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
Copy link
Member

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

}

let adapter = &adapter_guard[device.adapter_id.value];
let texture =
match device.create_texture_from_hal(hal_texture, device_id, adapter, desc) {
Ok(texture) => texture,
Err(error) => break error,
};
let num_levels = texture.full_range.levels.end;
let num_layers = texture.full_range.layers.end;
let ref_count = texture.life_guard.add_ref();

let id = fid.assign(texture, &mut token);
log::info!("Created texture {:?} with {:?}", id, desc);

device
.trackers
.lock()
.textures
.init(id, ref_count, TextureState::new(num_levels, num_layers))
.unwrap();
return (id.0, None);
};

let id = fid.assign_error(desc.label.borrow_or_default(), &mut token);
(id, Some(error))
}

pub fn texture_label<A: HalApi>(&self, id: id::TextureId) -> String {
A::hub(self).textures.label_for_resource(id)
}
Expand Down
44 changes: 44 additions & 0 deletions wgpu-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,22 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}

/// # Safety
///
/// Refer to the creation of wgpu-hal Instance for every backend.
pub unsafe fn from_hal_instance<A: HalApi>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same concern about the name

name: &str,
factory: G,
hal_instance: A::Instance,
) -> Self {
profiling::scope!("new", "Global");
Self {
instance: A::create_instance_from_hal(name, hal_instance),
surfaces: Registry::without_backend(&factory, "Surface"),
hubs: Hubs::new(&factory),
}
}

pub fn clear_backend<A: HalApi>(&self, _dummy: ()) {
let mut surface_guard = self.surfaces.data.write();
let hub = A::hub(self);
Expand Down Expand Up @@ -933,13 +949,21 @@ impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {

pub trait HalApi: hal::Api {
const VARIANT: Backend;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance;
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G>;
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface;
}

#[cfg(vulkan)]
impl HalApi for hal::api::Vulkan {
const VARIANT: Backend = Backend::Vulkan;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
vulkan: Some(hal_instance),
..Default::default()
}
}
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.vulkan
}
Expand All @@ -951,6 +975,12 @@ impl HalApi for hal::api::Vulkan {
#[cfg(metal)]
impl HalApi for hal::api::Metal {
const VARIANT: Backend = Backend::Metal;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
metal: Some(hal_instance),
}
}
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.metal
}
Expand All @@ -962,6 +992,13 @@ impl HalApi for hal::api::Metal {
#[cfg(dx12)]
impl HalApi for hal::api::Dx12 {
const VARIANT: Backend = Backend::Dx12;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
dx12: Some(hal_instance),
..Default::default()
}
}
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.dx12
}
Expand All @@ -986,6 +1023,13 @@ impl HalApi for hal::api::Dx11 {
#[cfg(gl)]
impl HalApi for hal::api::Gles {
const VARIANT: Backend = Backend::Gl;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
gl: Some(hal_instance),
..Default::default()
}
}
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.gl
}
Expand Down
92 changes: 84 additions & 8 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ fn downlevel_default_limits_less_than_default_limits() {
)
}

#[derive(Default)]
pub struct Instance {
#[allow(dead_code)]
name: String,
pub name: String,
#[cfg(vulkan)]
pub vulkan: Option<HalInstance<hal::api::Vulkan>>,
#[cfg(metal)]
Expand Down Expand Up @@ -248,9 +249,10 @@ impl<A: HalApi> Adapter<A> {
}
}

fn create_device(
fn create_device_from_hal(
&self,
self_id: AdapterId,
open: hal::OpenDevice<A>,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
) -> Result<Device<A>, RequestDeviceError> {
Expand Down Expand Up @@ -281,11 +283,6 @@ impl<A: HalApi> Adapter<A> {
log::warn!("Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. This is a massive performance footgun and likely not what you wanted");
}

let gpu = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err {
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
})?;

if let Some(_) = desc.label {
//TODO
}
Expand All @@ -305,7 +302,7 @@ impl<A: HalApi> Adapter<A> {
}

Device::new(
gpu,
open,
Stored {
value: Valid(self_id),
ref_count: self.life_guard.add_ref(),
Expand All @@ -317,6 +314,20 @@ impl<A: HalApi> Adapter<A> {
)
.or(Err(RequestDeviceError::OutOfMemory))
}

fn create_device(
&self,
self_id: AdapterId,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
) -> Result<Device<A>, RequestDeviceError> {
let open = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err {
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
})?;

self.create_device_from_hal(self_id, open, desc, trace_path)
}
}

impl<A: hal::Api> crate::hub::Resource for Adapter<A> {
Expand Down Expand Up @@ -649,6 +660,34 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Err(RequestAdapterError::NotFound)
}

/// # Safety
///
/// `hal_adapter` must be created from this global internal instance handle.
pub unsafe fn create_adapter_from_hal<A: HalApi>(
&self,
hal_adapter: hal::ExposedAdapter<A>,
input: Input<G, AdapterId>,
) -> AdapterId {
profiling::scope!("create_adapter_from_hal", "Instance");

let mut token = Token::root();
let fid = A::hub(&self).adapters.prepare(input);

match A::VARIANT {
#[cfg(vulkan)]
Backend::Vulkan => fid.assign(Adapter::new(hal_adapter), &mut token).0,
#[cfg(metal)]
Backend::Metal => fid.assign(Adapter::new(hal_adapter), &mut token).0,
#[cfg(dx12)]
Backend::Dx12 => fid.assign(Adapter::new(hal_adapter), &mut token).0,
#[cfg(dx11)]
Backend::Dx11 => fid.assign(Adapter::new(hal_adapter), &mut token).0,
#[cfg(gl)]
Backend::Gl => fid.assign(Adapter::new(hal_adapter), &mut token).0,
_ => unreachable!(),
}
}

pub fn adapter_get_info<A: HalApi>(
&self,
adapter_id: AdapterId,
Expand Down Expand Up @@ -764,4 +803,41 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let id = fid.assign_error(desc.label.borrow_or_default(), &mut token);
(id, Some(error))
}

/// # Safety
///
/// - `hal_device` must be created from `adapter_id` or its internal handle.
/// - `desc` must be a subset of `hal_device` features and limits.
pub unsafe fn create_device_from_hal<A: HalApi>(
&self,
adapter_id: AdapterId,
hal_device: hal::OpenDevice<A>,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
id_in: Input<G, DeviceId>,
) -> (DeviceId, Option<RequestDeviceError>) {
profiling::scope!("request_device", "Adapter");

let hub = A::hub(self);
let mut token = Token::root();
let fid = hub.devices.prepare(id_in);

let error = loop {
let (adapter_guard, mut token) = hub.adapters.read(&mut token);
let adapter = match adapter_guard.get(adapter_id) {
Ok(adapter) => adapter,
Err(_) => break RequestDeviceError::InvalidAdapter,
};
let device =
match adapter.create_device_from_hal(adapter_id, hal_device, desc, trace_path) {
Ok(device) => device,
Err(e) => break e,
};
let id = fid.assign(device, &mut token);
return (id.0, None);
};

let id = fid.assign_error(desc.label.borrow_or_default(), &mut token);
(id, Some(error))
}
}
Loading