9eead719b0
Full project snapshot migrated to new Gitea remote without history: engine, editor, physics, script, examples, tests, docs, and assets. Relicensed from GPLv3 to MIT and updated repo URLs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
95 lines
3.2 KiB
Rust
95 lines
3.2 KiB
Rust
//! GPU acquisition: instance, adapter, device, queue.
|
|
|
|
use super::RenderError;
|
|
|
|
/// A handle to the GPU: instance, adapter, and the device/queue pair every
|
|
/// rendering operation goes through.
|
|
///
|
|
/// Created either for a window surface (via [`RenderContext`]) or headless
|
|
/// with [`Gpu::headless`] for offscreen rendering and tests.
|
|
///
|
|
/// [`RenderContext`]: super::RenderContext
|
|
pub struct Gpu {
|
|
instance: wgpu::Instance,
|
|
adapter: wgpu::Adapter,
|
|
device: wgpu::Device,
|
|
queue: wgpu::Queue,
|
|
}
|
|
|
|
impl Gpu {
|
|
/// Acquires an adapter and device from an existing `instance`, preferring
|
|
/// an adapter that can present to `compatible_surface` when one is given.
|
|
///
|
|
/// `force_fallback_adapter` requests a software adapter (e.g. llvmpipe),
|
|
/// used as a last resort when no hardware adapter works.
|
|
pub(crate) fn with_instance(
|
|
instance: wgpu::Instance,
|
|
compatible_surface: Option<&wgpu::Surface<'_>>,
|
|
force_fallback_adapter: bool,
|
|
) -> Result<Self, RenderError> {
|
|
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
force_fallback_adapter,
|
|
compatible_surface,
|
|
}))?;
|
|
log::info!(
|
|
"GPU adapter: {} ({:?})",
|
|
adapter.get_info().name,
|
|
adapter.get_info().backend
|
|
);
|
|
let (device, queue) =
|
|
pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
|
label: Some("oxide.device"),
|
|
..Default::default()
|
|
}))?;
|
|
Ok(Self {
|
|
instance,
|
|
adapter,
|
|
device,
|
|
queue,
|
|
})
|
|
}
|
|
|
|
/// Acquires the GPU without any surface, for offscreen rendering and
|
|
/// automated tests.
|
|
///
|
|
/// Tries a hardware adapter first, then falls back to a software adapter
|
|
/// (e.g. llvmpipe) so headless rendering also works on machines without a
|
|
/// usable GPU.
|
|
pub fn headless() -> Result<Self, RenderError> {
|
|
// `from_env` keeps backend/flags overridable via WGPU_* env vars.
|
|
let instance =
|
|
wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
|
|
match Self::with_instance(instance, None, false) {
|
|
Ok(gpu) => Ok(gpu),
|
|
Err(hardware_err) => {
|
|
log::warn!("no hardware GPU adapter ({hardware_err}); trying software fallback");
|
|
let instance = wgpu::Instance::new(
|
|
wgpu::InstanceDescriptor::new_without_display_handle_from_env(),
|
|
);
|
|
Self::with_instance(instance, None, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The wgpu instance the adapter was created from.
|
|
pub fn instance(&self) -> &wgpu::Instance {
|
|
&self.instance
|
|
}
|
|
|
|
/// The physical adapter in use.
|
|
pub fn adapter(&self) -> &wgpu::Adapter {
|
|
&self.adapter
|
|
}
|
|
|
|
/// The logical device used to create GPU resources.
|
|
pub fn device(&self) -> &wgpu::Device {
|
|
&self.device
|
|
}
|
|
|
|
/// The queue used to submit command buffers.
|
|
pub fn queue(&self) -> &wgpu::Queue {
|
|
&self.queue
|
|
}
|
|
}
|