//! Logical graphics device. //! //! # Device //! //! This module exposes the [`Device`][Device] trait, which provides methods for creating //! and managing graphics resources such as buffers, images and memory. //! //! The `Adapter` and `Device` types are very similar to the Vulkan concept of //! "physical devices" vs. "logical devices"; an `Adapter` is single GPU //! (or CPU) that implements a backend, a `Device` is a //! handle to that physical device that has the requested capabilities //! and is used to actually do things. use std::any::Any; use std::borrow::Borrow; use std::ops::Range; use std::{fmt, iter}; use crate::{ buffer, format, image, memory::{Requirements, Segment}, pass, pool::CommandPoolCreateFlags, pso, pso::DescriptorPoolCreateFlags, query, queue::QueueFamilyId, Backend, MemoryTypeId, }; /// Error occurred caused device to be lost. #[derive(Clone, Debug, PartialEq)] pub struct DeviceLost; impl std::fmt::Display for DeviceLost { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.write_str("Device lost") } } impl std::error::Error for DeviceLost {} /// Error occurred caused surface to be lost. #[derive(Clone, Debug, PartialEq)] pub struct SurfaceLost; impl std::fmt::Display for SurfaceLost { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.write_str("Surface lost") } } impl std::error::Error for SurfaceLost {} /// Native window is already in use by graphics API. #[derive(Clone, Debug, PartialEq)] pub struct WindowInUse; impl std::fmt::Display for WindowInUse { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.write_str("Window is in use") } } impl std::error::Error for WindowInUse {} /// Error allocating memory. #[derive(Clone, Debug, PartialEq)] pub enum OutOfMemory { /// Host memory exhausted. Host, /// Device memory exhausted. Device, } impl std::fmt::Display for OutOfMemory { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OutOfMemory::Host => write!(fmt, "Out of host memory"), OutOfMemory::Device => write!(fmt, "Out of device memory"), } } } impl std::error::Error for OutOfMemory {} /// Error occurred caused device to be lost /// or out of memory error. #[derive(Clone, Debug, PartialEq)] pub enum OomOrDeviceLost { /// Out of either host or device memory. OutOfMemory(OutOfMemory), /// Device is lost DeviceLost(DeviceLost), } impl From for OomOrDeviceLost { fn from(error: OutOfMemory) -> Self { OomOrDeviceLost::OutOfMemory(error) } } impl From for OomOrDeviceLost { fn from(error: DeviceLost) -> Self { OomOrDeviceLost::DeviceLost(error) } } impl std::fmt::Display for OomOrDeviceLost { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OomOrDeviceLost::DeviceLost(err) => write!(fmt, "Failed querying device: {}", err), OomOrDeviceLost::OutOfMemory(err) => write!(fmt, "Failed querying device: {}", err), } } } impl std::error::Error for OomOrDeviceLost { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { OomOrDeviceLost::DeviceLost(err) => Some(err), OomOrDeviceLost::OutOfMemory(err) => Some(err), } } } /// Possible cause of allocation failure. #[derive(Clone, Debug, PartialEq)] pub enum AllocationError { /// Out of either host or device memory. OutOfMemory(OutOfMemory), /// Cannot create any more objects. TooManyObjects, } impl From for AllocationError { fn from(error: OutOfMemory) -> Self { AllocationError::OutOfMemory(error) } } impl std::fmt::Display for AllocationError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AllocationError::OutOfMemory(err) => write!(fmt, "Failed to allocate object: {}", err), AllocationError::TooManyObjects => { write!(fmt, "Failed to allocate object: Too many objects") } } } } impl std::error::Error for AllocationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { AllocationError::OutOfMemory(err) => Some(err), _ => None, } } } /// Device creation errors during `open`. #[derive(Clone, Debug, PartialEq)] pub enum CreationError { /// Out of either host or device memory. OutOfMemory(OutOfMemory), /// Device initialization failed due to implementation specific errors. InitializationFailed, /// At least one of the user requested extensions if not supported by the /// physical device. MissingExtension, /// At least one of the user requested features if not supported by the /// physical device. /// /// Use [`features`](trait.PhysicalDevice.html#tymethod.features) /// for checking the supported features. MissingFeature, /// Too many logical devices have been created from this physical device. /// /// The implementation may only support one logical device for each physical /// device or lacks resources to allocate a new device. TooManyObjects, /// The logical or physical device are lost during the device creation /// process. /// /// This may be caused by hardware failure, physical device removal, /// power outage, etc. DeviceLost, } impl std::fmt::Display for CreationError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CreationError::OutOfMemory(err) => write!(fmt, "Failed to create device: {}", err), CreationError::InitializationFailed => write!( fmt, "Failed to create device: Implementation specific error occurred" ), CreationError::MissingExtension => write!( fmt, "Failed to create device: Requested extension is missing" ), CreationError::MissingFeature => { write!(fmt, "Failed to create device: Requested feature is missing") } CreationError::TooManyObjects => { write!(fmt, "Failed to create device: Too many objects") } CreationError::DeviceLost => write!( fmt, "Failed to create device: Logical or Physical device was lost during creation" ), } } } impl std::error::Error for CreationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { CreationError::OutOfMemory(err) => Some(err), _ => None, } } } /// Error accessing a mapping. #[derive(Clone, Debug, PartialEq)] pub enum MapError { /// Out of either host or device memory. OutOfMemory(OutOfMemory), /// The requested mapping range is outside of the resource. OutOfBounds, /// Failed to allocate an appropriately sized contiguous virtual address range MappingFailed, /// Memory is not CPU visible Access, } impl From for MapError { fn from(error: OutOfMemory) -> Self { MapError::OutOfMemory(error) } } impl std::fmt::Display for MapError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MapError::OutOfMemory(err) => write!(fmt, "Failed to map memory: {}", err), MapError::OutOfBounds => write!(fmt, "Failed to map memory: Requested range is outside the resource"), MapError::MappingFailed => write!( fmt, "Failed to map memory: Unable to allocate an appropriately sized contiguous virtual address range" ), MapError::Access => write!(fmt, "Failed to map memory: Memory is not CPU visible"), } } } impl std::error::Error for MapError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { MapError::OutOfMemory(err) => Some(err), _ => None, } } } /// Error binding a resource to memory allocation. #[derive(Clone, Debug, PartialEq)] pub enum BindError { /// Out of either host or device memory. OutOfMemory(OutOfMemory), /// Requested binding to memory that doesn't support the required operations. WrongMemory, /// Requested binding to an invalid memory. OutOfBounds, } impl From for BindError { fn from(error: OutOfMemory) -> Self { BindError::OutOfMemory(error) } } impl std::fmt::Display for BindError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { BindError::OutOfMemory(err) => { write!(fmt, "Failed to bind object to memory range: {}", err) } BindError::OutOfBounds => write!( fmt, "Failed to bind object to memory range: Requested range is outside the resource" ), BindError::WrongMemory => { write!(fmt, "Failed to bind object to memory range: Wrong memory") } } } } impl std::error::Error for BindError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { BindError::OutOfMemory(err) => Some(err), _ => None, } } } /// Specifies the waiting targets. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum WaitFor { /// Wait for any target. Any, /// Wait for all targets at once. All, } /// An error from creating a shader module. #[derive(Clone, Debug, PartialEq)] pub enum ShaderError { /// The shader failed to compile. CompilationFailed(String), /// The shader is missing an entry point. MissingEntryPoint(String), /// The shader has a mismatch of interface (e.g missing push constants). InterfaceMismatch(String), /// The shader stage is not supported. UnsupportedStage(pso::ShaderStageFlags), /// Out of either host or device memory. OutOfMemory(OutOfMemory), } impl From for ShaderError { fn from(error: OutOfMemory) -> Self { ShaderError::OutOfMemory(error) } } impl std::fmt::Display for ShaderError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ShaderError::OutOfMemory(err) => write!(fmt, "Shader error: {}", err), ShaderError::CompilationFailed(string) => { write!(fmt, "Shader error: Compilation failed: {}", string) } ShaderError::MissingEntryPoint(string) => { write!(fmt, "Shader error: Missing entry point: {}", string) } ShaderError::InterfaceMismatch(string) => { write!(fmt, "Shader error: Interface mismatch: {}", string) } ShaderError::UnsupportedStage(stage) => { write!(fmt, "Shader error: Unsupported stage: {:?}", stage) } } } } impl std::error::Error for ShaderError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { ShaderError::OutOfMemory(err) => Some(err), _ => None, } } } /// Logical device handle, responsible for creating and managing resources /// for the physical device it was created from. /// /// ## Resource Construction and Handling /// /// This device structure can then be used to create and manage different resources, /// like [buffers][Device::create_buffer], [shader modules][Device::create_shader_module] /// and [images][Device::create_image]. See the individual methods for more information. /// /// ## Mutability /// /// All the methods get `&self`. Any internal mutability of the `Device` is hidden from the user. /// /// ## Synchronization /// /// `Device` should be usable concurrently from multiple threads. The `Send` and `Sync` bounds /// are not enforced at the HAL level due to OpenGL constraint (to be revised). Users can still /// benefit from the backends that support synchronization of the `Device`. /// pub trait Device: fmt::Debug + Any + Send + Sync { /// Allocates a memory segment of a specified type. /// /// There is only a limited amount of allocations allowed depending on the implementation! /// /// # Arguments /// /// * `memory_type` - Index of the memory type in the memory properties of the associated physical device. /// * `size` - Size of the allocation. unsafe fn allocate_memory( &self, memory_type: MemoryTypeId, size: u64, ) -> Result; /// Free device memory unsafe fn free_memory(&self, memory: B::Memory); /// Create a new [command pool][crate::pool::CommandPool] for a given queue family. /// /// *Note*: the family has to be associated with one of [the queue groups /// of this device][crate::adapter::Gpu::queue_groups]. unsafe fn create_command_pool( &self, family: QueueFamilyId, create_flags: CommandPoolCreateFlags, ) -> Result; /// Destroy a command pool. unsafe fn destroy_command_pool(&self, pool: B::CommandPool); /// Create a [render pass][crate::pass] with the given attachments and subpasses. /// /// The use of a render pass in a command buffer is a *render pass* instance. /// /// # Arguments /// /// * `attachments` - [image attachments][crate::pass::Attachment] to be used in /// this render pass. Usually you need at least one attachment, to be used as output. /// * `subpasses` - [subpasses][crate::pass::SubpassDesc] to use. /// You need to use at least one subpass. /// * `dependencies` - [dependencies between subpasses][crate::pass::SubpassDependency]. /// Can be empty. unsafe fn create_render_pass<'a, IA, IS, ID>( &self, attachments: IA, subpasses: IS, dependencies: ID, ) -> Result where IA: IntoIterator, IA::Item: Borrow, IA::IntoIter: ExactSizeIterator, IS: IntoIterator, IS::Item: Borrow>, IS::IntoIter: ExactSizeIterator, ID: IntoIterator, ID::Item: Borrow, ID::IntoIter: ExactSizeIterator; /// Destroys a *render pass* created by this device. unsafe fn destroy_render_pass(&self, rp: B::RenderPass); /// Create a new pipeline layout object. /// /// # Arguments /// /// * `set_layouts` - Descriptor set layouts /// * `push_constants` - Ranges of push constants. A shader stage may only contain one push /// constant block. The range is defined in units of bytes. /// /// # PipelineLayout /// /// Access to descriptor sets from a pipeline is accomplished through a *pipeline layout*. /// Zero or more descriptor set layouts and zero or more push constant ranges are combined to /// form a pipeline layout object which describes the complete set of resources that **can** be /// accessed by a pipeline. The pipeline layout represents a sequence of descriptor sets with /// each having a specific layout. This sequence of layouts is used to determine the interface /// between shader stages and shader resources. Each pipeline is created using a pipeline layout. unsafe fn create_pipeline_layout( &self, set_layouts: IS, push_constant: IR, ) -> Result where IS: IntoIterator, IS::Item: Borrow, IS::IntoIter: ExactSizeIterator, IR: IntoIterator, IR::Item: Borrow<(pso::ShaderStageFlags, Range)>, IR::IntoIter: ExactSizeIterator; /// Destroy a pipeline layout object unsafe fn destroy_pipeline_layout(&self, layout: B::PipelineLayout); /// Create a pipeline cache object. unsafe fn create_pipeline_cache( &self, data: Option<&[u8]>, ) -> Result; /// Retrieve data from pipeline cache object. unsafe fn get_pipeline_cache_data( &self, cache: &B::PipelineCache, ) -> Result, OutOfMemory>; /// Merge a number of source pipeline caches into the target one. unsafe fn merge_pipeline_caches( &self, target: &B::PipelineCache, sources: I, ) -> Result<(), OutOfMemory> where I: IntoIterator, I::Item: Borrow, I::IntoIter: ExactSizeIterator; /// Destroy a pipeline cache object. unsafe fn destroy_pipeline_cache(&self, cache: B::PipelineCache); /// Create a graphics pipeline. /// /// # Arguments /// /// * `desc` - the [description][crate::pso::GraphicsPipelineDesc] of /// the graphics pipeline to create. /// * `cache` - the pipeline cache, /// [obtained from this device][Device::create_pipeline_cache], /// used for faster PSO creation. unsafe fn create_graphics_pipeline<'a>( &self, desc: &pso::GraphicsPipelineDesc<'a, B>, cache: Option<&B::PipelineCache>, ) -> Result; /// Create multiple graphics pipelines. unsafe fn create_graphics_pipelines<'a, I>( &self, descs: I, cache: Option<&B::PipelineCache>, ) -> Vec> where I: IntoIterator, I::Item: Borrow>, { descs .into_iter() .map(|desc| self.create_graphics_pipeline(desc.borrow(), cache)) .collect() } /// Destroy a graphics pipeline. /// /// The graphics pipeline shouldn't be destroyed before any submitted command buffer, /// which references the graphics pipeline, has finished execution. unsafe fn destroy_graphics_pipeline(&self, pipeline: B::GraphicsPipeline); /// Create a compute pipeline. unsafe fn create_compute_pipeline<'a>( &self, desc: &pso::ComputePipelineDesc<'a, B>, cache: Option<&B::PipelineCache>, ) -> Result; /// Create compute pipelines. unsafe fn create_compute_pipelines<'a, I>( &self, descs: I, cache: Option<&B::PipelineCache>, ) -> Vec> where I: IntoIterator, I::Item: Borrow>, { descs .into_iter() .map(|desc| self.create_compute_pipeline(desc.borrow(), cache)) .collect() } /// Destroy a compute pipeline. /// /// The compute pipeline shouldn't be destroyed before any submitted command buffer, /// which references the compute pipeline, has finished execution. unsafe fn destroy_compute_pipeline(&self, pipeline: B::ComputePipeline); /// Create a new framebuffer object. /// /// # Safety /// - `extent.width`, `extent.height` and `extent.depth` **must** be greater than `0`. unsafe fn create_framebuffer( &self, pass: &B::RenderPass, attachments: I, extent: image::Extent, ) -> Result where I: IntoIterator, I::Item: Borrow; /// Destroy a framebuffer. /// /// The framebuffer shouldn't be destroy before any submitted command buffer, /// which references the framebuffer, has finished execution. unsafe fn destroy_framebuffer(&self, buf: B::Framebuffer); /// Create a new shader module object from the SPIR-V binary data. /// /// Once a shader module has been created, any [entry points][crate::pso::EntryPoint] /// it contains can be used in pipeline shader stages of /// [compute pipelines][crate::pso::ComputePipelineDesc] and /// [graphics pipelines][crate::pso::GraphicsPipelineDesc]. unsafe fn create_shader_module( &self, spirv_data: &[u32], ) -> Result; /// Destroy a shader module module /// /// A shader module can be destroyed while pipelines created using its shaders are still in use. unsafe fn destroy_shader_module(&self, shader: B::ShaderModule); /// Create a new buffer (unbound). /// /// The created buffer won't have associated memory until `bind_buffer_memory` is called. unsafe fn create_buffer( &self, size: u64, usage: buffer::Usage, ) -> Result; /// Get memory requirements for the buffer unsafe fn get_buffer_requirements(&self, buf: &B::Buffer) -> Requirements; /// Bind memory to a buffer. /// /// Be sure to check that there is enough memory available for the buffer. /// Use `get_buffer_requirements` to acquire the memory requirements. unsafe fn bind_buffer_memory( &self, memory: &B::Memory, offset: u64, buf: &mut B::Buffer, ) -> Result<(), BindError>; /// Destroy a buffer. /// /// The buffer shouldn't be destroyed before any submitted command buffer, /// which references the images, has finished execution. unsafe fn destroy_buffer(&self, buffer: B::Buffer); /// Create a new buffer view object unsafe fn create_buffer_view( &self, buf: &B::Buffer, fmt: Option, range: buffer::SubRange, ) -> Result; /// Destroy a buffer view object unsafe fn destroy_buffer_view(&self, view: B::BufferView); /// Create a new image object 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; /// Get memory requirements for the Image 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; /// Bind device memory to an image object unsafe fn bind_image_memory( &self, memory: &B::Memory, offset: u64, image: &mut B::Image, ) -> Result<(), BindError>; /// Destroy an image. /// /// The image shouldn't be destroyed before any submitted command buffer, /// which references the images, has finished execution. unsafe fn destroy_image(&self, image: B::Image); /// Create an image view from an existing image unsafe fn create_image_view( &self, image: &B::Image, view_kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, range: image::SubresourceRange, ) -> Result; /// Destroy an image view object unsafe fn destroy_image_view(&self, view: B::ImageView); /// Create a new sampler object unsafe fn create_sampler( &self, desc: &image::SamplerDesc, ) -> Result; /// Destroy a sampler object unsafe fn destroy_sampler(&self, sampler: B::Sampler); /// Create a descriptor pool. /// /// Descriptor pools allow allocation of descriptor sets. /// The pool can't be modified directly, only through updating descriptor sets. unsafe fn create_descriptor_pool( &self, max_sets: usize, descriptor_ranges: I, flags: DescriptorPoolCreateFlags, ) -> Result where I: IntoIterator, I::Item: Borrow, I::IntoIter: ExactSizeIterator; /// Destroy a descriptor pool object /// /// When a pool is destroyed, all descriptor sets allocated from the pool are implicitly freed /// and become invalid. Descriptor sets allocated from a given pool do not need to be freed /// before destroying that descriptor pool. unsafe fn destroy_descriptor_pool(&self, pool: B::DescriptorPool); /// Create a descriptor set layout. /// /// A descriptor set layout object is defined by an array of zero or more descriptor bindings. /// Each individual descriptor binding is specified by a descriptor type, a count (array size) /// of the number of descriptors in the binding, a set of shader stages that **can** access the /// binding, and (if using immutable samplers) an array of sampler descriptors. unsafe fn create_descriptor_set_layout( &self, bindings: I, immutable_samplers: J, ) -> Result where I: IntoIterator, I::Item: Borrow, J: IntoIterator, J::Item: Borrow, J::IntoIter: ExactSizeIterator; /// Destroy a descriptor set layout object unsafe fn destroy_descriptor_set_layout(&self, layout: B::DescriptorSetLayout); /// Specifying the parameters of a descriptor set write operation unsafe fn write_descriptor_sets<'a, I, J>(&self, write_iter: I) where I: IntoIterator>, J: IntoIterator, J::Item: Borrow>; /// Structure specifying a copy descriptor set operation unsafe fn copy_descriptor_sets<'a, I>(&self, copy_iter: I) where I: IntoIterator, I::Item: Borrow>, I::IntoIter: ExactSizeIterator; /// Map a memory object into application address space /// /// Call `map_memory()` to retrieve a host virtual address pointer to a region of a mappable memory object unsafe fn map_memory(&self, memory: &B::Memory, segment: Segment) -> Result<*mut u8, MapError>; /// Flush mapped memory ranges unsafe fn flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory> where I: IntoIterator, I::Item: Borrow<(&'a B::Memory, Segment)>; /// Invalidate ranges of non-coherent memory from the host caches unsafe fn invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory> where I: IntoIterator, I::Item: Borrow<(&'a B::Memory, Segment)>; /// Unmap a memory object once host access to it is no longer needed by the application unsafe fn unmap_memory(&self, memory: &B::Memory); /// Create a new semaphore object. fn create_semaphore(&self) -> Result; /// Destroy a semaphore object. unsafe fn destroy_semaphore(&self, semaphore: B::Semaphore); /// Create a new fence object. /// /// Fences are a synchronization primitive that **can** be used to insert a dependency from /// a queue to the host. /// Fences have two states - signaled and unsignaled. /// /// A fence **can** be signaled as part of the execution of a /// [queue submission][crate::queue::CommandQueue::submit] command. /// /// Fences **can** be unsignaled on the host with /// [`reset_fences`][Device::reset_fences]. /// /// Fences **can** be waited on by the host with the /// [`wait_for_fences`][Device::wait_for_fences] command. /// /// A fence's current state **can** be queried with /// [`get_fence_status`][Device::get_fence_status]. /// /// # Arguments /// /// * `signaled` - the fence will be in its signaled state. fn create_fence(&self, signaled: bool) -> Result; /// Resets a given fence to its original, unsignaled state. unsafe fn reset_fence(&self, fence: &B::Fence) -> Result<(), OutOfMemory> { self.reset_fences(iter::once(fence)) } /// Resets multiple fences to their original states. unsafe fn reset_fences(&self, fences: I) -> Result<(), OutOfMemory> where I: IntoIterator, I::Item: Borrow, I::IntoIter: ExactSizeIterator, { for fence in fences { self.reset_fence(fence.borrow())?; } Ok(()) } /// Blocks until the given fence is signaled. /// Returns true if the fence was signaled before the timeout. unsafe fn wait_for_fence( &self, fence: &B::Fence, timeout_ns: u64, ) -> Result { self.wait_for_fences(iter::once(fence), WaitFor::All, timeout_ns) } /// Blocks until all or one of the given fences are signaled. /// Returns true if fences were signaled before the timeout. unsafe fn wait_for_fences( &self, fences: I, wait: WaitFor, timeout_ns: u64, ) -> Result where I: IntoIterator, I::Item: Borrow, I::IntoIter: ExactSizeIterator, { 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.borrow(), 0)? { let elapsed_ns = to_ns(start.elapsed()); if elapsed_ns > timeout_ns { return Ok(false); } if !self.wait_for_fence(fence.borrow(), timeout_ns - elapsed_ns)? { return Ok(false); } } } Ok(true) } WaitFor::Any => { let fences: Vec<_> = fences.into_iter().collect(); loop { for fence in &fences { if self.wait_for_fence(fence.borrow(), 0)? { return Ok(true); } } if to_ns(start.elapsed()) >= timeout_ns { return Ok(false); } thread::sleep(time::Duration::from_millis(1)); } } } } /// true for signaled, false for not ready unsafe fn get_fence_status(&self, fence: &B::Fence) -> Result; /// Destroy a fence object unsafe fn destroy_fence(&self, fence: B::Fence); /// Create an event object. fn create_event(&self) -> Result; /// Destroy an event object. unsafe fn destroy_event(&self, event: B::Event); /// Query the status of an event. /// /// Returns `true` if the event is set, or `false` if it is reset. unsafe fn get_event_status(&self, event: &B::Event) -> Result; /// Sets an event. unsafe fn set_event(&self, event: &B::Event) -> Result<(), OutOfMemory>; /// Resets an event. unsafe fn reset_event(&self, event: &B::Event) -> Result<(), OutOfMemory>; /// Create a new query pool object /// /// Queries are managed using query pool objects. Each query pool is a collection of a specific /// number of queries of a particular type. unsafe fn create_query_pool( &self, ty: query::Type, count: query::Id, ) -> Result; /// Destroy a query pool object unsafe fn destroy_query_pool(&self, pool: B::QueryPool); /// Get query pool results into the specified CPU memory. /// Returns `Ok(false)` if the results are not ready yet and neither of `WAIT` or `PARTIAL` flags are set. unsafe fn get_query_pool_results( &self, pool: &B::QueryPool, queries: Range, data: &mut [u8], stride: buffer::Offset, flags: query::ResultFlags, ) -> Result; /// Wait for all queues associated with this device to idle. /// /// Host access to all queues needs to be **externally** sycnhronized! fn wait_idle(&self) -> Result<(), OutOfMemory>; /// Associate a name with an image, for easier debugging in external tools or with validation /// layers that can print a friendly name when referring to objects in error messages unsafe fn set_image_name(&self, image: &mut B::Image, name: &str); /// Associate a name with a buffer, for easier debugging in external tools or with validation /// layers that can print a friendly name when referring to objects in error messages unsafe fn set_buffer_name(&self, buffer: &mut B::Buffer, name: &str); /// Associate a name with a command buffer, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_command_buffer_name(&self, command_buffer: &mut B::CommandBuffer, name: &str); /// Associate a name with a semaphore, for easier debugging in external tools or with validation /// layers that can print a friendly name when referring to objects in error messages unsafe fn set_semaphore_name(&self, semaphore: &mut B::Semaphore, name: &str); /// Associate a name with a fence, for easier debugging in external tools or with validation /// layers that can print a friendly name when referring to objects in error messages unsafe fn set_fence_name(&self, fence: &mut B::Fence, name: &str); /// Associate a name with a framebuffer, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_framebuffer_name(&self, framebuffer: &mut B::Framebuffer, name: &str); /// Associate a name with a render pass, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_render_pass_name(&self, render_pass: &mut B::RenderPass, name: &str); /// Associate a name with a descriptor set, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_descriptor_set_name(&self, descriptor_set: &mut B::DescriptorSet, name: &str); /// Associate a name with a descriptor set layout, for easier debugging in external tools or /// with validation layers that can print a friendly name when referring to objects in error /// messages unsafe fn set_descriptor_set_layout_name( &self, descriptor_set_layout: &mut B::DescriptorSetLayout, name: &str, ); /// Associate a name with a pipeline layout, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_pipeline_layout_name(&self, pipeline_layout: &mut B::PipelineLayout, name: &str); /// Associate a name with a compute pipeline, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_compute_pipeline_name( &self, compute_pipeline: &mut B::ComputePipeline, name: &str, ); /// Associate a name with a graphics pipeline, for easier debugging in external tools or with /// validation layers that can print a friendly name when referring to objects in error messages unsafe fn set_graphics_pipeline_name( &self, graphics_pipeline: &mut B::GraphicsPipeline, name: &str, ); }