#[test] fn downlevel_default_limits_less_than_default_limits() { let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
assert!(
res.is_empty(), "Downlevel limits are greater than default limits",
)
}
#[derive(Default)] pubstruct Instance { #[allow(dead_code)] pub name: String, /// List of instances per backend. /// /// The ordering in this list implies prioritization and needs to be preserved. pub instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>, pub flags: wgt::InstanceFlags,
}
/// # Safety /// /// - The raw instance handle returned must not be manually destroyed. pubunsafefn as_hal<A: HalApi>(&self) -> Option<&A::Instance> { self.raw(A::VARIANT).map(|instance| {
instance
.as_any()
.downcast_ref() // This should be impossible. It would mean that backend instance and enum type are mismatching.
.expect("Stored instance is not of the correct type")
})
}
/// Creates a new surface targeting the given display/window handles. /// /// Internally attempts to create hal surfaces for all enabled backends. /// /// Fails only if creation for surfaces for all enabled backends fails in which case /// the error for each enabled backend is listed. /// Vice versa, if creation for any backend succeeds, success is returned. /// Surface creation errors are logged to the debug log in any case. /// /// # Safety /// /// - `display_handle` must be a valid object to create a surface upon. /// - `window_handle` must remain valid as long as the returned /// [`SurfaceId`] is being used. #[cfg(feature = "raw-window-handle")] pubunsafefn create_surface(
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Result<Surface, CreateSurfaceError> {
profiling::scope!("Instance::create_surface");
for (backend, instance) in &self.instance_per_backend { matchunsafe {
instance
.as_ref()
.create_surface(display_handle, window_handle)
} {
Ok(raw) => {
surface_per_backend.insert(*backend, raw);
}
Err(err) => {
log::debug!( "Instance::create_surface: failed to create surface for {:?}: {:?}",
backend,
err
);
errors.insert(*backend, err);
}
}
}
if surface_per_backend.is_empty() {
Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
errors,
))
} else { let surface = Surface {
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
surface_per_backend,
};
Ok(surface)
}
}
/// # Safety /// /// `layer` must be a valid pointer. #[cfg(metal)] pubunsafefn create_surface_metal(
&self,
layer: *mut std::ffi::c_void,
) -> Result<Surface, CreateSurfaceError> {
profiling::scope!("Instance::create_surface_metal");
let instance = unsafe { self.as_hal::<hal::api::Metal>() }
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
let layer = layer.cast(); // SAFETY: We do this cast and deref. (rather than using `metal` to get the // object we want) to avoid direct coupling on the `metal` crate. // // To wit, this pointer… // // - …is properly aligned. // - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal` // field. // - …points to an _initialized_ `MetalLayerRef`. // - …is only ever aliased via an immutable reference that lives within this // lexical scope. let layer = unsafe { &*layer }; let raw_surface: Box<dyn hal::DynSurface> = Box::new(instance.create_surface_from_layer(layer));
#[cfg(dx12)] /// # Safety /// /// The visual must be valid and able to be used to make a swapchain with. pubunsafefn create_surface_from_visual(
&self,
visual: *mut std::ffi::c_void,
) -> Result<Surface, CreateSurfaceError> {
profiling::scope!("Instance::instance_create_surface_from_visual"); self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
}
#[cfg(dx12)] /// # Safety /// /// The surface_handle must be valid and able to be used to make a swapchain with. pubunsafefn create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
) -> Result<Surface, CreateSurfaceError> {
profiling::scope!("Instance::instance_create_surface_from_surface_handle"); self.create_surface_dx12(|inst| unsafe {
inst.create_surface_from_surface_handle(surface_handle)
})
}
#[cfg(dx12)] /// # Safety /// /// The swap_chain_panel must be valid and able to be used to make a swapchain with. pubunsafefn create_surface_from_swap_chain_panel(
&self,
swap_chain_panel: *mut std::ffi::c_void,
) -> Result<Surface, CreateSurfaceError> {
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); self.create_surface_dx12(|inst| unsafe {
inst.create_surface_from_swap_chain_panel(swap_chain_panel)
})
}
letmut adapters = Vec::new(); for (_backend, instance) inself
.instance_per_backend
.iter()
.filter(|(backend, _)| backends.contains(Backends::from(*backend)))
{ // NOTE: We might be using `profiling` without any features. The empty backend of this // macro emits no code, so unused code linting changes depending on the backend.
profiling::scope!("enumerating", &*format!("{:?}", _backend));
let hal_adapters = unsafe { instance.enumerate_adapters(None) }; for raw in hal_adapters { let adapter = Adapter::new(raw);
api_log_debug!("Adapter {:?}", adapter.raw.info);
adapters.push(adapter);
}
}
adapters
}
fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 { // Since devices of type "Other" might really be "Unknown" and come // from APIs like OpenGL that don't specify device type, Prefer more // Specific types over Other. // // This means that backends which do provide accurate device types // will be preferred if their device type indicates an actual // hardware GPU (integrated or discrete). match device_type {
wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
wgt::DeviceType::DiscreteGpu => 1,
wgt::DeviceType::IntegratedGpu => 2,
wgt::DeviceType::Other => 3,
wgt::DeviceType::VirtualGpu => 4,
wgt::DeviceType::Cpu => 5,
}
}
// `request_adapter` can be a bit of a black box. // Shine some light on its decision in debug log. if adapters.is_empty() {
log::debug!("Request adapter didn't find compatible adapters.");
} else {
log::debug!( "Found {} compatible adapters. Sorted by preference:",
adapters.len()
); for adapter in &adapters {
log::debug!("* {:?}", adapter.info);
}
}
/// Returns the backend this adapter is using. pubfn backend(&self) -> Backend { self.raw.backend()
}
pubfn is_surface_supported(&self, surface: &Surface) -> bool { // If get_capabilities returns Err, then the API does not advertise support for the surface. // // This could occur if the user is running their app on Wayland but Vulkan does not support // VK_KHR_wayland_surface.
surface.get_capabilities(self).is_ok()
}
let device = Device::new(hal_device.device, self, desc, trace_path, instance_flags)?; let device = Arc::new(device);
let queue = Queue::new(device.clone(), hal_device.queue)?; let queue = Arc::new(queue);
device.set_queue(&queue);
Ok((device, queue))
}
pubfn create_device_and_queue( self: &Arc<Self>,
desc: &DeviceDescriptor,
instance_flags: wgt::InstanceFlags,
trace_path: Option<&std::path::Path>,
) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> { // Verify all features were exposed by the adapter if !self.raw.features.contains(desc.required_features) { return Err(RequestDeviceError::UnsupportedFeature(
desc.required_features - self.raw.features,
));
}
let caps = &self.raw.capabilities; if Backends::PRIMARY.contains(Backends::from(self.backend()))
&& !caps.downlevel.is_webgpu_compliant()
{ let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
log::warn!( "Missing downlevel flags: {:?}\n{}",
missing_flags,
DOWNLEVEL_WARNING_MESSAGE
);
log::warn!("{:#?}", caps.downlevel);
}
// Verify feature preconditions if desc
.required_features
.contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
&& self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
{
log::warn!( "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
This is a massive performance footgun and likely not what you wanted"
);
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum GetSurfaceSupportError { #[error("Surface is not supported for the specified backend {0}")]
NotSupportedByBackend(Backend), #[error("Failed to retrieve surface capabilities for the specified adapter.")]
FailedToRetrieveSurfaceCapabilitiesForAdapter,
}
#[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] /// Error when requesting a device from the adapter #[non_exhaustive] pubenum RequestDeviceError { #[error(transparent)]
Device(#[from] DeviceError), #[error(transparent)]
LimitsExceeded(#[from] FailedLimit), #[error("Unsupported features were requested: {0:?}")]
UnsupportedFeature(wgt::Features),
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum CreateSurfaceError { #[error("The backend {0} was not enabled on the instance.")]
BackendNotEnabled(Backend), #[error("Failed to create surface for any enabled backend: {0:?}")]
FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
}
impl Global { /// Creates a new surface targeting the given display/window handles. /// /// Internally attempts to create hal surfaces for all enabled backends. /// /// Fails only if creation for surfaces for all enabled backends fails in which case /// the error for each enabled backend is listed. /// Vice versa, if creation for any backend succeeds, success is returned. /// Surface creation errors are logged to the debug log in any case. /// /// id_in: /// - If `Some`, the id to assign to the surface. A new one will be generated otherwise. /// /// # Safety /// /// - `display_handle` must be a valid object to create a surface upon. /// - `window_handle` must remain valid as long as the returned /// [`SurfaceId`] is being used. #[cfg(feature = "raw-window-handle")] pubunsafefn instance_create_surface(
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> { let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?; let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
/// # Safety /// /// `layer` must be a valid pointer. #[cfg(metal)] pubunsafefn instance_create_surface_metal(
&self,
layer: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> { let surface = unsafe { self.instance.create_surface_metal(layer) }?; let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
#[cfg(dx12)] /// # Safety /// /// The visual must be valid and able to be used to make a swapchain with. pubunsafefn instance_create_surface_from_visual(
&self,
visual: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> { let surface = unsafe { self.instance.create_surface_from_visual(visual) }?; let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
#[cfg(dx12)] /// # Safety /// /// The surface_handle must be valid and able to be used to make a swapchain with. pubunsafefn instance_create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> { let surface = unsafe { self.instance
.create_surface_from_surface_handle(surface_handle)
}?; let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
#[cfg(dx12)] /// # Safety /// /// The swap_chain_panel must be valid and able to be used to make a swapchain with. pubunsafefn instance_create_surface_from_swap_chain_panel(
&self,
swap_chain_panel: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> { let surface = unsafe { self.instance
.create_surface_from_swap_chain_panel(swap_chain_panel)
}?; let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
pubfn request_adapter(
&self,
desc: &RequestAdapterOptions,
backends: Backends,
id_in: Option<AdapterId>,
) -> Result<AdapterId, RequestAdapterError> { let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id)); let desc = wgt::RequestAdapterOptions {
power_preference: desc.power_preference,
force_fallback_adapter: desc.force_fallback_adapter,
compatible_surface: compatible_surface.as_deref(),
}; let adapter = self.instance.request_adapter(&desc, backends)?; let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
Ok(id)
}
/// # Safety /// /// `hal_adapter` must be created from this global internal instance handle. pubunsafefn create_adapter_from_hal(
&self,
hal_adapter: hal::DynExposedAdapter,
input: Option<AdapterId>,
) -> AdapterId {
profiling::scope!("Instance::create_adapter_from_hal");
let fid = self.hub.adapters.prepare(input); let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
let device_fid = self.hub.devices.prepare(device_id_in); let queue_fid = self.hub.queues.prepare(queue_id_in);
let adapter = self.hub.adapters.get(adapter_id); let (device, queue) =
adapter.create_device_and_queue(desc, self.instance.flags, trace_path)?;
let device_id = device_fid.assign(device);
resource_log!("Created Device {:?}", device_id);
let queue_id = queue_fid.assign(queue);
resource_log!("Created Queue {:?}", queue_id);
Ok((device_id, queue_id))
}
/// # Safety /// /// - `hal_device` must be created from `adapter_id` or its internal handle. /// - `desc` must be a subset of `hal_device` features and limits. pubunsafefn create_device_from_hal(
&self,
adapter_id: AdapterId,
hal_device: hal::DynOpenDevice,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
device_id_in: Option<DeviceId>,
queue_id_in: Option<QueueId>,
) -> Result<(DeviceId, QueueId), RequestDeviceError> {
profiling::scope!("Global::create_device_from_hal");
let devices_fid = self.hub.devices.prepare(device_id_in); let queues_fid = self.hub.queues.prepare(queue_id_in);
let adapter = self.hub.adapters.get(adapter_id); let (device, queue) = adapter.create_device_and_queue_from_hal(
hal_device,
desc, self.instance.flags,
trace_path,
)?;
let device_id = devices_fid.assign(device);
resource_log!("Created Device {:?}", device_id);
let queue_id = queues_fid.assign(queue);
resource_log!("Created Queue {:?}", queue_id);
Ok((device_id, queue_id))
}
}
/// Generates a set of backends from a comma separated list of case-insensitive backend names. /// /// Whitespace is stripped, so both 'gl, dx12' and 'gl,dx12' are valid. /// /// Always returns WEBGPU on wasm over webgpu. /// /// Names: /// - vulkan = "vulkan" or "vk" /// - dx12 = "dx12" or "d3d12" /// - metal = "metal" or "mtl" /// - gles = "opengl" or "gles" or "gl" /// - webgpu = "webgpu" pubfn parse_backends_from_comma_list(string: &str) -> Backends { letmut backends = Backends::empty(); for backend in string.to_lowercase().split(',') {
backends |= match backend.trim() { "vulkan" | "vk" => Backends::VULKAN, "dx12" | "d3d12" => Backends::DX12, "metal" | "mtl" => Backends::METAL, "opengl" | "gles" | "gl" => Backends::GL, "webgpu" => Backends::BROWSER_WEBGPU,
b => {
log::warn!("unknown backend string '{}'", b); continue;
}
}
}
if backends.is_empty() {
log::warn!("no valid backend strings found!");
}
backends
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.