Import Oxide engine (Stages 0–10) under MIT license
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>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
//! 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user