1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
//! Physical devices and adapters. //! //! The `PhysicalDevice` trait specifies the API a backend must provide for dealing with //! and querying a physical device, such as a particular GPU. An `Adapter` is a struct //! containing a `PhysicalDevice` and metadata for a particular GPU, generally created //! from an `Instance` of that backend. `adapter.open_with(...)` will return a `Device` //! that has the properties specified. use std::any::Any; use std::fmt; use crate::error::DeviceCreationError; use crate::queue::{Capability, QueueGroup}; use crate::{format, image, memory, Backend, Features, Gpu, Limits}; /// Scheduling hint for devices about the priority of a queue. Values range from `0.0` (low) to /// `1.0` (high). pub type QueuePriority = f32; /// A strongly-typed index to a particular `MemoryType`. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct MemoryTypeId(pub usize); impl From<usize> for MemoryTypeId { fn from(id: usize) -> Self { MemoryTypeId(id) } } /// A description for a single chunk of memory in a heap. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct MemoryType { /// Properties of the associated memory, such as synchronization /// properties or whether it's on the CPU or GPU. pub properties: memory::Properties, /// Index to the underlying memory heap in `Gpu::memory_heaps` pub heap_index: usize, } /// Types of memory supported by this adapter and available memory. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct MemoryProperties { /// Each memory type is associated with one heap of `memory_heaps`. /// Multiple types can point to the same heap. pub memory_types: Vec<MemoryType>, /// Memory heaps with their size in bytes. pub memory_heaps: Vec<u64>, } /// Represents a physical device (such as a GPU) capable of supporting the given backend. pub trait PhysicalDevice<B: Backend>: fmt::Debug + Any + Send + Sync { /// Create a new logical device with the requested features. If `requested_features` is /// empty (e.g. through `Features::empty()`) then only the core features are supported. /// /// # Errors /// /// - Returns `TooManyObjects` if the implementation can't create a new logical device. /// - Returns `MissingFeature` if the implementation does not support a requested feature. /// /// # Examples /// /// ```no_run /// # extern crate gfx_backend_empty as empty; /// # extern crate gfx_hal; /// # fn main() { /// use gfx_hal::{PhysicalDevice, Features}; /// /// # let physical_device: empty::PhysicalDevice = return; /// # let family: empty::QueueFamily = return; /// # unsafe { /// let gpu = physical_device.open(&[(&family, &[1.0; 1])], Features::empty()); /// # }} /// ``` unsafe fn open( &self, families: &[(&B::QueueFamily, &[QueuePriority])], requested_features: Features, ) -> Result<Gpu<B>, DeviceCreationError>; /// Fetch details for a particular format. fn format_properties(&self, format: Option<format::Format>) -> format::Properties; /// Fetch details for a particular image format. fn image_format_properties( &self, format: format::Format, dimensions: u8, tiling: image::Tiling, usage: image::Usage, view_caps: image::ViewCapabilities, ) -> Option<image::FormatProperties>; /// Fetch details for the memory regions provided by the device. fn memory_properties(&self) -> MemoryProperties; /// Returns the features of this `Device`. This usually depends on the graphics API being /// used. fn features(&self) -> Features; /// Returns the resource limits of this `Device`. fn limits(&self) -> Limits; /// Check cache compatibility with the `Device`. fn is_valid_cache(&self, _cache: &[u8]) -> bool { false } } /// Supported physical device types #[derive(Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum DeviceType { /// Other Other = 0, /// Integrated IntegratedGpu = 1, /// Discrete DiscreteGpu = 2, /// Virtual / Hosted VirtualGpu = 3, /// Cpu / Software Rendering Cpu = 4, } /// Metadata about a backend adapter. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct AdapterInfo { /// Adapter name pub name: String, /// Vendor PCI id of the adapter pub vendor: usize, /// PCI id of the adapter pub device: usize, /// Type of device pub device_type: DeviceType, } /// The list of `Adapter` instances is obtained by calling `Instance::enumerate_adapters()`. /// /// Given an `Adapter` a `Gpu` can be constructed by calling `PhysicalDevice::open()` on its /// `physical_device` field. However, if only a single queue family is needed or if no /// additional device features are required, then the `Adapter::open_with` convenience method /// can be used instead. #[derive(Debug)] pub struct Adapter<B: Backend> { /// General information about this adapter. pub info: AdapterInfo, /// Actual physical device. pub physical_device: B::PhysicalDevice, /// Queue families supported by this adapter. pub queue_families: Vec<B::QueueFamily>, } impl<B: Backend> Adapter<B> { /// Open the physical device with `count` queues from some active queue family. The family is /// the first that both provides the capability `C`, supports at least `count` queues, and for /// which `selector` returns true. /// /// # Examples /// /// ```no_run /// # extern crate gfx_backend_empty as empty; /// # extern crate gfx_hal as hal; /// use hal::General; /// # fn main() { /// /// # let mut adapter: hal::Adapter<empty::Backend> = return; /// let (device, queues) = adapter.open_with::<_, General>(1, |_| true).unwrap(); /// # } /// ``` /// /// # Return /// /// Returns the same errors as `open` and `InitializationFailed` if no suitable /// queue family could be found. pub fn open_with<F, C>( &self, count: usize, selector: F, ) -> Result<(B::Device, QueueGroup<B, C>), DeviceCreationError> where F: Fn(&B::QueueFamily) -> bool, C: Capability, { use crate::queue::QueueFamily; let requested_family = self.queue_families.iter().find(|family| { C::supported_by(family.queue_type()) && selector(family) && count <= family.max_queues() }); let priorities = vec![1.0; count]; let (id, families) = match requested_family { Some(family) => (family.id(), [(family, priorities.as_slice())]), _ => return Err(DeviceCreationError::InitializationFailed), }; let Gpu { device, mut queues } = unsafe { self.physical_device.open(&families, Features::empty()) }?; Ok((device, queues.take(id).unwrap())) } }