#[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))]
pub mod vulkan;
#[cfg(all(feature = "dx12", target_os = "windows"))]
pub mod dx12;
pub mod mock;
#[cfg(target_os = "macos")]
pub mod metal;
use crate::types::{
BackendType, BufferUsage, Color, DepthFormat, DepthStencilState, DeviceType, IndexFormat,
PrimitiveTopology, SamplerDesc, TextureFormat, TextureUsage, VertexBufferLayout,
};
use anyhow::Result;
pub use raw_window_handle;
#[derive(Debug, Clone)]
pub struct AdapterInfo {
pub id: u32,
pub name: String,
pub vendor: String,
pub backend: BackendType,
pub device_type: DeviceType,
}
pub type DeviceHandle = u64;
pub type BufferHandle = u64;
pub type ShaderHandle = u64;
pub type PipelineHandle = u64;
pub type ComputePipelineHandle = u64;
pub type BindGroupHandle = u64;
pub type BindGroupLayoutHandle = u64;
pub type RenderTargetHandle = u64;
pub type SurfaceHandle = u64;
pub type SwapchainImageHandle = u64;
pub type TextureHandle = u64;
pub type SamplerHandle = u64;
#[derive(Debug, Clone)]
pub enum RenderCommand {
Clear(Color),
ClearDepth(f32),
SetPipeline(PipelineHandle),
SetVertexBuffer { slot: u32, buffer: BufferHandle, offset: u64 },
SetIndexBuffer { buffer: BufferHandle, offset: u64, format: IndexFormat },
SetBindGroup { index: u32, bind_group: BindGroupHandle },
Draw {
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
},
DrawIndexed {
index_count: u32,
instance_count: u32,
first_index: u32,
base_vertex: i32,
first_instance: u32,
},
}
#[derive(Debug, Clone)]
pub enum ComputeCommand {
SetPipeline(ComputePipelineHandle),
SetBindGroup { index: u32, bind_group: BindGroupHandle },
Dispatch {
workgroups_x: u32,
workgroups_y: u32,
workgroups_z: u32,
},
}
pub trait GpuBackend: Send + Sync {
fn backend_type(&self) -> BackendType;
fn enumerate_adapters(&self) -> Vec<AdapterInfo>;
fn create_device(&mut self, adapter_id: u32) -> Result<DeviceHandle>;
fn destroy_device(&mut self, device: DeviceHandle);
fn is_device_valid(&self, device: DeviceHandle) -> bool;
fn create_buffer(&mut self, device: DeviceHandle, size: u64, usage: BufferUsage) -> Result<BufferHandle>;
fn destroy_buffer(&mut self, buffer: BufferHandle);
fn write_buffer(&mut self, buffer: BufferHandle, offset: u64, data: &[u8]) -> Result<()>;
fn buffer_size(&self, buffer: BufferHandle) -> u64;
fn create_shader(&mut self, device: DeviceHandle, slang_source: &str) -> Result<ShaderHandle>;
fn create_shader_with_paths(&mut self, device: DeviceHandle, slang_source: &str, search_paths: &[&str]) -> Result<ShaderHandle>;
fn destroy_shader(&mut self, shader: ShaderHandle);
fn create_bind_group_layout(&mut self, device: DeviceHandle, entries: &[BindGroupLayoutEntry]) -> Result<BindGroupLayoutHandle>;
fn create_bind_group(&mut self, device: DeviceHandle, layout: BindGroupLayoutHandle, entries: &[BindGroupEntry]) -> Result<BindGroupHandle>;
fn destroy_bind_group(&mut self, bind_group: BindGroupHandle);
fn create_pipeline(
&mut self,
device: DeviceHandle,
vertex_shader: ShaderHandle,
fragment_shader: ShaderHandle,
vertex_layout: &VertexBufferLayout,
topology: PrimitiveTopology,
target_format: TextureFormat,
) -> Result<PipelineHandle>;
fn create_pipeline_with_layout(
&mut self,
device: DeviceHandle,
vertex_shader: ShaderHandle,
fragment_shader: ShaderHandle,
vertex_layout: &VertexBufferLayout,
topology: PrimitiveTopology,
target_format: TextureFormat,
bind_group_layouts: &[BindGroupLayoutHandle],
) -> Result<PipelineHandle>;
fn destroy_pipeline(&mut self, pipeline: PipelineHandle);
fn create_pipeline_with_depth(
&mut self,
device: DeviceHandle,
vertex_shader: ShaderHandle,
fragment_shader: ShaderHandle,
vertex_layout: &VertexBufferLayout,
topology: PrimitiveTopology,
target_format: TextureFormat,
bind_group_layouts: &[BindGroupLayoutHandle],
depth_stencil: Option<&DepthStencilState>,
) -> Result<PipelineHandle>;
fn create_render_target(&mut self, device: DeviceHandle, width: u32, height: u32, format: TextureFormat) -> Result<RenderTargetHandle>;
fn create_render_target_with_depth(
&mut self,
device: DeviceHandle,
width: u32,
height: u32,
color_format: TextureFormat,
depth_format: Option<DepthFormat>,
) -> Result<RenderTargetHandle>;
fn destroy_render_target(&mut self, target: RenderTargetHandle);
fn render_to_target(&mut self, device: DeviceHandle, target: RenderTargetHandle, commands: &[RenderCommand]) -> Result<()>;
fn read_target_to_cpu(&mut self, target: RenderTargetHandle, output: &mut [u8]) -> Result<()>;
fn create_texture(
&mut self,
device: DeviceHandle,
width: u32,
height: u32,
format: TextureFormat,
usage: TextureUsage,
) -> Result<TextureHandle>;
fn write_texture(&mut self, texture: TextureHandle, data: &[u8], width: u32, height: u32) -> Result<()>;
fn destroy_texture(&mut self, texture: TextureHandle);
fn create_sampler(&mut self, device: DeviceHandle, desc: &SamplerDesc) -> Result<SamplerHandle>;
fn destroy_sampler(&mut self, sampler: SamplerHandle);
fn create_surface(&mut self, device: DeviceHandle, window: &dyn raw_window_handle::HasWindowHandle, display: &dyn raw_window_handle::HasDisplayHandle) -> Result<SurfaceHandle>;
fn destroy_surface(&mut self, surface: SurfaceHandle);
fn surface_acquire(&mut self, surface: SurfaceHandle) -> Result<SwapchainImageHandle>;
fn surface_render(&mut self, surface: SurfaceHandle, image: SwapchainImageHandle, commands: &[RenderCommand]) -> Result<()>;
fn surface_present(&mut self, surface: SurfaceHandle, image: SwapchainImageHandle) -> Result<()>;
fn surface_resize(&mut self, surface: SurfaceHandle, width: u32, height: u32) -> Result<()>;
fn surface_size(&self, surface: SurfaceHandle) -> (u32, u32);
fn surface_format(&self, surface: SurfaceHandle) -> TextureFormat;
fn create_compute_pipeline(
&mut self,
device: DeviceHandle,
compute_shader: ShaderHandle,
bind_group_layouts: &[BindGroupLayoutHandle],
) -> Result<ComputePipelineHandle>;
fn destroy_compute_pipeline(&mut self, pipeline: ComputePipelineHandle);
fn dispatch_compute(&mut self, device: DeviceHandle, commands: &[ComputeCommand]) -> Result<()>;
}
#[derive(Debug, Clone)]
pub struct BindGroupLayoutEntry {
pub binding: u32,
pub visibility: ShaderStages,
pub ty: BindingType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ShaderStages(pub u32);
impl ShaderStages {
pub const VERTEX: ShaderStages = ShaderStages(1);
pub const FRAGMENT: ShaderStages = ShaderStages(2);
pub const COMPUTE: ShaderStages = ShaderStages(4);
pub const ALL: ShaderStages = ShaderStages(7); }
#[derive(Debug, Clone)]
pub enum BindingType {
UniformBuffer,
StorageBuffer { read_only: bool },
Texture,
Sampler,
StorageTexture,
}
#[derive(Debug, Clone)]
pub struct BindGroupEntry {
pub binding: u32,
pub resource: BindingResource,
}
#[derive(Debug, Clone)]
pub enum BindingResource {
Buffer { buffer: BufferHandle, offset: u64, size: u64 },
Texture(TextureHandle),
Sampler(SamplerHandle),
}
pub fn create_default_backend() -> Result<Box<dyn GpuBackend>> {
#[cfg(all(feature = "dx12", target_os = "windows"))]
{
tracing::info!("Creating DX12 backend");
Ok(Box::new(dx12::Dx12Backend::new()?))
}
#[cfg(all(
feature = "vulkan",
not(target_arch = "wasm32"),
not(all(feature = "dx12", target_os = "windows"))
))]
{
tracing::info!("Creating Vulkan backend");
Ok(Box::new(vulkan::VulkanBackend::new()?))
}
#[cfg(not(any(
all(feature = "dx12", target_os = "windows"),
all(feature = "vulkan", not(target_arch = "wasm32"))
)))]
{
anyhow::bail!("No GPU backend available - enable 'vulkan' or 'dx12' feature")
}
}
pub fn create_backend(backend_type: BackendType) -> Result<Box<dyn GpuBackend>> {
match backend_type {
#[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))]
BackendType::Vulkan => {
tracing::info!("Creating Vulkan backend");
Ok(Box::new(vulkan::VulkanBackend::new()?))
}
#[cfg(all(feature = "dx12", target_os = "windows"))]
BackendType::Dx12 => {
tracing::info!("Creating DX12 backend");
Ok(Box::new(dx12::Dx12Backend::new()?))
}
_ => anyhow::bail!("Backend {:?} not available on this platform", backend_type),
}
}