use crate::{
buffer, format, image,
memory::{Requirements, Segment},
pass,
pool::CommandPoolCreateFlags,
pso,
pso::DescriptorPoolCreateFlags,
query,
queue::QueueFamilyId,
Backend, MemoryTypeId,
};
use std::{any::Any, fmt, iter, ops::Range};
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
#[error("Device lost")]
pub struct DeviceLost;
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum OutOfMemory {
#[error("Out of host memory")]
Host,
#[error("Out of device memory")]
Device,
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum WaitError {
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
#[error(transparent)]
DeviceLost(#[from] DeviceLost),
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum AllocationError {
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
#[error("Too many objects")]
TooManyObjects,
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum CreationError {
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
#[error("Implementation specific error occurred")]
InitializationFailed,
#[error("Requested extension is missing")]
MissingExtension,
#[error("Requested feature is missing")]
MissingFeature,
#[error("Too many objects")]
TooManyObjects,
#[error("Logical or Physical device was lost during creation")]
DeviceLost,
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum MapError {
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
#[error("Requested range is outside the resource")]
OutOfBounds,
#[error("Unable to allocate an appropriately sized contiguous virtual address range")]
MappingFailed,
#[error("Memory is not CPU visible")]
Access,
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum BindError {
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
#[error("Wrong memory")]
WrongMemory,
#[error("Requested range is outside the resource")]
OutOfBounds,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WaitFor {
Any,
All,
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum ShaderError {
#[error("Shader module is not supported")]
Unsupported,
#[error("Shader module failed to compile: {0:}")]
CompilationFailed(String),
#[error(transparent)]
OutOfMemory(#[from] OutOfMemory),
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ShaderModuleDesc<'a> {
SpirV(&'a [u32]),
}
pub trait Device<B: Backend>: fmt::Debug + Any + Send + Sync {
unsafe fn allocate_memory(
&self,
memory_type: MemoryTypeId,
size: u64,
) -> Result<B::Memory, AllocationError>;
unsafe fn free_memory(&self, memory: B::Memory);
unsafe fn create_command_pool(
&self,
family: QueueFamilyId,
create_flags: CommandPoolCreateFlags,
) -> Result<B::CommandPool, OutOfMemory>;
unsafe fn destroy_command_pool(&self, pool: B::CommandPool);
unsafe fn create_render_pass<'a, Ia, Is, Id>(
&self,
attachments: Ia,
subpasses: Is,
dependencies: Id,
) -> Result<B::RenderPass, OutOfMemory>
where
Ia: Iterator<Item = pass::Attachment>,
Is: Iterator<Item = pass::SubpassDesc<'a>>,
Id: Iterator<Item = pass::SubpassDependency>;
unsafe fn destroy_render_pass(&self, rp: B::RenderPass);
unsafe fn create_pipeline_layout<'a, Is, Ic>(
&self,
set_layouts: Is,
push_constant: Ic,
) -> Result<B::PipelineLayout, OutOfMemory>
where
Is: Iterator<Item = &'a B::DescriptorSetLayout>,
Ic: Iterator<Item = (pso::ShaderStageFlags, Range<u32>)>;
unsafe fn destroy_pipeline_layout(&self, layout: B::PipelineLayout);
unsafe fn create_pipeline_cache(
&self,
data: Option<&[u8]>,
) -> Result<B::PipelineCache, OutOfMemory>;
unsafe fn get_pipeline_cache_data(
&self,
cache: &B::PipelineCache,
) -> Result<Vec<u8>, OutOfMemory>;
unsafe fn merge_pipeline_caches<'a, I>(
&self,
target: &mut B::PipelineCache,
sources: I,
) -> Result<(), OutOfMemory>
where
I: Iterator<Item = &'a B::PipelineCache>;
unsafe fn destroy_pipeline_cache(&self, cache: B::PipelineCache);
unsafe fn create_graphics_pipeline<'a>(
&self,
desc: &pso::GraphicsPipelineDesc<'a, B>,
cache: Option<&B::PipelineCache>,
) -> Result<B::GraphicsPipeline, pso::CreationError>;
unsafe fn destroy_graphics_pipeline(&self, pipeline: B::GraphicsPipeline);
unsafe fn create_compute_pipeline<'a>(
&self,
desc: &pso::ComputePipelineDesc<'a, B>,
cache: Option<&B::PipelineCache>,
) -> Result<B::ComputePipeline, pso::CreationError>;
unsafe fn destroy_compute_pipeline(&self, pipeline: B::ComputePipeline);
unsafe fn create_framebuffer<I>(
&self,
pass: &B::RenderPass,
attachments: I,
extent: image::Extent,
) -> Result<B::Framebuffer, OutOfMemory>
where
I: Iterator<Item = image::FramebufferAttachment>;
unsafe fn destroy_framebuffer(&self, buf: B::Framebuffer);
unsafe fn create_shader_module(&self, spirv: &[u32]) -> Result<B::ShaderModule, ShaderError>;
unsafe fn create_shader_module_from_naga(
&self,
module: naga::Module,
) -> Result<B::ShaderModule, (ShaderError, naga::Module)> {
Err((ShaderError::Unsupported, module))
}
unsafe fn destroy_shader_module(&self, shader: B::ShaderModule);
unsafe fn create_buffer(
&self,
size: u64,
usage: buffer::Usage,
) -> Result<B::Buffer, buffer::CreationError>;
unsafe fn get_buffer_requirements(&self, buf: &B::Buffer) -> Requirements;
unsafe fn bind_buffer_memory(
&self,
memory: &B::Memory,
offset: u64,
buf: &mut B::Buffer,
) -> Result<(), BindError>;
unsafe fn destroy_buffer(&self, buffer: B::Buffer);
unsafe fn create_buffer_view(
&self,
buf: &B::Buffer,
fmt: Option<format::Format>,
range: buffer::SubRange,
) -> Result<B::BufferView, buffer::ViewCreationError>;
unsafe fn destroy_buffer_view(&self, view: B::BufferView);
unsafe fn create_image(
&self,
kind: image::Kind,
mip_levels: image::Level,
format: format::Format,
tiling: image::Tiling,
usage: image::Usage,
view_caps: image::ViewCapabilities,
) -> Result<B::Image, image::CreationError>;
unsafe fn get_image_requirements(&self, image: &B::Image) -> Requirements;
unsafe fn get_image_subresource_footprint(
&self,
image: &B::Image,
subresource: image::Subresource,
) -> image::SubresourceFootprint;
unsafe fn bind_image_memory(
&self,
memory: &B::Memory,
offset: u64,
image: &mut B::Image,
) -> Result<(), BindError>;
unsafe fn destroy_image(&self, image: B::Image);
unsafe fn create_image_view(
&self,
image: &B::Image,
view_kind: image::ViewKind,
format: format::Format,
swizzle: format::Swizzle,
range: image::SubresourceRange,
) -> Result<B::ImageView, image::ViewCreationError>;
unsafe fn destroy_image_view(&self, view: B::ImageView);
unsafe fn create_sampler(
&self,
desc: &image::SamplerDesc,
) -> Result<B::Sampler, AllocationError>;
unsafe fn destroy_sampler(&self, sampler: B::Sampler);
unsafe fn create_descriptor_pool<I>(
&self,
max_sets: usize,
descriptor_ranges: I,
flags: DescriptorPoolCreateFlags,
) -> Result<B::DescriptorPool, OutOfMemory>
where
I: Iterator<Item = pso::DescriptorRangeDesc>;
unsafe fn destroy_descriptor_pool(&self, pool: B::DescriptorPool);
unsafe fn create_descriptor_set_layout<'a, I, J>(
&self,
bindings: I,
immutable_samplers: J,
) -> Result<B::DescriptorSetLayout, OutOfMemory>
where
I: Iterator<Item = pso::DescriptorSetLayoutBinding>,
J: Iterator<Item = &'a B::Sampler>;
unsafe fn destroy_descriptor_set_layout(&self, layout: B::DescriptorSetLayout);
unsafe fn write_descriptor_set<'a, I>(&self, op: pso::DescriptorSetWrite<'a, B, I>)
where
I: Iterator<Item = pso::Descriptor<'a, B>>;
unsafe fn copy_descriptor_set<'a>(&self, op: pso::DescriptorSetCopy<'a, B>);
unsafe fn map_memory(
&self,
memory: &mut B::Memory,
segment: Segment,
) -> Result<*mut u8, MapError>;
unsafe fn flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory>
where
I: Iterator<Item = (&'a B::Memory, Segment)>;
unsafe fn invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory>
where
I: Iterator<Item = (&'a B::Memory, Segment)>;
unsafe fn unmap_memory(&self, memory: &mut B::Memory);
fn create_semaphore(&self) -> Result<B::Semaphore, OutOfMemory>;
unsafe fn destroy_semaphore(&self, semaphore: B::Semaphore);
fn create_fence(&self, signaled: bool) -> Result<B::Fence, OutOfMemory>;
unsafe fn reset_fence(&self, fence: &mut B::Fence) -> Result<(), OutOfMemory>;
unsafe fn wait_for_fence(&self, fence: &B::Fence, timeout_ns: u64) -> Result<bool, WaitError> {
self.wait_for_fences(iter::once(fence), WaitFor::All, timeout_ns)
}
unsafe fn wait_for_fences<'a, I>(
&self,
fences: I,
wait: WaitFor,
timeout_ns: u64,
) -> Result<bool, WaitError>
where
I: Iterator<Item = &'a B::Fence>,
{
use std::{thread, time};
fn to_ns(duration: time::Duration) -> u64 {
duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64
}
let start = time::Instant::now();
match wait {
WaitFor::All => {
for fence in fences {
if !self.wait_for_fence(fence, 0)? {
let elapsed_ns = to_ns(start.elapsed());
if elapsed_ns > timeout_ns {
return Ok(false);
}
if !self.wait_for_fence(fence, timeout_ns - elapsed_ns)? {
return Ok(false);
}
}
}
Ok(true)
}
WaitFor::Any => {
let fences: Vec<_> = fences.collect();
loop {
for &fence in &fences {
if self.wait_for_fence(fence, 0)? {
return Ok(true);
}
}
if to_ns(start.elapsed()) >= timeout_ns {
return Ok(false);
}
thread::sleep(time::Duration::from_millis(1));
}
}
}
}
unsafe fn get_fence_status(&self, fence: &B::Fence) -> Result<bool, DeviceLost>;
unsafe fn destroy_fence(&self, fence: B::Fence);
fn create_event(&self) -> Result<B::Event, OutOfMemory>;
unsafe fn destroy_event(&self, event: B::Event);
unsafe fn get_event_status(&self, event: &B::Event) -> Result<bool, WaitError>;
unsafe fn set_event(&self, event: &mut B::Event) -> Result<(), OutOfMemory>;
unsafe fn reset_event(&self, event: &mut B::Event) -> Result<(), OutOfMemory>;
unsafe fn create_query_pool(
&self,
ty: query::Type,
count: query::Id,
) -> Result<B::QueryPool, query::CreationError>;
unsafe fn destroy_query_pool(&self, pool: B::QueryPool);
unsafe fn get_query_pool_results(
&self,
pool: &B::QueryPool,
queries: Range<query::Id>,
data: &mut [u8],
stride: buffer::Stride,
flags: query::ResultFlags,
) -> Result<bool, WaitError>;
fn wait_idle(&self) -> Result<(), OutOfMemory>;
unsafe fn set_image_name(&self, image: &mut B::Image, name: &str);
unsafe fn set_buffer_name(&self, buffer: &mut B::Buffer, name: &str);
unsafe fn set_command_buffer_name(&self, command_buffer: &mut B::CommandBuffer, name: &str);
unsafe fn set_semaphore_name(&self, semaphore: &mut B::Semaphore, name: &str);
unsafe fn set_fence_name(&self, fence: &mut B::Fence, name: &str);
unsafe fn set_framebuffer_name(&self, framebuffer: &mut B::Framebuffer, name: &str);
unsafe fn set_render_pass_name(&self, render_pass: &mut B::RenderPass, name: &str);
unsafe fn set_descriptor_set_name(&self, descriptor_set: &mut B::DescriptorSet, name: &str);
unsafe fn set_descriptor_set_layout_name(
&self,
descriptor_set_layout: &mut B::DescriptorSetLayout,
name: &str,
);
unsafe fn set_pipeline_layout_name(&self, pipeline_layout: &mut B::PipelineLayout, name: &str);
}