1 /*!
2 # D3D12 backend internals.
3 
4 ## Resource transitions
5 
6 Vulkan semantics for resource states doesn't exactly match D3D12.
7 
8 For regular images, whenever there is a specific layout used,
9 we map it to a corresponding D3D12 resource state.
10 
11 For the swapchain images, we consider them to be in COMMON state
12 everywhere except for render passes, where it's forcefully
13 transitioned into the render state. When transfers to/from are
14 requested, we transition them into and from the COPY_ states.
15 
16 For buffers and images in General layout, we the best effort of guessing
17 the single mutable state based on the access flags. We can't reliably
18 handle a case where multiple mutable access flags are used.
19 */
20 
21 #[macro_use]
22 extern crate bitflags;
23 #[macro_use]
24 extern crate log;
25 
26 mod command;
27 mod conv;
28 mod descriptors_cpu;
29 mod device;
30 mod internal;
31 mod pool;
32 mod resource;
33 mod root_constants;
34 mod window;
35 
36 use auxil::FastHashMap;
37 use hal::{
38     adapter, format as f, image, memory, pso::PipelineStage, queue as q, Features, Limits,
39     PhysicalDeviceProperties,
40 };
41 use range_alloc::RangeAllocator;
42 
43 use parking_lot::{Mutex, RwLock};
44 use smallvec::SmallVec;
45 use winapi::{
46     shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, minwindef::TRUE, winerror},
47     um::{d3d12, d3d12sdklayers, handleapi, synchapi, winbase},
48     Interface,
49 };
50 
51 use std::{
52     borrow::{Borrow, BorrowMut},
53     ffi::OsString,
54     fmt,
55     mem,
56     os::windows::ffi::OsStringExt,
57     //TODO: use parking_lot
58     sync::Arc,
59 };
60 
61 use self::descriptors_cpu::DescriptorCpuPool;
62 use crate::resource::Image;
63 
64 #[derive(Debug)]
65 pub(crate) struct HeapProperties {
66     pub page_property: d3d12::D3D12_CPU_PAGE_PROPERTY,
67     pub memory_pool: d3d12::D3D12_MEMORY_POOL,
68 }
69 
70 // https://msdn.microsoft.com/de-de/library/windows/desktop/dn770377(v=vs.85).aspx
71 // Only 16 input slots allowed.
72 const MAX_VERTEX_BUFFERS: usize = 16;
73 const MAX_DESCRIPTOR_SETS: usize = 8;
74 
75 const NUM_HEAP_PROPERTIES: usize = 3;
76 
77 pub type DescriptorIndex = u64;
78 
79 // Memory types are grouped according to the supported resources.
80 // Grouping is done to circumvent the limitations of heap tier 1 devices.
81 // Devices with Tier 1 will expose `BuffersOnly`, `ImageOnly` and `TargetOnly`.
82 // Devices with Tier 2 or higher will only expose `Universal`.
83 enum MemoryGroup {
84     Universal = 0,
85     BufferOnly,
86     ImageOnly,
87     TargetOnly,
88 
89     NumGroups,
90 }
91 
92 // https://msdn.microsoft.com/de-de/library/windows/desktop/dn788678(v=vs.85).aspx
93 static HEAPS_NUMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
94     // DEFAULT
95     HeapProperties {
96         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
97         memory_pool: d3d12::D3D12_MEMORY_POOL_L1,
98     },
99     // UPLOAD
100     HeapProperties {
101         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
102         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
103     },
104     // READBACK
105     HeapProperties {
106         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
107         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
108     },
109 ];
110 
111 static HEAPS_UMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
112     // DEFAULT
113     HeapProperties {
114         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
115         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
116     },
117     // UPLOAD
118     HeapProperties {
119         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
120         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
121     },
122     // READBACK
123     HeapProperties {
124         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
125         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
126     },
127 ];
128 
129 static HEAPS_CCUMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
130     // DEFAULT
131     HeapProperties {
132         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
133         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
134     },
135     // UPLOAD
136     HeapProperties {
137         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
138         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
139     },
140     //READBACK
141     HeapProperties {
142         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
143         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
144     },
145 ];
146 
147 #[derive(Debug, Copy, Clone)]
148 pub enum QueueFamily {
149     // Specially marked present queue.
150     // It's basically a normal 3D queue but D3D12 swapchain creation requires an
151     // associated queue, which we don't know on `create_swapchain`.
152     Present,
153     Normal(q::QueueType),
154 }
155 
156 const MAX_QUEUES: usize = 16; // infinite, to be fair
157 
158 impl q::QueueFamily for QueueFamily {
queue_type(&self) -> q::QueueType159     fn queue_type(&self) -> q::QueueType {
160         match *self {
161             QueueFamily::Present => q::QueueType::General,
162             QueueFamily::Normal(ty) => ty,
163         }
164     }
max_queues(&self) -> usize165     fn max_queues(&self) -> usize {
166         match *self {
167             QueueFamily::Present => 1,
168             QueueFamily::Normal(_) => MAX_QUEUES,
169         }
170     }
id(&self) -> q::QueueFamilyId171     fn id(&self) -> q::QueueFamilyId {
172         // This must match the order exposed by `QUEUE_FAMILIES`
173         q::QueueFamilyId(match *self {
174             QueueFamily::Present => 0,
175             QueueFamily::Normal(q::QueueType::General) => 1,
176             QueueFamily::Normal(q::QueueType::Compute) => 2,
177             QueueFamily::Normal(q::QueueType::Transfer) => 3,
178             _ => unreachable!(),
179         })
180     }
supports_sparse_binding(&self) -> bool181     fn supports_sparse_binding(&self) -> bool {
182         true
183     }
184 }
185 
186 impl QueueFamily {
native_type(&self) -> native::CmdListType187     fn native_type(&self) -> native::CmdListType {
188         use hal::queue::QueueFamily as _;
189         use native::CmdListType as Clt;
190 
191         let queue_type = self.queue_type();
192         match queue_type {
193             q::QueueType::General | q::QueueType::Graphics => Clt::Direct,
194             q::QueueType::Compute => Clt::Compute,
195             q::QueueType::Transfer => Clt::Copy,
196         }
197     }
198 }
199 
200 static QUEUE_FAMILIES: [QueueFamily; 4] = [
201     QueueFamily::Present,
202     QueueFamily::Normal(q::QueueType::General),
203     QueueFamily::Normal(q::QueueType::Compute),
204     QueueFamily::Normal(q::QueueType::Transfer),
205 ];
206 
207 #[derive(Default)]
208 struct Workarounds {
209     // On WARP, temporary CPU descriptors are still used by the runtime
210     // after we call `CopyDescriptors`.
211     avoid_cpu_descriptor_overwrites: bool,
212 }
213 
214 //Note: fields are dropped in the order of declaration, so we put the
215 // most owning fields last.
216 pub struct PhysicalDevice {
217     features: Features,
218     properties: PhysicalDeviceProperties,
219     format_properties: Arc<FormatProperties>,
220     private_caps: PrivateCapabilities,
221     workarounds: Workarounds,
222     heap_properties: &'static [HeapProperties; NUM_HEAP_PROPERTIES],
223     memory_properties: adapter::MemoryProperties,
224     // Indicates that there is currently an active logical device.
225     // Opening the same adapter multiple times will return the same D3D12Device again.
226     is_open: Arc<Mutex<bool>>,
227     adapter: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
228     library: Arc<native::D3D12Lib>,
229 }
230 
231 impl fmt::Debug for PhysicalDevice {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result232     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
233         fmt.write_str("PhysicalDevice")
234     }
235 }
236 
237 unsafe impl Send for PhysicalDevice {}
238 unsafe impl Sync for PhysicalDevice {}
239 
240 impl adapter::PhysicalDevice<Backend> for PhysicalDevice {
open( &self, families: &[(&QueueFamily, &[q::QueuePriority])], requested_features: Features, ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError>241     unsafe fn open(
242         &self,
243         families: &[(&QueueFamily, &[q::QueuePriority])],
244         requested_features: Features,
245     ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError> {
246         let mut open_guard = match self.is_open.try_lock() {
247             Some(inner) => inner,
248             None => return Err(hal::device::CreationError::TooManyObjects),
249         };
250 
251         if !self.features().contains(requested_features) {
252             return Err(hal::device::CreationError::MissingFeature);
253         }
254 
255         let device_raw = match self
256             .library
257             .create_device(self.adapter, native::FeatureLevel::L11_0)
258         {
259             Ok((device, hr)) if winerror::SUCCEEDED(hr) => device,
260             Ok((_, hr)) => {
261                 error!("error on device creation: {:x}", hr);
262                 return Err(hal::device::CreationError::InitializationFailed);
263             }
264             Err(e) => panic!("device creation failed with {:?}", e),
265         };
266 
267         // Always create the presentation queue in case we want to build a swapchain.
268         let (present_queue, hr_queue) = device_raw.create_command_queue(
269             QueueFamily::Present.native_type(),
270             native::Priority::Normal,
271             native::CommandQueueFlags::empty(),
272             0,
273         );
274         if !winerror::SUCCEEDED(hr_queue) {
275             error!("error on queue creation: {:x}", hr_queue);
276         }
277 
278         let mut device = Device::new(device_raw, &self, present_queue);
279         device.features = requested_features;
280 
281         let queue_groups = families
282             .iter()
283             .map(|&(&family, priorities)| {
284                 use hal::queue::QueueFamily as _;
285                 let mut group = q::QueueGroup::new(family.id());
286 
287                 let create_idle_event = || native::Event::create(true, false);
288 
289                 match family {
290                     QueueFamily::Present => {
291                         // Exactly **one** present queue!
292                         // Number of queues need to be larger than 0 else it
293                         // violates the specification.
294                         let queue = Queue {
295                             raw: device.present_queue.clone(),
296                             idle_fence: device.create_raw_fence(false),
297                             idle_event: create_idle_event(),
298                         };
299                         device.append_queue(queue.clone());
300                         group.add_queue(queue);
301                     }
302                     QueueFamily::Normal(_) => {
303                         let list_type = family.native_type();
304                         for _ in 0..priorities.len() {
305                             let (queue, hr_queue) = device_raw.create_command_queue(
306                                 list_type,
307                                 native::Priority::Normal,
308                                 native::CommandQueueFlags::empty(),
309                                 0,
310                             );
311 
312                             if winerror::SUCCEEDED(hr_queue) {
313                                 let queue = Queue {
314                                     raw: queue,
315                                     idle_fence: device.create_raw_fence(false),
316                                     idle_event: create_idle_event(),
317                                 };
318                                 device.append_queue(queue.clone());
319                                 group.add_queue(queue);
320                             } else {
321                                 error!("error on queue creation: {:x}", hr_queue);
322                             }
323                         }
324                     }
325                 }
326 
327                 group
328             })
329             .collect();
330 
331         *open_guard = true;
332 
333         Ok(adapter::Gpu {
334             device,
335             queue_groups,
336         })
337     }
338 
format_properties(&self, fmt: Option<f::Format>) -> f::Properties339     fn format_properties(&self, fmt: Option<f::Format>) -> f::Properties {
340         let idx = fmt.map(|fmt| fmt as usize).unwrap_or(0);
341         self.format_properties.resolve(idx).properties
342     }
343 
image_format_properties( &self, format: f::Format, dimensions: u8, tiling: image::Tiling, usage: image::Usage, view_caps: image::ViewCapabilities, ) -> Option<image::FormatProperties>344     fn image_format_properties(
345         &self,
346         format: f::Format,
347         dimensions: u8,
348         tiling: image::Tiling,
349         usage: image::Usage,
350         view_caps: image::ViewCapabilities,
351     ) -> Option<image::FormatProperties> {
352         conv::map_format(format)?; //filter out unknown formats
353         let format_info = self.format_properties.resolve(format as usize);
354 
355         let supported_usage = {
356             use hal::image::Usage as U;
357             let props = match tiling {
358                 image::Tiling::Optimal => format_info.properties.optimal_tiling,
359                 image::Tiling::Linear => format_info.properties.linear_tiling,
360             };
361             let mut flags = U::empty();
362             if props.contains(f::ImageFeature::TRANSFER_SRC) {
363                 flags |= U::TRANSFER_SRC;
364             }
365             if props.contains(f::ImageFeature::TRANSFER_DST) {
366                 flags |= U::TRANSFER_DST;
367             }
368             if props.contains(f::ImageFeature::SAMPLED) {
369                 flags |= U::SAMPLED;
370             }
371             if props.contains(f::ImageFeature::STORAGE) {
372                 flags |= U::STORAGE;
373             }
374             if props.contains(f::ImageFeature::COLOR_ATTACHMENT) {
375                 flags |= U::COLOR_ATTACHMENT;
376             }
377             if props.contains(f::ImageFeature::DEPTH_STENCIL_ATTACHMENT) {
378                 flags |= U::DEPTH_STENCIL_ATTACHMENT;
379             }
380             flags
381         };
382         if !supported_usage.contains(usage) {
383             return None;
384         }
385 
386         let max_resource_size =
387             (d3d12::D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM as usize) << 20;
388         Some(match tiling {
389             image::Tiling::Optimal => image::FormatProperties {
390                 max_extent: match dimensions {
391                     1 => image::Extent {
392                         width: d3d12::D3D12_REQ_TEXTURE1D_U_DIMENSION,
393                         height: 1,
394                         depth: 1,
395                     },
396                     2 => image::Extent {
397                         width: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
398                         height: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
399                         depth: 1,
400                     },
401                     3 => image::Extent {
402                         width: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
403                         height: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
404                         depth: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
405                     },
406                     _ => return None,
407                 },
408                 max_levels: d3d12::D3D12_REQ_MIP_LEVELS as _,
409                 max_layers: match dimensions {
410                     1 => d3d12::D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION as _,
411                     2 => d3d12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
412                     _ => return None,
413                 },
414                 sample_count_mask: if dimensions == 2
415                     && !view_caps.contains(image::ViewCapabilities::KIND_CUBE)
416                     && !usage.contains(image::Usage::STORAGE)
417                 {
418                     format_info.sample_count_mask
419                 } else {
420                     0x1
421                 },
422                 max_resource_size,
423             },
424             image::Tiling::Linear => image::FormatProperties {
425                 max_extent: match dimensions {
426                     2 => image::Extent {
427                         width: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
428                         height: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
429                         depth: 1,
430                     },
431                     _ => return None,
432                 },
433                 max_levels: 1,
434                 max_layers: 1,
435                 sample_count_mask: 0x1,
436                 max_resource_size,
437             },
438         })
439     }
440 
memory_properties(&self) -> adapter::MemoryProperties441     fn memory_properties(&self) -> adapter::MemoryProperties {
442         self.memory_properties.clone()
443     }
444 
features(&self) -> Features445     fn features(&self) -> Features {
446         self.features
447     }
448 
properties(&self) -> PhysicalDeviceProperties449     fn properties(&self) -> PhysicalDeviceProperties {
450         self.properties
451     }
452 }
453 
454 #[derive(Clone)]
455 pub struct Queue {
456     pub(crate) raw: native::CommandQueue,
457     idle_fence: native::Fence,
458     idle_event: native::Event,
459 }
460 
461 impl fmt::Debug for Queue {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result462     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
463         fmt.write_str("Queue")
464     }
465 }
466 
467 impl Queue {
destroy(&self)468     unsafe fn destroy(&self) {
469         handleapi::CloseHandle(self.idle_event.0);
470         self.idle_fence.destroy();
471         self.raw.destroy();
472     }
473 
wait_idle_impl(&self) -> Result<(), hal::device::OutOfMemory>474     fn wait_idle_impl(&self) -> Result<(), hal::device::OutOfMemory> {
475         self.raw.signal(self.idle_fence, 1);
476         assert_eq!(
477             winerror::S_OK,
478             self.idle_fence.set_event_on_completion(self.idle_event, 1)
479         );
480 
481         unsafe {
482             synchapi::WaitForSingleObject(self.idle_event.0, winbase::INFINITE);
483         }
484 
485         Ok(())
486     }
487 }
488 
489 unsafe impl Send for Queue {}
490 unsafe impl Sync for Queue {}
491 
492 impl q::Queue<Backend> for Queue {
submit<'a, Ic, Iw, Is>( &mut self, command_buffers: Ic, _wait_semaphores: Iw, _signal_semaphores: Is, fence: Option<&mut resource::Fence>, ) where Ic: Iterator<Item = &'a command::CommandBuffer>, Iw: Iterator<Item = (&'a resource::Semaphore, PipelineStage)>, Is: Iterator<Item = &'a resource::Semaphore>,493     unsafe fn submit<'a, Ic, Iw, Is>(
494         &mut self,
495         command_buffers: Ic,
496         _wait_semaphores: Iw,
497         _signal_semaphores: Is,
498         fence: Option<&mut resource::Fence>,
499     ) where
500         Ic: Iterator<Item = &'a command::CommandBuffer>,
501         Iw: Iterator<Item = (&'a resource::Semaphore, PipelineStage)>,
502         Is: Iterator<Item = &'a resource::Semaphore>,
503     {
504         // Reset idle fence and event
505         // That's safe here due to exclusive access to the queue
506         self.idle_fence.signal(0);
507         synchapi::ResetEvent(self.idle_event.0);
508 
509         // TODO: semaphores
510         let lists = command_buffers
511             .map(|cmd_buf| cmd_buf.as_raw_list())
512             .collect::<SmallVec<[_; 4]>>();
513         self.raw
514             .ExecuteCommandLists(lists.len() as _, lists.as_ptr());
515 
516         if let Some(fence) = fence {
517             assert_eq!(winerror::S_OK, self.raw.Signal(fence.raw.as_mut_ptr(), 1));
518         }
519     }
520 
bind_sparse<'a, Iw, Is, Ibi, Ib, Iii, Io, Ii>( &mut self, _wait_semaphores: Iw, _signal_semaphores: Is, _buffer_memory_binds: Ib, _image_opaque_memory_binds: Io, image_memory_binds: Ii, device: &Device, fence: Option<&resource::Fence>, ) where Ibi: Iterator<Item = &'a memory::SparseBind<&'a resource::Memory>>, Ib: Iterator<Item = (&'a mut resource::Buffer, Ibi)>, Iii: Iterator<Item = &'a memory::SparseImageBind<&'a resource::Memory>>, Io: Iterator<Item = (&'a mut resource::Image, Ibi)>, Ii: Iterator<Item = (&'a mut resource::Image, Iii)>, Iw: Iterator<Item = &'a resource::Semaphore>, Is: Iterator<Item = &'a resource::Semaphore>,521     unsafe fn bind_sparse<'a, Iw, Is, Ibi, Ib, Iii, Io, Ii>(
522         &mut self,
523         _wait_semaphores: Iw,
524         _signal_semaphores: Is,
525         _buffer_memory_binds: Ib,
526         _image_opaque_memory_binds: Io,
527         image_memory_binds: Ii,
528         device: &Device,
529         fence: Option<&resource::Fence>,
530     ) where
531         Ibi: Iterator<Item = &'a memory::SparseBind<&'a resource::Memory>>,
532         Ib: Iterator<Item = (&'a mut resource::Buffer, Ibi)>,
533         Iii: Iterator<Item = &'a memory::SparseImageBind<&'a resource::Memory>>,
534         Io: Iterator<Item = (&'a mut resource::Image, Ibi)>,
535         Ii: Iterator<Item = (&'a mut resource::Image, Iii)>,
536         Iw: Iterator<Item = &'a resource::Semaphore>,
537         Is: Iterator<Item = &'a resource::Semaphore>,
538     {
539         // Reset idle fence and event
540         // That's safe here due to exclusive access to the queue
541         self.idle_fence.signal(0);
542         synchapi::ResetEvent(self.idle_event.0);
543 
544         // TODO: semaphores
545 
546         for (image, binds) in image_memory_binds {
547             let image = image.borrow_mut();
548 
549             let (bits, image_kind) = match image {
550                 Image::Unbound(unbound) => (unbound.format.surface_desc().bits, unbound.kind),
551                 Image::Bound(bound) => (bound.surface_type.desc().bits, bound.kind),
552             };
553             let block_size = match image_kind {
554                 image::Kind::D1(_, _) => unimplemented!(),
555                 image::Kind::D2(_, _, _, samples) => {
556                     image::get_tile_size(image::TileKind::Flat(samples), bits)
557                 }
558                 image::Kind::D3(_, _, _) => image::get_tile_size(image::TileKind::Volume, bits),
559             };
560 
561             // TODO avoid allocations
562             let mut resource_coords = Vec::new();
563             let mut region_sizes = Vec::new();
564             let mut range_flags = Vec::new();
565             let mut heap_range_start_offsets = Vec::new();
566             let mut range_tile_counts = Vec::new();
567 
568             let mut heap: *mut d3d12::ID3D12Heap = std::ptr::null_mut();
569             for bind in binds {
570                 resource_coords.push(d3d12::D3D12_TILED_RESOURCE_COORDINATE {
571                     X: bind.offset.x as u32,
572                     Y: bind.offset.y as u32,
573                     Z: bind.offset.z as u32,
574                     Subresource: image.calc_subresource(
575                         bind.subresource.level as _,
576                         bind.subresource.layer as _,
577                         0,
578                     ),
579                 });
580 
581                 // Increment one tile if the extent is not a multiple of the block size
582                 // Accessing these IS unsafe, but that is also true of Vulkan as the documentation
583                 // requires an extent multiple of the block size.
584                 let tile_extents = (
585                     (bind.extent.width / block_size.0 as u32)
586                         + ((bind.extent.width % block_size.0 as u32) != 0) as u32,
587                     (bind.extent.height / block_size.1 as u32)
588                         + ((bind.extent.height % block_size.1 as u32) != 0) as u32,
589                     (bind.extent.depth / block_size.2 as u32)
590                         + ((bind.extent.depth % block_size.2 as u32) != 0) as u32,
591                 );
592                 let number_tiles = tile_extents.0 * tile_extents.1 * tile_extents.2;
593                 region_sizes.push(d3d12::D3D12_TILE_REGION_SIZE {
594                     NumTiles: number_tiles,
595                     UseBox: 1,
596                     Width: tile_extents.0,
597                     Height: tile_extents.1 as u16,
598                     Depth: tile_extents.2 as u16,
599                 });
600 
601                 if let Some((memory, memory_offset)) = bind.memory {
602                     // TODO multiple heap support
603                     // would involve multiple update tile mapping calls
604                     if heap.is_null() {
605                         heap = memory.borrow().heap.as_mut_ptr();
606                     } else if cfg!(debug_assertions) {
607                         debug_assert_eq!(heap, memory.borrow().heap.as_mut_ptr());
608                     }
609                     range_flags.push(d3d12::D3D12_TILE_RANGE_FLAG_NONE);
610                     heap_range_start_offsets.push(memory_offset as u32);
611                 } else {
612                     range_flags.push(d3d12::D3D12_TILE_RANGE_FLAG_NULL);
613                     heap_range_start_offsets.push(0);
614                 }
615                 range_tile_counts.push(number_tiles);
616             }
617 
618             match image {
619                 Image::Bound(bound) => {
620                     self.raw.UpdateTileMappings(
621                         bound.resource.as_mut_ptr(),
622                         resource_coords.len() as u32,
623                         resource_coords.as_ptr(),
624                         region_sizes.as_ptr(),
625                         heap,
626                         range_flags.len() as u32,
627                         range_flags.as_ptr(),
628                         heap_range_start_offsets.as_ptr(),
629                         range_tile_counts.as_ptr(),
630                         d3d12::D3D12_TILE_MAPPING_FLAG_NONE,
631                     );
632                 }
633                 Image::Unbound(image_unbound) => {
634                     let mut resource = native::Resource::null();
635                     assert_eq!(
636                         winerror::S_OK,
637                         device.raw.clone().CreateReservedResource(
638                             &image_unbound.desc,
639                             d3d12::D3D12_RESOURCE_STATE_COMMON,
640                             std::ptr::null(),
641                             &d3d12::ID3D12Resource::uuidof(),
642                             resource.mut_void(),
643                         )
644                     );
645 
646                     self.raw.UpdateTileMappings(
647                         resource.as_mut_ptr(),
648                         resource_coords.len() as u32,
649                         resource_coords.as_ptr(),
650                         region_sizes.as_ptr(),
651                         heap,
652                         range_flags.len() as u32,
653                         range_flags.as_ptr(),
654                         heap_range_start_offsets.as_ptr(),
655                         range_tile_counts.as_ptr(),
656                         d3d12::D3D12_TILE_MAPPING_FLAG_NONE,
657                     );
658 
659                     device.bind_image_resource(resource, image, resource::Place::Swapchain {});
660                 }
661             }
662         }
663         // TODO sparse buffers and opaque images iterated here
664 
665         if let Some(fence) = fence {
666             assert_eq!(winerror::S_OK, self.raw.Signal(fence.raw.as_mut_ptr(), 1));
667         }
668     }
669 
present( &mut self, surface: &mut window::Surface, image: window::SwapchainImage, _wait_semaphore: Option<&mut resource::Semaphore>, ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError>670     unsafe fn present(
671         &mut self,
672         surface: &mut window::Surface,
673         image: window::SwapchainImage,
674         _wait_semaphore: Option<&mut resource::Semaphore>,
675     ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError> {
676         surface.present(image).map(|()| None)
677     }
678 
wait_idle(&mut self) -> Result<(), hal::device::OutOfMemory>679     fn wait_idle(&mut self) -> Result<(), hal::device::OutOfMemory> {
680         self.wait_idle_impl()
681     }
682 
timestamp_period(&self) -> f32683     fn timestamp_period(&self) -> f32 {
684         let mut frequency = 0u64;
685         unsafe {
686             self.raw.GetTimestampFrequency(&mut frequency);
687         }
688         (1_000_000_000.0 / frequency as f64) as f32
689     }
690 }
691 
692 #[derive(Debug, Clone, Copy)]
693 enum MemoryArchitecture {
694     NUMA,
695     UMA,
696     CacheCoherentUMA,
697 }
698 
699 #[derive(Debug, Clone, Copy)]
700 pub struct PrivateCapabilities {
701     heterogeneous_resource_heaps: bool,
702     memory_architecture: MemoryArchitecture,
703 }
704 
705 #[derive(Clone, Debug)]
706 struct CmdSignatures {
707     draw: native::CommandSignature,
708     draw_indexed: native::CommandSignature,
709     dispatch: native::CommandSignature,
710 }
711 
712 impl CmdSignatures {
destroy(&self)713     unsafe fn destroy(&self) {
714         self.draw.destroy();
715         self.draw_indexed.destroy();
716         self.dispatch.destroy();
717     }
718 }
719 
720 // Shared objects between command buffers, owned by the device.
721 #[derive(Debug)]
722 struct Shared {
723     pub signatures: CmdSignatures,
724     pub service_pipes: internal::ServicePipes,
725 }
726 
727 impl Shared {
destroy(&self)728     unsafe fn destroy(&self) {
729         self.signatures.destroy();
730         self.service_pipes.destroy();
731     }
732 }
733 
734 pub struct SamplerStorage {
735     map: Mutex<FastHashMap<image::SamplerDesc, descriptors_cpu::Handle>>,
736     //TODO: respect the D3D12_REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE limit
737     pool: Mutex<DescriptorCpuPool>,
738     heap: resource::DescriptorHeap,
739     origins: RwLock<resource::DescriptorOrigins>,
740 }
741 
742 impl SamplerStorage {
destroy(&mut self)743     unsafe fn destroy(&mut self) {
744         self.pool.lock().destroy();
745         self.heap.destroy();
746     }
747 }
748 
749 pub struct Device {
750     raw: native::Device,
751     private_caps: PrivateCapabilities,
752     features: Features,
753     format_properties: Arc<FormatProperties>,
754     heap_properties: &'static [HeapProperties],
755     // CPU only pools
756     rtv_pool: Mutex<DescriptorCpuPool>,
757     dsv_pool: Mutex<DescriptorCpuPool>,
758     srv_uav_pool: Mutex<DescriptorCpuPool>,
759     descriptor_updater: Mutex<descriptors_cpu::DescriptorUpdater>,
760     // CPU/GPU descriptor heaps
761     heap_srv_cbv_uav: (
762         resource::DescriptorHeap,
763         Mutex<RangeAllocator<DescriptorIndex>>,
764     ),
765     samplers: SamplerStorage,
766     events: Mutex<Vec<native::Event>>,
767     shared: Arc<Shared>,
768     // Present queue exposed by the `Present` queue family.
769     // Required for swapchain creation. Only a single queue supports presentation.
770     present_queue: native::CommandQueue,
771     // List of all queues created from this device, including present queue.
772     // Needed for `wait_idle`.
773     queues: Vec<Queue>,
774     // Indicates that there is currently an active device.
775     open: Arc<Mutex<bool>>,
776     library: Arc<native::D3D12Lib>,
777 }
778 
779 impl fmt::Debug for Device {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result780     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
781         fmt.write_str("Device")
782     }
783 }
784 
785 unsafe impl Send for Device {} //blocked by ComPtr
786 unsafe impl Sync for Device {} //blocked by ComPtr
787 
788 impl Device {
new( device: native::Device, physical_device: &PhysicalDevice, present_queue: native::CommandQueue, ) -> Self789     fn new(
790         device: native::Device,
791         physical_device: &PhysicalDevice,
792         present_queue: native::CommandQueue,
793     ) -> Self {
794         // Allocate descriptor heaps
795         let rtv_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Rtv);
796         let dsv_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Dsv);
797         let srv_uav_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::CbvSrvUav);
798 
799         // maximum number of CBV/SRV/UAV descriptors in heap for Tier 1
800         let view_capacity = 1_000_000;
801         let heap_srv_cbv_uav = Self::create_descriptor_heap_impl(
802             device,
803             native::DescriptorHeapType::CbvSrvUav,
804             true,
805             view_capacity,
806         );
807         let view_range_allocator = RangeAllocator::new(0..(view_capacity as u64));
808 
809         let sampler_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Sampler);
810         let heap_sampler = Self::create_descriptor_heap_impl(
811             device,
812             native::DescriptorHeapType::Sampler,
813             true,
814             2_048,
815         );
816 
817         let descriptor_updater = descriptors_cpu::DescriptorUpdater::new(
818             device,
819             physical_device.workarounds.avoid_cpu_descriptor_overwrites,
820         );
821 
822         let draw_signature = Self::create_command_signature(device, device::CommandSignature::Draw);
823         let draw_indexed_signature =
824             Self::create_command_signature(device, device::CommandSignature::DrawIndexed);
825         let dispatch_signature =
826             Self::create_command_signature(device, device::CommandSignature::Dispatch);
827 
828         let signatures = CmdSignatures {
829             draw: draw_signature,
830             draw_indexed: draw_indexed_signature,
831             dispatch: dispatch_signature,
832         };
833         let service_pipes =
834             internal::ServicePipes::new(device, Arc::clone(&physical_device.library));
835         let shared = Shared {
836             signatures,
837             service_pipes,
838         };
839 
840         Device {
841             raw: device,
842             library: Arc::clone(&physical_device.library),
843             private_caps: physical_device.private_caps,
844             features: Features::empty(),
845             format_properties: physical_device.format_properties.clone(),
846             heap_properties: physical_device.heap_properties,
847             rtv_pool: Mutex::new(rtv_pool),
848             dsv_pool: Mutex::new(dsv_pool),
849             srv_uav_pool: Mutex::new(srv_uav_pool),
850             descriptor_updater: Mutex::new(descriptor_updater),
851             heap_srv_cbv_uav: (heap_srv_cbv_uav, Mutex::new(view_range_allocator)),
852             samplers: SamplerStorage {
853                 map: Mutex::default(),
854                 pool: Mutex::new(sampler_pool),
855                 heap: heap_sampler,
856                 origins: RwLock::default(),
857             },
858             events: Mutex::new(Vec::new()),
859             shared: Arc::new(shared),
860             present_queue,
861             queues: Vec::new(),
862             open: Arc::clone(&physical_device.is_open),
863         }
864     }
865 
append_queue(&mut self, queue: Queue)866     fn append_queue(&mut self, queue: Queue) {
867         self.queues.push(queue);
868     }
869 
870     /// Get the native d3d12 device.
871     ///
872     /// Required for FFI with libraries like RenderDoc.
as_raw(&self) -> *mut d3d12::ID3D12Device873     pub unsafe fn as_raw(&self) -> *mut d3d12::ID3D12Device {
874         self.raw.as_mut_ptr()
875     }
876 }
877 
878 impl Drop for Device {
drop(&mut self)879     fn drop(&mut self) {
880         *self.open.lock() = false;
881 
882         unsafe {
883             for queue in &mut self.queues {
884                 let _ = q::Queue::wait_idle(queue);
885                 queue.destroy();
886             }
887 
888             self.shared.destroy();
889             self.heap_srv_cbv_uav.0.destroy();
890             self.samplers.destroy();
891             self.rtv_pool.lock().destroy();
892             self.dsv_pool.lock().destroy();
893             self.srv_uav_pool.lock().destroy();
894 
895             self.descriptor_updater.lock().destroy();
896 
897             // Debug tracking alive objects
898             let (debug_device, hr_debug) = self.raw.cast::<d3d12sdklayers::ID3D12DebugDevice>();
899             if winerror::SUCCEEDED(hr_debug) {
900                 debug_device.ReportLiveDeviceObjects(d3d12sdklayers::D3D12_RLDO_DETAIL);
901                 debug_device.destroy();
902             }
903 
904             self.raw.destroy();
905         }
906     }
907 }
908 
909 #[derive(Debug)]
910 pub struct Instance {
911     pub(crate) factory: native::Factory4,
912     library: Arc<native::D3D12Lib>,
913     lib_dxgi: native::DxgiLib,
914 }
915 
916 impl Drop for Instance {
drop(&mut self)917     fn drop(&mut self) {
918         unsafe {
919             self.factory.destroy();
920         }
921     }
922 }
923 
924 unsafe impl Send for Instance {}
925 unsafe impl Sync for Instance {}
926 
927 impl hal::Instance<Backend> for Instance {
create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend>928     fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
929         let lib_main = match native::D3D12Lib::new() {
930             Ok(lib) => lib,
931             Err(_) => return Err(hal::UnsupportedBackend),
932         };
933 
934         #[cfg(debug_assertions)]
935         {
936             // Enable debug layer
937             match lib_main.get_debug_interface() {
938                 Ok((debug_controller, hr)) if winerror::SUCCEEDED(hr) => {
939                     debug_controller.enable_layer();
940                     unsafe {
941                         debug_controller.Release();
942                     }
943                 }
944                 _ => {
945                     warn!("Unable to get D3D12 debug interface");
946                 }
947             }
948         }
949 
950         let lib_dxgi = native::DxgiLib::new().unwrap();
951 
952         // The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
953         // `CreateDXGIFactory2` if the debug interface is actually available. So
954         // we check for whether it exists first.
955         let factory_flags = match lib_dxgi.get_debug_interface1() {
956             Ok((queue, hr)) if winerror::SUCCEEDED(hr) => {
957                 unsafe { queue.destroy() };
958                 native::FactoryCreationFlags::DEBUG
959             }
960             _ => native::FactoryCreationFlags::empty(),
961         };
962 
963         // Create DXGI factory
964         let factory = match lib_dxgi.create_factory2(factory_flags) {
965             Ok((factory, hr)) if winerror::SUCCEEDED(hr) => factory,
966             Ok((_, hr)) => {
967                 info!("Failed on dxgi factory creation: {:?}", hr);
968                 return Err(hal::UnsupportedBackend);
969             }
970             Err(_) => return Err(hal::UnsupportedBackend),
971         };
972 
973         Ok(Instance {
974             factory,
975             library: Arc::new(lib_main),
976             lib_dxgi,
977         })
978     }
979 
enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>>980     fn enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>> {
981         use self::memory::Properties;
982 
983         // Try to use high performance order by default (returns None on Windows < 1803)
984         let (use_f6, factory6) = unsafe {
985             let (f6, hr) = self.factory.cast::<dxgi1_6::IDXGIFactory6>();
986             if winerror::SUCCEEDED(hr) {
987                 // It's okay to decrement the refcount here because we
988                 // have another reference to the factory already owned by `self`.
989                 f6.destroy();
990                 (true, f6)
991             } else {
992                 (false, native::WeakPtr::null())
993             }
994         };
995 
996         // Enumerate adapters
997         let mut cur_index = 0;
998         let mut adapters = Vec::new();
999         loop {
1000             let adapter = if use_f6 {
1001                 let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
1002                 let hr = unsafe {
1003                     factory6.EnumAdapterByGpuPreference(
1004                         cur_index,
1005                         2, // HIGH_PERFORMANCE
1006                         &dxgi1_2::IDXGIAdapter2::uuidof(),
1007                         adapter2.mut_void() as *mut *mut _,
1008                     )
1009                 };
1010 
1011                 if hr == winerror::DXGI_ERROR_NOT_FOUND {
1012                     break;
1013                 }
1014                 if !winerror::SUCCEEDED(hr) {
1015                     error!("Failed enumerating adapters: 0x{:x}", hr);
1016                     break;
1017                 }
1018 
1019                 adapter2
1020             } else {
1021                 let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
1022                 let hr1 = unsafe {
1023                     self.factory
1024                         .EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _)
1025                 };
1026 
1027                 if hr1 == winerror::DXGI_ERROR_NOT_FOUND {
1028                     break;
1029                 }
1030 
1031                 let (adapter2, hr2) = unsafe { adapter1.cast::<dxgi1_2::IDXGIAdapter2>() };
1032                 if !winerror::SUCCEEDED(hr2) {
1033                     error!("Failed casting to Adapter2: 0x{:x}", hr2);
1034                     break;
1035                 }
1036 
1037                 unsafe {
1038                     adapter1.destroy();
1039                 }
1040                 adapter2
1041             };
1042 
1043             cur_index += 1;
1044 
1045             // Check for D3D12 support
1046             // Create temporary device to get physical device information
1047             let device = match self
1048                 .library
1049                 .create_device(adapter, native::FeatureLevel::L11_0)
1050             {
1051                 Ok((device, hr)) if winerror::SUCCEEDED(hr) => device,
1052                 _ => continue,
1053             };
1054 
1055             // We have found a possible adapter
1056             // acquire the device information
1057             let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
1058             unsafe {
1059                 adapter.GetDesc2(&mut desc);
1060             }
1061 
1062             let device_name = {
1063                 let len = desc.Description.iter().take_while(|&&c| c != 0).count();
1064                 let name = <OsString as OsStringExt>::from_wide(&desc.Description[..len]);
1065                 name.to_string_lossy().into_owned()
1066             };
1067 
1068             let mut features_architecture: d3d12::D3D12_FEATURE_DATA_ARCHITECTURE =
1069                 unsafe { mem::zeroed() };
1070             assert_eq!(winerror::S_OK, unsafe {
1071                 device.CheckFeatureSupport(
1072                     d3d12::D3D12_FEATURE_ARCHITECTURE,
1073                     &mut features_architecture as *mut _ as *mut _,
1074                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_ARCHITECTURE>() as _,
1075                 )
1076             });
1077 
1078             let mut workarounds = Workarounds::default();
1079 
1080             let info = adapter::AdapterInfo {
1081                 name: device_name,
1082                 vendor: desc.VendorId as usize,
1083                 device: desc.DeviceId as usize,
1084                 device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
1085                     workarounds.avoid_cpu_descriptor_overwrites = true;
1086                     adapter::DeviceType::VirtualGpu
1087                 } else if features_architecture.CacheCoherentUMA == TRUE {
1088                     adapter::DeviceType::IntegratedGpu
1089                 } else {
1090                     adapter::DeviceType::DiscreteGpu
1091                 },
1092             };
1093 
1094             let mut features: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() };
1095             assert_eq!(winerror::S_OK, unsafe {
1096                 device.CheckFeatureSupport(
1097                     d3d12::D3D12_FEATURE_D3D12_OPTIONS,
1098                     &mut features as *mut _ as *mut _,
1099                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS>() as _,
1100                 )
1101             });
1102 
1103             let depth_bounds_test_supported = {
1104                 let mut features2: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2 =
1105                     unsafe { mem::zeroed() };
1106                 let hr = unsafe {
1107                     device.CheckFeatureSupport(
1108                         d3d12::D3D12_FEATURE_D3D12_OPTIONS2,
1109                         &mut features2 as *mut _ as *mut _,
1110                         mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2>() as _,
1111                     )
1112                 };
1113                 if hr == winerror::S_OK {
1114                     features2.DepthBoundsTestSupported != 0
1115                 } else {
1116                     false
1117                 }
1118             };
1119 
1120             let heterogeneous_resource_heaps =
1121                 features.ResourceHeapTier != d3d12::D3D12_RESOURCE_HEAP_TIER_1;
1122 
1123             let uma = features_architecture.UMA == TRUE;
1124             let cc_uma = features_architecture.CacheCoherentUMA == TRUE;
1125 
1126             let (memory_architecture, heap_properties) = match (uma, cc_uma) {
1127                 (true, true) => (MemoryArchitecture::CacheCoherentUMA, &HEAPS_CCUMA),
1128                 (true, false) => (MemoryArchitecture::UMA, &HEAPS_UMA),
1129                 (false, _) => (MemoryArchitecture::NUMA, &HEAPS_NUMA),
1130             };
1131 
1132             // https://msdn.microsoft.com/en-us/library/windows/desktop/dn788678(v=vs.85).aspx
1133             let base_memory_types: [adapter::MemoryType; NUM_HEAP_PROPERTIES] =
1134                 match memory_architecture {
1135                     MemoryArchitecture::NUMA => [
1136                         // DEFAULT
1137                         adapter::MemoryType {
1138                             properties: Properties::DEVICE_LOCAL,
1139                             heap_index: 0,
1140                         },
1141                         // UPLOAD
1142                         adapter::MemoryType {
1143                             properties: Properties::CPU_VISIBLE | Properties::COHERENT,
1144                             heap_index: 1,
1145                         },
1146                         // READBACK
1147                         adapter::MemoryType {
1148                             properties: Properties::CPU_VISIBLE
1149                                 | Properties::COHERENT
1150                                 | Properties::CPU_CACHED,
1151                             heap_index: 1,
1152                         },
1153                     ],
1154                     MemoryArchitecture::UMA => [
1155                         // DEFAULT
1156                         adapter::MemoryType {
1157                             properties: Properties::DEVICE_LOCAL,
1158                             heap_index: 0,
1159                         },
1160                         // UPLOAD
1161                         adapter::MemoryType {
1162                             properties: Properties::DEVICE_LOCAL
1163                                 | Properties::CPU_VISIBLE
1164                                 | Properties::COHERENT,
1165                             heap_index: 0,
1166                         },
1167                         // READBACK
1168                         adapter::MemoryType {
1169                             properties: Properties::DEVICE_LOCAL
1170                                 | Properties::CPU_VISIBLE
1171                                 | Properties::COHERENT
1172                                 | Properties::CPU_CACHED,
1173                             heap_index: 0,
1174                         },
1175                     ],
1176                     MemoryArchitecture::CacheCoherentUMA => [
1177                         // DEFAULT
1178                         adapter::MemoryType {
1179                             properties: Properties::DEVICE_LOCAL,
1180                             heap_index: 0,
1181                         },
1182                         // UPLOAD
1183                         adapter::MemoryType {
1184                             properties: Properties::DEVICE_LOCAL
1185                                 | Properties::CPU_VISIBLE
1186                                 | Properties::COHERENT
1187                                 | Properties::CPU_CACHED,
1188                             heap_index: 0,
1189                         },
1190                         // READBACK
1191                         adapter::MemoryType {
1192                             properties: Properties::DEVICE_LOCAL
1193                                 | Properties::CPU_VISIBLE
1194                                 | Properties::COHERENT
1195                                 | Properties::CPU_CACHED,
1196                             heap_index: 0,
1197                         },
1198                     ],
1199                 };
1200 
1201             let memory_types = if heterogeneous_resource_heaps {
1202                 base_memory_types.to_vec()
1203             } else {
1204                 // We multiplicate the base memory types depending on the resource usage:
1205                 //     0.. 3: Reserved for futures use
1206                 //     4.. 6: Buffers
1207                 //     7.. 9: Images
1208                 //    10..12: Targets
1209                 //
1210                 // The supported memory types for a resource can be requested by asking for
1211                 // the memory requirements. Memory type indices are encoded as bitflags.
1212                 // `device::MEM_TYPE_MASK` (0b111) defines the bitmask for one base memory type group.
1213                 // The corresponding shift masks (`device::MEM_TYPE_BUFFER_SHIFT`,
1214                 // `device::MEM_TYPE_IMAGE_SHIFT`, `device::MEM_TYPE_TARGET_SHIFT`)
1215                 // denote the usage group.
1216                 let mut types = Vec::new();
1217                 for i in 0..MemoryGroup::NumGroups as _ {
1218                     types.extend(base_memory_types.iter().map(|mem_type| {
1219                         let mut ty = mem_type.clone();
1220 
1221                         // Images and Targets are not host visible as we can't create
1222                         // a corresponding buffer for mapping.
1223                         if i == MemoryGroup::ImageOnly as _ || i == MemoryGroup::TargetOnly as _ {
1224                             ty.properties.remove(Properties::CPU_VISIBLE);
1225                             // Coherent and cached can only be on memory types that are cpu visible
1226                             ty.properties.remove(Properties::COHERENT);
1227                             ty.properties.remove(Properties::CPU_CACHED);
1228                         }
1229                         ty
1230                     }));
1231                 }
1232                 types
1233             };
1234 
1235             let memory_heaps = {
1236                 // Get the IDXGIAdapter3 from the created device to query video memory information.
1237                 let adapter_id = unsafe { device.GetAdapterLuid() };
1238                 let adapter = {
1239                     let mut adapter = native::WeakPtr::<dxgi1_4::IDXGIAdapter3>::null();
1240                     unsafe {
1241                         assert_eq!(
1242                             winerror::S_OK,
1243                             self.factory.EnumAdapterByLuid(
1244                                 adapter_id,
1245                                 &dxgi1_4::IDXGIAdapter3::uuidof(),
1246                                 adapter.mut_void(),
1247                             )
1248                         );
1249                     }
1250                     adapter
1251                 };
1252 
1253                 let query_memory = |segment: dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP| unsafe {
1254                     let mut mem_info: dxgi1_4::DXGI_QUERY_VIDEO_MEMORY_INFO = mem::zeroed();
1255                     assert_eq!(
1256                         winerror::S_OK,
1257                         adapter.QueryVideoMemoryInfo(0, segment, &mut mem_info)
1258                     );
1259                     mem_info.Budget
1260                 };
1261 
1262                 let mut heaps = vec![adapter::MemoryHeap {
1263                     size: query_memory(dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP_LOCAL),
1264                     flags: memory::HeapFlags::DEVICE_LOCAL,
1265                 }];
1266                 if let MemoryArchitecture::NUMA = memory_architecture {
1267                     heaps.push(adapter::MemoryHeap {
1268                         size: query_memory(dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL),
1269                         flags: memory::HeapFlags::empty(),
1270                     });
1271                 }
1272                 heaps
1273             };
1274             //TODO: find a way to get a tighter bound?
1275             let sample_count_mask = 0x3F;
1276 
1277             // Theoretically vram limited, but in practice 2^20 is the limit
1278             let tier3_practical_descriptor_limit = 1 << 20;
1279 
1280             let full_heap_count = match features.ResourceBindingTier {
1281                 d3d12::D3D12_RESOURCE_BINDING_TIER_1 => {
1282                     d3d12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1
1283                 }
1284                 d3d12::D3D12_RESOURCE_BINDING_TIER_2 => {
1285                     d3d12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2
1286                 }
1287                 d3d12::D3D12_RESOURCE_BINDING_TIER_3 => tier3_practical_descriptor_limit,
1288                 _ => unreachable!(),
1289             } as _;
1290 
1291             let uav_limit = match features.ResourceBindingTier {
1292                 d3d12::D3D12_RESOURCE_BINDING_TIER_1 => 8, // conservative, is 64 on feature level 11.1
1293                 d3d12::D3D12_RESOURCE_BINDING_TIER_2 => 64,
1294                 d3d12::D3D12_RESOURCE_BINDING_TIER_3 => tier3_practical_descriptor_limit,
1295                 _ => unreachable!(),
1296             } as _;
1297 
1298             let mut tiled_resource_features = Features::empty();
1299             if features.TiledResourcesTier >= d3d12::D3D12_TILED_RESOURCES_TIER_1 {
1300                 tiled_resource_features |= Features::SPARSE_BINDING;
1301                 tiled_resource_features |= Features::SPARSE_RESIDENCY_IMAGE_2D;
1302                 tiled_resource_features |= Features::SPARSE_RESIDENCY_BUFFER;
1303                 tiled_resource_features |= Features::SPARSE_RESIDENCY_ALIASED;
1304                 tiled_resource_features |= Features::SPARSE_RESIDENCY_2_SAMPLES;
1305                 tiled_resource_features |= Features::SPARSE_RESIDENCY_4_SAMPLES;
1306                 tiled_resource_features |= Features::SPARSE_RESIDENCY_8_SAMPLES;
1307                 tiled_resource_features |= Features::SPARSE_RESIDENCY_16_SAMPLES;
1308             }
1309             if features.TiledResourcesTier >= d3d12::D3D12_TILED_RESOURCES_TIER_3 {
1310                 tiled_resource_features |= Features::SPARSE_RESIDENCY_IMAGE_3D;
1311             }
1312 
1313             let conservative_faster_features = if features.ConservativeRasterizationTier
1314                 == d3d12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED
1315             {
1316                 Features::empty()
1317             } else {
1318                 Features::CONSERVATIVE_RASTERIZATION
1319             };
1320 
1321             let physical_device = PhysicalDevice {
1322                 library: Arc::clone(&self.library),
1323                 adapter,
1324                 features:
1325                     // TODO: add more features, based on
1326                     // https://msdn.microsoft.com/de-de/library/windows/desktop/mt186615(v=vs.85).aspx
1327                     Features::ROBUST_BUFFER_ACCESS |
1328                     Features::IMAGE_CUBE_ARRAY |
1329                     Features::GEOMETRY_SHADER |
1330                     Features::TESSELLATION_SHADER |
1331                     Features::NON_FILL_POLYGON_MODE |
1332                     if depth_bounds_test_supported { Features::DEPTH_BOUNDS } else { Features::empty() } |
1333                     //logic_op: false, // Optional on feature level 11_0
1334                     Features::MULTI_DRAW_INDIRECT |
1335                     Features::FORMAT_BC |
1336                     Features::INSTANCE_RATE |
1337                     Features::DEPTH_CLAMP |
1338                     Features::SAMPLER_MIP_LOD_BIAS |
1339                     Features::SAMPLER_BORDER_COLOR |
1340                     Features::MUTABLE_COMPARISON_SAMPLER |
1341                     Features::SAMPLER_ANISOTROPY |
1342                     Features::TEXTURE_DESCRIPTOR_ARRAY |
1343                     Features::BUFFER_DESCRIPTOR_ARRAY |
1344                     Features::SAMPLER_MIRROR_CLAMP_EDGE |
1345                     Features::NDC_Y_UP |
1346                     Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING |
1347                     Features::SHADER_STORAGE_IMAGE_ARRAY_DYNAMIC_INDEXING |
1348                     Features::SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING |
1349                     Features::SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING |
1350                     Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING |
1351                     Features::STORAGE_TEXTURE_DESCRIPTOR_INDEXING |
1352                     Features::STORAGE_BUFFER_DESCRIPTOR_INDEXING |
1353                     Features::UNIFORM_BUFFER_DESCRIPTOR_INDEXING |
1354                     Features::UNSIZED_DESCRIPTOR_ARRAY |
1355                     Features::DRAW_INDIRECT_COUNT |
1356                     tiled_resource_features |
1357                     conservative_faster_features,
1358                 properties: PhysicalDeviceProperties {
1359                     limits: Limits {
1360                         //TODO: verify all of these not linked to constants
1361                         max_memory_allocation_count: !0,
1362                         max_bound_descriptor_sets: MAX_DESCRIPTOR_SETS as u16,
1363                         descriptor_limits: hal::DescriptorLimits {
1364                             max_per_stage_descriptor_samplers: match features.ResourceBindingTier {
1365                                 d3d12::D3D12_RESOURCE_BINDING_TIER_1 => 16,
1366                                 d3d12::D3D12_RESOURCE_BINDING_TIER_2 | d3d12::D3D12_RESOURCE_BINDING_TIER_3 | _ => d3d12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
1367                             } as _,
1368                             max_per_stage_descriptor_uniform_buffers: match features.ResourceBindingTier
1369                             {
1370                                 d3d12::D3D12_RESOURCE_BINDING_TIER_1 | d3d12::D3D12_RESOURCE_BINDING_TIER_2 => {
1371                                     d3d12::D3D12_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT
1372                                 }
1373                                 d3d12::D3D12_RESOURCE_BINDING_TIER_3 | _ => full_heap_count as _,
1374                             } as _,
1375                             max_per_stage_descriptor_storage_buffers: uav_limit,
1376                             max_per_stage_descriptor_sampled_images: match features.ResourceBindingTier
1377                             {
1378                                 d3d12::D3D12_RESOURCE_BINDING_TIER_1 => 128,
1379                                 d3d12::D3D12_RESOURCE_BINDING_TIER_2
1380                                 | d3d12::D3D12_RESOURCE_BINDING_TIER_3
1381                                 | _ => full_heap_count,
1382                             } as _,
1383                             max_per_stage_descriptor_storage_images: uav_limit,
1384                             max_per_stage_resources: !0,
1385                             max_descriptor_set_samplers: d3d12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE as _,
1386                             max_descriptor_set_uniform_buffers: full_heap_count,
1387                             max_descriptor_set_uniform_buffers_dynamic: 8,
1388                             max_descriptor_set_storage_buffers: uav_limit,
1389                             max_descriptor_set_storage_buffers_dynamic: 4,
1390                             max_descriptor_set_sampled_images: full_heap_count,
1391                             max_descriptor_set_storage_images: uav_limit,
1392                             ..hal::DescriptorLimits::default() // TODO
1393                         },
1394                         max_uniform_buffer_range: (d3d12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16)
1395                             as _,
1396                         max_storage_buffer_range: !0,
1397                         // Is actually 256, but need space for the descriptors in there, so leave at 128 to discourage explosions
1398                         max_push_constants_size: 128,
1399                         max_image_1d_size: d3d12::D3D12_REQ_TEXTURE1D_U_DIMENSION as _,
1400                         max_image_2d_size: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION as _,
1401                         max_image_3d_size: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION as _,
1402                         max_image_cube_size: d3d12::D3D12_REQ_TEXTURECUBE_DIMENSION as _,
1403                         max_image_array_layers: d3d12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
1404                         max_texel_elements: 0,
1405                         max_patch_size: 0,
1406                         max_viewports: d3d12::D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE as _,
1407                         max_viewport_dimensions: [d3d12::D3D12_VIEWPORT_BOUNDS_MAX as _; 2],
1408                         max_framebuffer_extent: hal::image::Extent {
1409                             width: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
1410                             height: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
1411                             depth: 1,
1412                         },
1413                         max_framebuffer_layers: 1,
1414                         max_compute_work_group_count: [
1415                             d3d12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
1416                             d3d12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
1417                             d3d12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
1418                         ],
1419                         max_compute_work_group_invocations: d3d12::D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP as _,
1420                         max_compute_work_group_size: [
1421                             d3d12::D3D12_CS_THREAD_GROUP_MAX_X,
1422                             d3d12::D3D12_CS_THREAD_GROUP_MAX_Y,
1423                             d3d12::D3D12_CS_THREAD_GROUP_MAX_Z,
1424                         ],
1425                         max_vertex_input_attributes: d3d12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT as _,
1426                         max_vertex_input_bindings: d3d12::D3D12_VS_INPUT_REGISTER_COUNT as _,
1427                         max_vertex_input_attribute_offset: 255, // TODO
1428                         max_vertex_input_binding_stride: d3d12::D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES as _,
1429                         max_vertex_output_components: d3d12::D3D12_VS_OUTPUT_REGISTER_COUNT as _,
1430                         max_fragment_input_components: d3d12::D3D12_PS_INPUT_REGISTER_COUNT as _,
1431                         max_fragment_output_attachments: d3d12::D3D12_PS_OUTPUT_REGISTER_COUNT as _,
1432                         max_fragment_dual_source_attachments: 1,
1433                         max_fragment_combined_output_resources: (d3d12::D3D12_PS_OUTPUT_REGISTER_COUNT + d3d12::D3D12_PS_CS_UAV_REGISTER_COUNT) as _,
1434                         min_texel_buffer_offset_alignment: 1, // TODO
1435                         min_uniform_buffer_offset_alignment: d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as _,
1436                         min_storage_buffer_offset_alignment: 4, // TODO
1437                         framebuffer_color_sample_counts: sample_count_mask,
1438                         framebuffer_depth_sample_counts: sample_count_mask,
1439                         framebuffer_stencil_sample_counts: sample_count_mask,
1440                         max_color_attachments: d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as _,
1441                         buffer_image_granularity: 1,
1442                         non_coherent_atom_size: 1, //TODO: confirm
1443                         max_sampler_anisotropy: 16.,
1444                         optimal_buffer_copy_offset_alignment: d3d12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as _,
1445                         optimal_buffer_copy_pitch_alignment: d3d12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as _,
1446                         min_vertex_input_binding_stride_alignment: 1,
1447                         ..Limits::default() //TODO
1448                     },
1449                     dynamic_pipeline_states: hal::DynamicStates::VIEWPORT
1450                         | hal::DynamicStates::SCISSOR
1451                         | hal::DynamicStates::BLEND_CONSTANTS
1452                         | hal::DynamicStates::STENCIL_REFERENCE,
1453                     downlevel: hal::DownlevelProperties::all_enabled(),
1454                     ..PhysicalDeviceProperties::default()
1455                 },
1456                 format_properties: Arc::new(FormatProperties::new(device)),
1457                 private_caps: PrivateCapabilities {
1458                     heterogeneous_resource_heaps,
1459                     memory_architecture,
1460                 },
1461                 workarounds,
1462                 heap_properties,
1463                 memory_properties: adapter::MemoryProperties {
1464                     memory_types,
1465                     memory_heaps,
1466                 },
1467                 is_open: Arc::new(Mutex::new(false)),
1468             };
1469 
1470             let queue_families = QUEUE_FAMILIES.to_vec();
1471 
1472             adapters.push(adapter::Adapter {
1473                 info,
1474                 physical_device,
1475                 queue_families,
1476             });
1477         }
1478         adapters
1479     }
1480 
create_surface( &self, has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result<window::Surface, hal::window::InitError>1481     unsafe fn create_surface(
1482         &self,
1483         has_handle: &impl raw_window_handle::HasRawWindowHandle,
1484     ) -> Result<window::Surface, hal::window::InitError> {
1485         match has_handle.raw_window_handle() {
1486             raw_window_handle::RawWindowHandle::Windows(handle) => {
1487                 Ok(self.create_surface_from_hwnd(handle.hwnd))
1488             }
1489             _ => Err(hal::window::InitError::UnsupportedWindowHandle),
1490         }
1491     }
1492 
destroy_surface(&self, _surface: window::Surface)1493     unsafe fn destroy_surface(&self, _surface: window::Surface) {
1494         // TODO: Implement Surface cleanup
1495     }
1496 }
1497 
1498 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1499 pub enum Backend {}
1500 impl hal::Backend for Backend {
1501     type Instance = Instance;
1502     type PhysicalDevice = PhysicalDevice;
1503     type Device = Device;
1504     type Surface = window::Surface;
1505 
1506     type QueueFamily = QueueFamily;
1507     type Queue = Queue;
1508     type CommandBuffer = command::CommandBuffer;
1509 
1510     type Memory = resource::Memory;
1511     type CommandPool = pool::CommandPool;
1512 
1513     type ShaderModule = resource::ShaderModule;
1514     type RenderPass = resource::RenderPass;
1515     type Framebuffer = resource::Framebuffer;
1516 
1517     type Buffer = resource::Buffer;
1518     type BufferView = resource::BufferView;
1519     type Image = resource::Image;
1520     type ImageView = resource::ImageView;
1521     type Sampler = resource::Sampler;
1522 
1523     type ComputePipeline = resource::ComputePipeline;
1524     type GraphicsPipeline = resource::GraphicsPipeline;
1525     type PipelineLayout = resource::PipelineLayout;
1526     type PipelineCache = ();
1527     type DescriptorSetLayout = resource::DescriptorSetLayout;
1528     type DescriptorPool = resource::DescriptorPool;
1529     type DescriptorSet = resource::DescriptorSet;
1530 
1531     type Fence = resource::Fence;
1532     type Semaphore = resource::Semaphore;
1533     type Event = ();
1534     type QueryPool = resource::QueryPool;
1535 }
1536 
validate_line_width(width: f32)1537 fn validate_line_width(width: f32) {
1538     // Note from the Vulkan spec:
1539     // > If the wide lines feature is not enabled, lineWidth must be 1.0
1540     // Simply assert and no-op because DX12 never exposes `Features::LINE_WIDTH`
1541     assert_eq!(width, 1.0);
1542 }
1543 
1544 #[derive(Clone, Copy, Debug, Default)]
1545 struct FormatInfo {
1546     properties: f::Properties,
1547     sample_count_mask: u8,
1548 }
1549 
1550 #[derive(Debug)]
1551 pub struct FormatProperties {
1552     info: Box<[Mutex<Option<FormatInfo>>]>,
1553     device: native::Device,
1554 }
1555 
1556 impl Drop for FormatProperties {
drop(&mut self)1557     fn drop(&mut self) {
1558         unsafe {
1559             self.device.destroy();
1560         }
1561     }
1562 }
1563 
1564 impl FormatProperties {
new(device: native::Device) -> Self1565     fn new(device: native::Device) -> Self {
1566         let mut buf = Vec::with_capacity(f::NUM_FORMATS);
1567         buf.push(Mutex::new(Some(FormatInfo::default())));
1568         for _ in 1..f::NUM_FORMATS {
1569             buf.push(Mutex::new(None))
1570         }
1571         FormatProperties {
1572             info: buf.into_boxed_slice(),
1573             device,
1574         }
1575     }
1576 
resolve(&self, idx: usize) -> FormatInfo1577     fn resolve(&self, idx: usize) -> FormatInfo {
1578         let mut guard = self.info[idx].lock();
1579         if let Some(info) = *guard {
1580             return info;
1581         }
1582         let format: f::Format = unsafe { mem::transmute(idx as u32) };
1583         let is_compressed = format.surface_desc().is_compressed();
1584         let dxgi_format = match conv::map_format(format) {
1585             Some(format) => format,
1586             None => {
1587                 let info = FormatInfo::default();
1588                 *guard = Some(info);
1589                 return info;
1590             }
1591         };
1592 
1593         let properties = {
1594             let mut props = f::Properties::default();
1595             let mut data = d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
1596                 Format: dxgi_format,
1597                 Support1: unsafe { mem::zeroed() },
1598                 Support2: unsafe { mem::zeroed() },
1599             };
1600             assert_eq!(winerror::S_OK, unsafe {
1601                 self.device.CheckFeatureSupport(
1602                     d3d12::D3D12_FEATURE_FORMAT_SUPPORT,
1603                     &mut data as *mut _ as *mut _,
1604                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
1605                 )
1606             });
1607             let can_buffer = 0 != data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_BUFFER;
1608             let can_image = 0
1609                 != data.Support1
1610                     & (d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE1D
1611                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE2D
1612                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE3D
1613                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE);
1614             let can_linear = can_image && !is_compressed;
1615             if can_image {
1616                 props.optimal_tiling |= f::ImageFeature::TRANSFER_SRC
1617                     | f::ImageFeature::TRANSFER_DST
1618                     | f::ImageFeature::SAMPLED;
1619             }
1620             if can_linear {
1621                 props.linear_tiling |= f::ImageFeature::TRANSFER_SRC
1622                     | f::ImageFeature::TRANSFER_DST
1623                     | f::ImageFeature::SAMPLED
1624                     | f::ImageFeature::BLIT_SRC;
1625             }
1626             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER != 0 {
1627                 props.buffer_features |= f::BufferFeature::VERTEX;
1628             }
1629             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0 {
1630                 props.optimal_tiling |= f::ImageFeature::SAMPLED_LINEAR;
1631             }
1632             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0 {
1633                 props.optimal_tiling |=
1634                     f::ImageFeature::COLOR_ATTACHMENT | f::ImageFeature::BLIT_DST;
1635             }
1636             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0 {
1637                 props.optimal_tiling |= f::ImageFeature::COLOR_ATTACHMENT_BLEND;
1638             }
1639             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL != 0 {
1640                 props.optimal_tiling |= f::ImageFeature::DEPTH_STENCIL_ATTACHMENT;
1641             }
1642             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD != 0 {
1643                 //TODO: check d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD ?
1644                 if can_buffer {
1645                     props.buffer_features |= f::BufferFeature::UNIFORM_TEXEL;
1646                 }
1647             }
1648             if data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD != 0 {
1649                 //TODO: other atomic flags?
1650                 if can_buffer {
1651                     props.buffer_features |= f::BufferFeature::STORAGE_TEXEL_ATOMIC;
1652                 }
1653                 if can_image {
1654                     props.optimal_tiling |= f::ImageFeature::STORAGE_ATOMIC;
1655                 }
1656             }
1657             if data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0 {
1658                 if can_buffer {
1659                     props.buffer_features |= f::BufferFeature::STORAGE_TEXEL;
1660                 }
1661                 if can_image {
1662                     // Since read-only storage is exposed as SRV, we can guarantee read-only storage
1663                     // without checking D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD first.
1664                     props.optimal_tiling |= f::ImageFeature::STORAGE;
1665 
1666                     if data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD != 0 {
1667                         props.optimal_tiling |= f::ImageFeature::STORAGE_READ_WRITE;
1668                     }
1669                 }
1670             }
1671             //TODO: blits, linear tiling
1672             props
1673         };
1674 
1675         let sample_count_mask = if is_compressed {
1676             // just an optimization to avoid the queries
1677             1
1678         } else {
1679             let mut mask = 0;
1680             for i in 0..6 {
1681                 let mut data = d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
1682                     Format: dxgi_format,
1683                     SampleCount: 1 << i,
1684                     Flags: 0,
1685                     NumQualityLevels: 0,
1686                 };
1687                 assert_eq!(winerror::S_OK, unsafe {
1688                     self.device.CheckFeatureSupport(
1689                         d3d12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
1690                         &mut data as *mut _ as *mut _,
1691                         mem::size_of::<d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS>() as _,
1692                     )
1693                 });
1694                 if data.NumQualityLevels != 0 {
1695                     mask |= 1 << i;
1696                 }
1697             }
1698             mask
1699         };
1700 
1701         let info = FormatInfo {
1702             properties,
1703             sample_count_mask,
1704         };
1705         *guard = Some(info);
1706         info
1707     }
1708 }
1709