use oxiui_core::UiError;
pub const TARGET_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
pub struct GpuContext {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub color_texture: wgpu::Texture,
pub color_view: wgpu::TextureView,
pub width: u32,
pub height: u32,
}
impl GpuContext {
pub fn headless(width: u32, height: u32) -> Result<Self, UiError> {
if width == 0 || height == 0 {
return Err(UiError::Unsupported(
"headless target dimensions must be non-zero".to_string(),
));
}
let instance = wgpu::Instance::default();
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
force_fallback_adapter: false,
compatible_surface: None,
}))
.map_err(|e| UiError::Unsupported(format!("no GPU adapter available: {e}")))?;
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
label: Some("oxiui-render-wgpu headless device"),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: wgpu::MemoryHints::Performance,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
trace: wgpu::Trace::Off,
}))
.map_err(|e| UiError::Backend(format!("GPU device request failed: {e}")))?;
let color_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("oxiui-render-wgpu offscreen target"),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: TARGET_FORMAT,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
let color_view = color_texture.create_view(&wgpu::TextureViewDescriptor::default());
Ok(Self {
device,
queue,
color_texture,
color_view,
width,
height,
})
}
}