use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GpuAllocError {
OutOfMemory,
InvalidSize,
UnsupportedUsage,
AlignmentFailed,
BackendError(String),
}
impl fmt::Display for GpuAllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GpuAllocError::OutOfMemory => write!(f, "GPU out of memory"),
GpuAllocError::InvalidSize => write!(f, "Invalid buffer size"),
GpuAllocError::UnsupportedUsage => write!(f, "Unsupported buffer usage flags"),
GpuAllocError::AlignmentFailed => write!(f, "Alignment requirements not met"),
GpuAllocError::BackendError(msg) => write!(f, "Backend error: {}", msg),
}
}
}
impl std::error::Error for GpuAllocError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GpuMemoryIntent {
DeviceOnly,
HostVisible,
HostCached,
Staging,
Readback,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GpuLifetime {
Frame,
MultiFrame(u8),
Persistent,
}
#[derive(Debug, Clone)]
pub struct GpuAllocRequirements {
pub size: usize,
pub alignment: usize,
pub intent: GpuMemoryIntent,
pub lifetime: GpuLifetime,
}
impl GpuAllocRequirements {
pub fn new(size: usize, intent: GpuMemoryIntent, lifetime: GpuLifetime) -> Self {
Self {
size,
alignment: 1, intent,
lifetime,
}
}
pub fn with_alignment(mut self, alignment: usize) -> Self {
self.alignment = alignment;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BufferUsage {
pub bits: u32,
}
impl BufferUsage {
pub const TRANSFER_SRC: Self = Self { bits: 0x0001 };
pub const TRANSFER_DST: Self = Self { bits: 0x0002 };
pub const UNIFORM_TEXEL_BUFFER: Self = Self { bits: 0x0004 };
pub const STORAGE_TEXEL_BUFFER: Self = Self { bits: 0x0008 };
pub const UNIFORM_BUFFER: Self = Self { bits: 0x0010 };
pub const STORAGE_BUFFER: Self = Self { bits: 0x0020 };
pub const INDEX_BUFFER: Self = Self { bits: 0x0040 };
pub const VERTEX_BUFFER: Self = Self { bits: 0x0080 };
pub const INDIRECT_BUFFER: Self = Self { bits: 0x0100 };
}
impl std::ops::BitOr for BufferUsage {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self { bits: self.bits | rhs.bits }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryType {
DeviceLocal,
HostVisible,
HostCoherent,
HostCached,
Lazy,
}
#[derive(Debug, Clone, Default)]
pub struct GpuAllocStats {
pub total_bytes: usize,
pub allocated_bytes: usize,
pub transient_bytes: usize,
pub persistent_bytes: usize,
pub peak_usage: usize,
pub allocation_count: usize,
}
pub trait GpuAllocator: Send + Sync {
fn allocate(&self, req: GpuAllocRequirements) -> Result<Box<dyn GpuBuffer>, GpuAllocError>;
fn deallocate(&self, buffer: Box<dyn GpuBuffer>);
fn stats(&self) -> GpuAllocStats;
fn supports_intent(&self, intent: GpuMemoryIntent) -> bool;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MapMode {
Read,
Write,
ReadWrite,
}
pub trait GpuMappable {
fn map(&mut self, mode: MapMode) -> Result<*mut u8, GpuAllocError>;
fn unmap(&mut self);
fn flush(&self, offset: usize, size: usize) -> Result<(), GpuAllocError>;
fn invalidate(&self, offset: usize, size: usize) -> Result<(), GpuAllocError>;
}
pub trait GpuFrameAllocator: GpuAllocator {
fn begin_gpu_frame(&mut self);
fn end_gpu_frame(&mut self);
fn frame_alloc(&mut self, req: GpuAllocRequirements) -> Result<Self::Buffer, GpuAllocError> {
let mut frame_req = req;
frame_req.lifetime = GpuLifetime::Frame;
self.allocate(frame_req)
}
fn current_frame(&self) -> u64;
}
pub trait GpuBuffer: Send + Sync {
fn size(&self) -> usize;
fn intent(&self) -> GpuMemoryIntent;
fn lifetime(&self) -> GpuLifetime;
fn raw_handle(&self) -> *mut std::ffi::c_void;
fn map(&mut self) -> Option<*mut u8>;
fn unmap(&mut self);
fn flush(&self, offset: usize, size: usize) -> Result<(), GpuAllocError>;
fn invalidate(&self, offset: usize, size: usize) -> Result<(), GpuAllocError>;
}
pub trait GpuAllocator: Send + Sync {
fn allocate_buffer(
&mut self,
size: usize,
usage: BufferUsage,
memory_type: MemoryType,
) -> Result<Box<dyn GpuBuffer>, GpuAllocError>;
fn free_buffer(&mut self, buffer: Box<dyn GpuBuffer>);
fn total_allocated(&self) -> usize;
fn available_memory(&self) -> usize;
fn supports_mapping(&self) -> bool;
fn alignment_for(&self, usage: BufferUsage) -> usize;
}
#[derive(Debug, Clone, Default)]
pub struct GpuAllocStats {
pub allocation_count: usize,
pub allocated_bytes: usize,
pub failed_allocations: usize,
pub peak_usage: usize,
pub fragmentation: f32,
}