1 #[macro_use]
2 extern crate bitflags;
3 #[macro_use]
4 extern crate log;
5 
6 mod command;
7 mod conv;
8 mod descriptors_cpu;
9 mod device;
10 mod internal;
11 mod pool;
12 mod resource;
13 mod root_constants;
14 mod window;
15 
16 use hal::{
17     adapter,
18     format as f,
19     image,
20     memory,
21     pso::PipelineStage,
22     queue as q,
23     Features,
24     Hints,
25     Limits,
26 };
27 
28 use winapi::{
29     shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, minwindef::TRUE, winerror},
30     um::{d3d12, d3d12sdklayers, handleapi, synchapi, winbase},
31     Interface,
32 };
33 
34 use std::{
35     borrow::Borrow,
36     ffi::OsString,
37     fmt,
38     mem,
39     os::windows::ffi::OsStringExt,
40     sync::{Arc, Mutex},
41 };
42 
43 use self::descriptors_cpu::DescriptorCpuPool;
44 
45 #[derive(Debug)]
46 pub(crate) struct HeapProperties {
47     pub page_property: d3d12::D3D12_CPU_PAGE_PROPERTY,
48     pub memory_pool: d3d12::D3D12_MEMORY_POOL,
49 }
50 
51 // https://msdn.microsoft.com/de-de/library/windows/desktop/dn770377(v=vs.85).aspx
52 // Only 16 input slots allowed.
53 const MAX_VERTEX_BUFFERS: usize = 16;
54 
55 const NUM_HEAP_PROPERTIES: usize = 3;
56 
57 // Memory types are grouped according to the supported resources.
58 // Grouping is done to circumvent the limitations of heap tier 1 devices.
59 // Devices with Tier 1 will expose `BuffersOnl`, `ImageOnly` and `TargetOnly`.
60 // Devices with Tier 2 or higher will only expose `Universal`.
61 enum MemoryGroup {
62     Universal = 0,
63     BufferOnly,
64     ImageOnly,
65     TargetOnly,
66 
67     NumGroups,
68 }
69 
70 // https://msdn.microsoft.com/de-de/library/windows/desktop/dn788678(v=vs.85).aspx
71 static HEAPS_NUMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
72     // DEFAULT
73     HeapProperties {
74         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
75         memory_pool: d3d12::D3D12_MEMORY_POOL_L1,
76     },
77     // UPLOAD
78     HeapProperties {
79         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
80         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
81     },
82     // READBACK
83     HeapProperties {
84         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
85         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
86     },
87 ];
88 
89 static HEAPS_UMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
90     // DEFAULT
91     HeapProperties {
92         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
93         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
94     },
95     // UPLOAD
96     HeapProperties {
97         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
98         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
99     },
100     // READBACK
101     HeapProperties {
102         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
103         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
104     },
105 ];
106 
107 static HEAPS_CCUMA: [HeapProperties; NUM_HEAP_PROPERTIES] = [
108     // DEFAULT
109     HeapProperties {
110         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
111         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
112     },
113     // UPLOAD
114     HeapProperties {
115         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
116         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
117     },
118     //READBACK
119     HeapProperties {
120         page_property: d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
121         memory_pool: d3d12::D3D12_MEMORY_POOL_L0,
122     },
123 ];
124 
125 #[derive(Debug, Copy, Clone)]
126 pub enum QueueFamily {
127     // Specially marked present queue.
128     // It's basically a normal 3D queue but D3D12 swapchain creation requires an
129     // associated queue, which we don't know on `create_swapchain`.
130     Present,
131     Normal(q::QueueType),
132 }
133 
134 const MAX_QUEUES: usize = 16; // infinite, to be fair
135 
136 impl q::QueueFamily for QueueFamily {
queue_type(&self) -> q::QueueType137     fn queue_type(&self) -> q::QueueType {
138         match *self {
139             QueueFamily::Present => q::QueueType::General,
140             QueueFamily::Normal(ty) => ty,
141         }
142     }
max_queues(&self) -> usize143     fn max_queues(&self) -> usize {
144         match *self {
145             QueueFamily::Present => 1,
146             QueueFamily::Normal(_) => MAX_QUEUES,
147         }
148     }
id(&self) -> q::QueueFamilyId149     fn id(&self) -> q::QueueFamilyId {
150         // This must match the order exposed by `QUEUE_FAMILIES`
151         q::QueueFamilyId(match *self {
152             QueueFamily::Present => 0,
153             QueueFamily::Normal(q::QueueType::General) => 1,
154             QueueFamily::Normal(q::QueueType::Compute) => 2,
155             QueueFamily::Normal(q::QueueType::Transfer) => 3,
156             _ => unreachable!(),
157         })
158     }
159 }
160 
161 impl QueueFamily {
native_type(&self) -> native::CmdListType162     fn native_type(&self) -> native::CmdListType {
163         use hal::queue::QueueFamily as _;
164         use native::CmdListType as Clt;
165 
166         let queue_type = self.queue_type();
167         match queue_type {
168             q::QueueType::General | q::QueueType::Graphics => Clt::Direct,
169             q::QueueType::Compute => Clt::Compute,
170             q::QueueType::Transfer => Clt::Copy,
171         }
172     }
173 }
174 
175 static QUEUE_FAMILIES: [QueueFamily; 4] = [
176     QueueFamily::Present,
177     QueueFamily::Normal(q::QueueType::General),
178     QueueFamily::Normal(q::QueueType::Compute),
179     QueueFamily::Normal(q::QueueType::Transfer),
180 ];
181 
182 //Note: fields are dropped in the order of declaration, so we put the
183 // most owning fields last.
184 pub struct PhysicalDevice {
185     features: Features,
186     hints: Hints,
187     limits: Limits,
188     format_properties: Arc<FormatProperties>,
189     private_caps: Capabilities,
190     heap_properties: &'static [HeapProperties; NUM_HEAP_PROPERTIES],
191     memory_properties: adapter::MemoryProperties,
192     // Indicates that there is currently an active logical device.
193     // Opening the same adapter multiple times will return the same D3D12Device again.
194     is_open: Arc<Mutex<bool>>,
195     adapter: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
196     library: Arc<native::D3D12Lib>,
197 }
198 
199 impl fmt::Debug for PhysicalDevice {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result200     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
201         fmt.write_str("PhysicalDevice")
202     }
203 }
204 
205 unsafe impl Send for PhysicalDevice {}
206 unsafe impl Sync for PhysicalDevice {}
207 
208 impl adapter::PhysicalDevice<Backend> for PhysicalDevice {
open( &self, families: &[(&QueueFamily, &[q::QueuePriority])], requested_features: Features, ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError>209     unsafe fn open(
210         &self,
211         families: &[(&QueueFamily, &[q::QueuePriority])],
212         requested_features: Features,
213     ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError> {
214         let lock = self.is_open.try_lock();
215         let mut open_guard = match lock {
216             Ok(inner) => inner,
217             Err(_) => return Err(hal::device::CreationError::TooManyObjects),
218         };
219 
220         if !self.features().contains(requested_features) {
221             return Err(hal::device::CreationError::MissingFeature);
222         }
223 
224         let device_raw = match self
225             .library
226             .create_device(self.adapter, native::FeatureLevel::L11_0)
227         {
228             Ok((device, hr)) if winerror::SUCCEEDED(hr) => device,
229             Ok((_, hr)) => {
230                 error!("error on device creation: {:x}", hr);
231                 return Err(hal::device::CreationError::InitializationFailed);
232             }
233             Err(e) => panic!("device creation failed with {:?}", e),
234         };
235 
236         // Always create the presentation queue in case we want to build a swapchain.
237         let (present_queue, hr_queue) = device_raw.create_command_queue(
238             QueueFamily::Present.native_type(),
239             native::Priority::Normal,
240             native::CommandQueueFlags::empty(),
241             0,
242         );
243         if !winerror::SUCCEEDED(hr_queue) {
244             error!("error on queue creation: {:x}", hr_queue);
245         }
246 
247         let mut device = Device::new(device_raw, &self, present_queue);
248         device.features = requested_features;
249 
250         let queue_groups = families
251             .into_iter()
252             .map(|&(&family, priorities)| {
253                 use hal::queue::QueueFamily as _;
254                 let mut group = q::QueueGroup::new(family.id());
255 
256                 let create_idle_event = || native::Event::create(true, false);
257 
258                 match family {
259                     QueueFamily::Present => {
260                         // Exactly **one** present queue!
261                         // Number of queues need to be larger than 0 else it
262                         // violates the specification.
263                         let queue = CommandQueue {
264                             raw: device.present_queue.clone(),
265                             idle_fence: device.create_raw_fence(false),
266                             idle_event: create_idle_event(),
267                         };
268                         device.append_queue(queue.clone());
269                         group.add_queue(queue);
270                     }
271                     QueueFamily::Normal(_) => {
272                         let list_type = family.native_type();
273                         for _ in 0 .. priorities.len() {
274                             let (queue, hr_queue) = device_raw.create_command_queue(
275                                 list_type,
276                                 native::Priority::Normal,
277                                 native::CommandQueueFlags::empty(),
278                                 0,
279                             );
280 
281                             if winerror::SUCCEEDED(hr_queue) {
282                                 let queue = CommandQueue {
283                                     raw: queue,
284                                     idle_fence: device.create_raw_fence(false),
285                                     idle_event: create_idle_event(),
286                                 };
287                                 device.append_queue(queue.clone());
288                                 group.add_queue(queue);
289                             } else {
290                                 error!("error on queue creation: {:x}", hr_queue);
291                             }
292                         }
293                     }
294                 }
295 
296                 group
297             })
298             .collect();
299 
300         *open_guard = true;
301 
302         Ok(adapter::Gpu {
303             device,
304             queue_groups,
305         })
306     }
307 
format_properties(&self, fmt: Option<f::Format>) -> f::Properties308     fn format_properties(&self, fmt: Option<f::Format>) -> f::Properties {
309         let idx = fmt.map(|fmt| fmt as usize).unwrap_or(0);
310         self.format_properties.get(idx).properties
311     }
312 
image_format_properties( &self, format: f::Format, dimensions: u8, tiling: image::Tiling, usage: image::Usage, view_caps: image::ViewCapabilities, ) -> Option<image::FormatProperties>313     fn image_format_properties(
314         &self,
315         format: f::Format,
316         dimensions: u8,
317         tiling: image::Tiling,
318         usage: image::Usage,
319         view_caps: image::ViewCapabilities,
320     ) -> Option<image::FormatProperties> {
321         conv::map_format(format)?; //filter out unknown formats
322         let format_info = self.format_properties.get(format as usize);
323 
324         let supported_usage = {
325             use hal::image::Usage as U;
326             let props = match tiling {
327                 image::Tiling::Optimal => format_info.properties.optimal_tiling,
328                 image::Tiling::Linear => format_info.properties.linear_tiling,
329             };
330             let mut flags = U::empty();
331             // Note: these checks would have been nicer if we had explicit BLIT usage
332             if props.contains(f::ImageFeature::BLIT_SRC) {
333                 flags |= U::TRANSFER_SRC;
334             }
335             if props.contains(f::ImageFeature::BLIT_DST) {
336                 flags |= U::TRANSFER_DST;
337             }
338             if props.contains(f::ImageFeature::SAMPLED) {
339                 flags |= U::SAMPLED;
340             }
341             if props.contains(f::ImageFeature::STORAGE) {
342                 flags |= U::STORAGE;
343             }
344             if props.contains(f::ImageFeature::COLOR_ATTACHMENT) {
345                 flags |= U::COLOR_ATTACHMENT;
346             }
347             if props.contains(f::ImageFeature::DEPTH_STENCIL_ATTACHMENT) {
348                 flags |= U::DEPTH_STENCIL_ATTACHMENT;
349             }
350             flags
351         };
352         if !supported_usage.contains(usage) {
353             return None;
354         }
355 
356         let max_resource_size =
357             (d3d12::D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM as usize) << 20;
358         Some(match tiling {
359             image::Tiling::Optimal => image::FormatProperties {
360                 max_extent: match dimensions {
361                     1 => image::Extent {
362                         width: d3d12::D3D12_REQ_TEXTURE1D_U_DIMENSION,
363                         height: 1,
364                         depth: 1,
365                     },
366                     2 => image::Extent {
367                         width: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
368                         height: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
369                         depth: 1,
370                     },
371                     3 => image::Extent {
372                         width: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
373                         height: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
374                         depth: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
375                     },
376                     _ => return None,
377                 },
378                 max_levels: d3d12::D3D12_REQ_MIP_LEVELS as _,
379                 max_layers: match dimensions {
380                     1 => d3d12::D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION as _,
381                     2 => d3d12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
382                     _ => return None,
383                 },
384                 sample_count_mask: if dimensions == 2
385                     && !view_caps.contains(image::ViewCapabilities::KIND_CUBE)
386                     && !usage.contains(image::Usage::STORAGE)
387                 {
388                     format_info.sample_count_mask
389                 } else {
390                     0x1
391                 },
392                 max_resource_size,
393             },
394             image::Tiling::Linear => image::FormatProperties {
395                 max_extent: match dimensions {
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                     _ => return None,
402                 },
403                 max_levels: 1,
404                 max_layers: 1,
405                 sample_count_mask: 0x1,
406                 max_resource_size,
407             },
408         })
409     }
410 
memory_properties(&self) -> adapter::MemoryProperties411     fn memory_properties(&self) -> adapter::MemoryProperties {
412         self.memory_properties.clone()
413     }
414 
features(&self) -> Features415     fn features(&self) -> Features {
416         self.features
417     }
418 
hints(&self) -> Hints419     fn hints(&self) -> Hints {
420         self.hints
421     }
422 
limits(&self) -> Limits423     fn limits(&self) -> Limits {
424         self.limits
425     }
426 }
427 
428 #[derive(Clone)]
429 pub struct CommandQueue {
430     pub(crate) raw: native::CommandQueue,
431     idle_fence: native::Fence,
432     idle_event: native::Event,
433 }
434 
435 impl fmt::Debug for CommandQueue {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result436     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
437         fmt.write_str("CommandQueue")
438     }
439 }
440 
441 impl CommandQueue {
destroy(&self)442     unsafe fn destroy(&self) {
443         handleapi::CloseHandle(self.idle_event.0);
444         self.idle_fence.destroy();
445         self.raw.destroy();
446     }
447 }
448 
449 unsafe impl Send for CommandQueue {}
450 unsafe impl Sync for CommandQueue {}
451 
452 impl q::CommandQueue<Backend> for CommandQueue {
submit<'a, T, Ic, S, Iw, Is>( &mut self, submission: q::Submission<Ic, Iw, Is>, fence: Option<&resource::Fence>, ) where T: 'a + Borrow<command::CommandBuffer>, Ic: IntoIterator<Item = &'a T>, S: 'a + Borrow<resource::Semaphore>, Iw: IntoIterator<Item = (&'a S, PipelineStage)>, Is: IntoIterator<Item = &'a S>,453     unsafe fn submit<'a, T, Ic, S, Iw, Is>(
454         &mut self,
455         submission: q::Submission<Ic, Iw, Is>,
456         fence: Option<&resource::Fence>,
457     ) where
458         T: 'a + Borrow<command::CommandBuffer>,
459         Ic: IntoIterator<Item = &'a T>,
460         S: 'a + Borrow<resource::Semaphore>,
461         Iw: IntoIterator<Item = (&'a S, PipelineStage)>,
462         Is: IntoIterator<Item = &'a S>,
463     {
464         // Reset idle fence and event
465         // That's safe here due to exclusive access to the queue
466         self.idle_fence.signal(0);
467         synchapi::ResetEvent(self.idle_event.0);
468 
469         // TODO: semaphores
470         let mut lists = submission
471             .command_buffers
472             .into_iter()
473             .map(|buf| buf.borrow().as_raw_list())
474             .collect::<Vec<_>>();
475         self.raw
476             .ExecuteCommandLists(lists.len() as _, lists.as_mut_ptr());
477 
478         if let Some(fence) = fence {
479             assert_eq!(winerror::S_OK, self.raw.Signal(fence.raw.as_mut_ptr(), 1));
480         }
481     }
482 
present<'a, W, Is, S, Iw>( &mut self, swapchains: Is, _wait_semaphores: Iw, ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError> where W: 'a + Borrow<window::Swapchain>, Is: IntoIterator<Item = (&'a W, hal::window::SwapImageIndex)>, S: 'a + Borrow<resource::Semaphore>, Iw: IntoIterator<Item = &'a S>,483     unsafe fn present<'a, W, Is, S, Iw>(
484         &mut self,
485         swapchains: Is,
486         _wait_semaphores: Iw,
487     ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError>
488     where
489         W: 'a + Borrow<window::Swapchain>,
490         Is: IntoIterator<Item = (&'a W, hal::window::SwapImageIndex)>,
491         S: 'a + Borrow<resource::Semaphore>,
492         Iw: IntoIterator<Item = &'a S>,
493     {
494         // TODO: semaphores
495         for (swapchain, _) in swapchains {
496             swapchain.borrow().inner.Present(1, 0);
497         }
498 
499         Ok(None)
500     }
501 
present_surface( &mut self, surface: &mut window::Surface, _image: resource::ImageView, _wait_semaphore: Option<&resource::Semaphore>, ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError>502     unsafe fn present_surface(
503         &mut self,
504         surface: &mut window::Surface,
505         _image: resource::ImageView,
506         _wait_semaphore: Option<&resource::Semaphore>,
507     ) -> Result<Option<hal::window::Suboptimal>, hal::window::PresentError> {
508         surface.present();
509         Ok(None)
510     }
511 
wait_idle(&self) -> Result<(), hal::device::OutOfMemory>512     fn wait_idle(&self) -> Result<(), hal::device::OutOfMemory> {
513         self.raw.signal(self.idle_fence, 1);
514         assert_eq!(
515             winerror::S_OK,
516             self.idle_fence.set_event_on_completion(self.idle_event, 1)
517         );
518 
519         unsafe {
520             synchapi::WaitForSingleObject(self.idle_event.0, winbase::INFINITE);
521         }
522 
523         Ok(())
524     }
525 }
526 
527 #[derive(Debug, Clone, Copy)]
528 enum MemoryArchitecture {
529     NUMA,
530     UMA,
531     CacheCoherentUMA,
532 }
533 
534 #[derive(Debug, Clone, Copy)]
535 pub struct Capabilities {
536     heterogeneous_resource_heaps: bool,
537     memory_architecture: MemoryArchitecture,
538 }
539 
540 #[derive(Clone, Debug)]
541 struct CmdSignatures {
542     draw: native::CommandSignature,
543     draw_indexed: native::CommandSignature,
544     dispatch: native::CommandSignature,
545 }
546 
547 impl CmdSignatures {
destroy(&self)548     unsafe fn destroy(&self) {
549         self.draw.destroy();
550         self.draw_indexed.destroy();
551         self.dispatch.destroy();
552     }
553 }
554 
555 // Shared objects between command buffers, owned by the device.
556 #[derive(Debug)]
557 struct Shared {
558     pub signatures: CmdSignatures,
559     pub service_pipes: internal::ServicePipes,
560 }
561 
562 impl Shared {
destroy(&self)563     unsafe fn destroy(&self) {
564         self.signatures.destroy();
565         self.service_pipes.destroy();
566     }
567 }
568 
569 pub struct Device {
570     raw: native::Device,
571     private_caps: Capabilities,
572     features: Features,
573     format_properties: Arc<FormatProperties>,
574     heap_properties: &'static [HeapProperties],
575     // CPU only pools
576     rtv_pool: Mutex<DescriptorCpuPool>,
577     dsv_pool: Mutex<DescriptorCpuPool>,
578     srv_uav_pool: Mutex<DescriptorCpuPool>,
579     sampler_pool: Mutex<DescriptorCpuPool>,
580     descriptor_update_pools: Mutex<Vec<descriptors_cpu::HeapLinear>>,
581     // CPU/GPU descriptor heaps
582     heap_srv_cbv_uav: Mutex<resource::DescriptorHeap>,
583     heap_sampler: Mutex<resource::DescriptorHeap>,
584     events: Mutex<Vec<native::Event>>,
585     shared: Arc<Shared>,
586     // Present queue exposed by the `Present` queue family.
587     // Required for swapchain creation. Only a single queue supports presentation.
588     present_queue: native::CommandQueue,
589     // List of all queues created from this device, including present queue.
590     // Needed for `wait_idle`.
591     queues: Vec<CommandQueue>,
592     // Indicates that there is currently an active device.
593     open: Arc<Mutex<bool>>,
594     library: Arc<native::D3D12Lib>,
595 }
596 
597 impl fmt::Debug for Device {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result598     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
599         fmt.write_str("Device")
600     }
601 }
602 
603 unsafe impl Send for Device {} //blocked by ComPtr
604 unsafe impl Sync for Device {} //blocked by ComPtr
605 
606 impl Device {
new( device: native::Device, physical_device: &PhysicalDevice, present_queue: native::CommandQueue, ) -> Self607     fn new(
608         device: native::Device,
609         physical_device: &PhysicalDevice,
610         present_queue: native::CommandQueue,
611     ) -> Self {
612         // Allocate descriptor heaps
613         let rtv_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Rtv);
614         let dsv_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Dsv);
615         let srv_uav_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::CbvSrvUav);
616         let sampler_pool = DescriptorCpuPool::new(device, native::DescriptorHeapType::Sampler);
617 
618         let heap_srv_cbv_uav = Self::create_descriptor_heap_impl(
619             device,
620             native::DescriptorHeapType::CbvSrvUav,
621             true,
622             1_000_000, // maximum number of CBV/SRV/UAV descriptors in heap for Tier 1
623         );
624 
625         let heap_sampler = Self::create_descriptor_heap_impl(
626             device,
627             native::DescriptorHeapType::Sampler,
628             true,
629             2_048,
630         );
631 
632         let draw_signature = Self::create_command_signature(device, device::CommandSignature::Draw);
633         let draw_indexed_signature =
634             Self::create_command_signature(device, device::CommandSignature::DrawIndexed);
635         let dispatch_signature =
636             Self::create_command_signature(device, device::CommandSignature::Dispatch);
637 
638         let signatures = CmdSignatures {
639             draw: draw_signature,
640             draw_indexed: draw_indexed_signature,
641             dispatch: dispatch_signature,
642         };
643         let service_pipes =
644             internal::ServicePipes::new(device, Arc::clone(&physical_device.library));
645         let shared = Shared {
646             signatures,
647             service_pipes,
648         };
649 
650         Device {
651             raw: device,
652             library: Arc::clone(&physical_device.library),
653             private_caps: physical_device.private_caps,
654             features: Features::empty(),
655             format_properties: physical_device.format_properties.clone(),
656             heap_properties: physical_device.heap_properties,
657             rtv_pool: Mutex::new(rtv_pool),
658             dsv_pool: Mutex::new(dsv_pool),
659             srv_uav_pool: Mutex::new(srv_uav_pool),
660             sampler_pool: Mutex::new(sampler_pool),
661             descriptor_update_pools: Mutex::new(Vec::new()),
662             heap_srv_cbv_uav: Mutex::new(heap_srv_cbv_uav),
663             heap_sampler: Mutex::new(heap_sampler),
664             events: Mutex::new(Vec::new()),
665             shared: Arc::new(shared),
666             present_queue,
667             queues: Vec::new(),
668             open: Arc::clone(&physical_device.is_open),
669         }
670     }
671 
append_queue(&mut self, queue: CommandQueue)672     fn append_queue(&mut self, queue: CommandQueue) {
673         self.queues.push(queue);
674     }
675 
676     /// Get the native d3d12 device.
677     ///
678     /// Required for FFI with libraries like RenderDoc.
as_raw(&self) -> *mut d3d12::ID3D12Device679     pub unsafe fn as_raw(&self) -> *mut d3d12::ID3D12Device {
680         self.raw.as_mut_ptr()
681     }
682 }
683 
684 impl Drop for Device {
drop(&mut self)685     fn drop(&mut self) {
686         *self.open.lock().unwrap() = false;
687 
688         unsafe {
689             for queue in &mut self.queues {
690                 queue.destroy();
691             }
692 
693             self.shared.destroy();
694             self.heap_srv_cbv_uav.lock().unwrap().destroy();
695             self.heap_sampler.lock().unwrap().destroy();
696             self.rtv_pool.lock().unwrap().destroy();
697             self.dsv_pool.lock().unwrap().destroy();
698             self.srv_uav_pool.lock().unwrap().destroy();
699             self.sampler_pool.lock().unwrap().destroy();
700 
701             for pool in &*self.descriptor_update_pools.lock().unwrap() {
702                 pool.destroy();
703             }
704 
705             // Debug tracking alive objects
706             let (debug_device, hr_debug) = self.raw.cast::<d3d12sdklayers::ID3D12DebugDevice>();
707             if winerror::SUCCEEDED(hr_debug) {
708                 debug_device.ReportLiveDeviceObjects(d3d12sdklayers::D3D12_RLDO_DETAIL);
709                 debug_device.destroy();
710             }
711 
712             self.raw.destroy();
713         }
714     }
715 }
716 
717 #[derive(Debug)]
718 pub struct Instance {
719     pub(crate) factory: native::Factory4,
720     library: Arc<native::D3D12Lib>,
721     lib_dxgi: native::DxgiLib,
722 }
723 
724 impl Drop for Instance {
drop(&mut self)725     fn drop(&mut self) {
726         unsafe {
727             self.factory.destroy();
728         }
729     }
730 }
731 
732 unsafe impl Send for Instance {}
733 unsafe impl Sync for Instance {}
734 
735 impl hal::Instance<Backend> for Instance {
create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend>736     fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
737         let lib_main = match native::D3D12Lib::new() {
738             Ok(lib) => lib,
739             Err(_) => return Err(hal::UnsupportedBackend),
740         };
741 
742         #[cfg(debug_assertions)]
743         {
744             // Enable debug layer
745             match lib_main.get_debug_interface() {
746                 Ok((debug_controller, hr)) if winerror::SUCCEEDED(hr) => {
747                     debug_controller.enable_layer();
748                     unsafe {
749                         debug_controller.Release();
750                     }
751                 }
752                 _ => {
753                     warn!("Unable to get D3D12 debug interface");
754                 }
755             }
756         }
757 
758         let lib_dxgi = native::DxgiLib::new().unwrap();
759 
760         // The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
761         // `CreateDXGIFactory2` if the debug interface is actually available. So
762         // we check for whether it exists first.
763         let factory_flags = match lib_dxgi.get_debug_interface1() {
764             Ok((queue, hr)) if winerror::SUCCEEDED(hr) => {
765                 unsafe { queue.destroy() };
766                 native::FactoryCreationFlags::DEBUG
767             }
768             _ => native::FactoryCreationFlags::empty(),
769         };
770 
771         // Create DXGI factory
772         let factory = match lib_dxgi.create_factory2(factory_flags) {
773             Ok((factory, hr)) if winerror::SUCCEEDED(hr) => factory,
774             Ok((_, hr)) => {
775                 info!("Failed on dxgi factory creation: {:?}", hr);
776                 return Err(hal::UnsupportedBackend);
777             }
778             Err(_) => return Err(hal::UnsupportedBackend),
779         };
780 
781         Ok(Instance {
782             factory,
783             library: Arc::new(lib_main),
784             lib_dxgi,
785         })
786     }
787 
enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>>788     fn enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>> {
789         use self::memory::Properties;
790 
791         // Try to use high performance order by default (returns None on Windows < 1803)
792         let (use_f6, factory6) = unsafe {
793             let (f6, hr) = self.factory.cast::<dxgi1_6::IDXGIFactory6>();
794             if winerror::SUCCEEDED(hr) {
795                 // It's okay to decrement the refcount here because we
796                 // have another reference to the factory already owned by `self`.
797                 f6.destroy();
798                 (true, f6)
799             } else {
800                 (false, native::WeakPtr::null())
801             }
802         };
803 
804         // Enumerate adapters
805         let mut cur_index = 0;
806         let mut adapters = Vec::new();
807         loop {
808             let adapter = if use_f6 {
809                 let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
810                 let hr = unsafe {
811                     factory6.EnumAdapterByGpuPreference(
812                         cur_index,
813                         2, // HIGH_PERFORMANCE
814                         &dxgi1_2::IDXGIAdapter2::uuidof(),
815                         adapter2.mut_void() as *mut *mut _,
816                     )
817                 };
818 
819                 if hr == winerror::DXGI_ERROR_NOT_FOUND {
820                     break;
821                 }
822 
823                 adapter2
824             } else {
825                 let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
826                 let hr1 = unsafe {
827                     self.factory
828                         .EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _)
829                 };
830 
831                 if hr1 == winerror::DXGI_ERROR_NOT_FOUND {
832                     break;
833                 }
834 
835                 let (adapter2, hr2) = unsafe { adapter1.cast::<dxgi1_2::IDXGIAdapter2>() };
836                 if !winerror::SUCCEEDED(hr2) {
837                     error!("Failed casting to Adapter2");
838                     break;
839                 }
840 
841                 unsafe {
842                     adapter1.destroy();
843                 }
844                 adapter2
845             };
846 
847             cur_index += 1;
848 
849             // Check for D3D12 support
850             // Create temporary device to get physical device information
851             let device = match self
852                 .library
853                 .create_device(adapter, native::FeatureLevel::L11_0)
854             {
855                 Ok((device, hr)) if winerror::SUCCEEDED(hr) => device,
856                 _ => continue,
857             };
858 
859             // We have found a possible adapter
860             // acquire the device information
861             let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
862             unsafe {
863                 adapter.GetDesc2(&mut desc);
864             }
865 
866             let device_name = {
867                 let len = desc.Description.iter().take_while(|&&c| c != 0).count();
868                 let name = <OsString as OsStringExt>::from_wide(&desc.Description[.. len]);
869                 name.to_string_lossy().into_owned()
870             };
871 
872             let info = adapter::AdapterInfo {
873                 name: device_name,
874                 vendor: desc.VendorId as usize,
875                 device: desc.DeviceId as usize,
876                 device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
877                     adapter::DeviceType::VirtualGpu
878                 } else {
879                     adapter::DeviceType::DiscreteGpu
880                 },
881             };
882 
883             let mut features: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() };
884             assert_eq!(winerror::S_OK, unsafe {
885                 device.CheckFeatureSupport(
886                     d3d12::D3D12_FEATURE_D3D12_OPTIONS,
887                     &mut features as *mut _ as *mut _,
888                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS>() as _,
889                 )
890             });
891 
892             let mut features_architecture: d3d12::D3D12_FEATURE_DATA_ARCHITECTURE =
893                 unsafe { mem::zeroed() };
894             assert_eq!(winerror::S_OK, unsafe {
895                 device.CheckFeatureSupport(
896                     d3d12::D3D12_FEATURE_ARCHITECTURE,
897                     &mut features_architecture as *mut _ as *mut _,
898                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_ARCHITECTURE>() as _,
899                 )
900             });
901 
902             let depth_bounds_test_supported = {
903                 let mut features2: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2 =
904                     unsafe { mem::zeroed() };
905                 let hr = unsafe {
906                     device.CheckFeatureSupport(
907                         d3d12::D3D12_FEATURE_D3D12_OPTIONS2,
908                         &mut features2 as *mut _ as *mut _,
909                         mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2>() as _,
910                     )
911                 };
912                 if hr == winerror::S_OK {
913                     features2.DepthBoundsTestSupported != 0
914                 } else {
915                     false
916                 }
917             };
918 
919             let heterogeneous_resource_heaps =
920                 features.ResourceHeapTier != d3d12::D3D12_RESOURCE_HEAP_TIER_1;
921 
922             let uma = features_architecture.UMA == TRUE;
923             let cc_uma = features_architecture.CacheCoherentUMA == TRUE;
924 
925             let (memory_architecture, heap_properties) = match (uma, cc_uma) {
926                 (true, true) => (MemoryArchitecture::CacheCoherentUMA, &HEAPS_CCUMA),
927                 (true, false) => (MemoryArchitecture::UMA, &HEAPS_UMA),
928                 (false, _) => (MemoryArchitecture::NUMA, &HEAPS_NUMA),
929             };
930 
931             // https://msdn.microsoft.com/en-us/library/windows/desktop/dn788678(v=vs.85).aspx
932             let base_memory_types: [adapter::MemoryType; NUM_HEAP_PROPERTIES] =
933                 match memory_architecture {
934                     MemoryArchitecture::NUMA => [
935                         // DEFAULT
936                         adapter::MemoryType {
937                             properties: Properties::DEVICE_LOCAL,
938                             heap_index: 0,
939                         },
940                         // UPLOAD
941                         adapter::MemoryType {
942                             properties: Properties::CPU_VISIBLE | Properties::COHERENT,
943                             heap_index: 1,
944                         },
945                         // READBACK
946                         adapter::MemoryType {
947                             properties: Properties::CPU_VISIBLE
948                                 | Properties::COHERENT
949                                 | Properties::CPU_CACHED,
950                             heap_index: 1,
951                         },
952                     ],
953                     MemoryArchitecture::UMA => [
954                         // DEFAULT
955                         adapter::MemoryType {
956                             properties: Properties::DEVICE_LOCAL,
957                             heap_index: 0,
958                         },
959                         // UPLOAD
960                         adapter::MemoryType {
961                             properties: Properties::DEVICE_LOCAL
962                                 | Properties::CPU_VISIBLE
963                                 | Properties::COHERENT,
964                             heap_index: 0,
965                         },
966                         // READBACK
967                         adapter::MemoryType {
968                             properties: Properties::DEVICE_LOCAL
969                                 | Properties::CPU_VISIBLE
970                                 | Properties::COHERENT
971                                 | Properties::CPU_CACHED,
972                             heap_index: 0,
973                         },
974                     ],
975                     MemoryArchitecture::CacheCoherentUMA => [
976                         // DEFAULT
977                         adapter::MemoryType {
978                             properties: Properties::DEVICE_LOCAL,
979                             heap_index: 0,
980                         },
981                         // UPLOAD
982                         adapter::MemoryType {
983                             properties: Properties::DEVICE_LOCAL
984                                 | Properties::CPU_VISIBLE
985                                 | Properties::COHERENT
986                                 | Properties::CPU_CACHED,
987                             heap_index: 0,
988                         },
989                         // READBACK
990                         adapter::MemoryType {
991                             properties: Properties::DEVICE_LOCAL
992                                 | Properties::CPU_VISIBLE
993                                 | Properties::COHERENT
994                                 | Properties::CPU_CACHED,
995                             heap_index: 0,
996                         },
997                     ],
998                 };
999 
1000             let memory_types = if heterogeneous_resource_heaps {
1001                 base_memory_types.to_vec()
1002             } else {
1003                 // We multiplicate the base memory types depending on the resource usage:
1004                 //     0.. 3: Reserved for futures use
1005                 //     4.. 6: Buffers
1006                 //     7.. 9: Images
1007                 //    10..12: Targets
1008                 //
1009                 // The supported memory types for a resource can be requested by asking for
1010                 // the memory requirements. Memory type indices are encoded as bitflags.
1011                 // `device::MEM_TYPE_MASK` (0b111) defines the bitmask for one base memory type group.
1012                 // The corresponding shift masks (`device::MEM_TYPE_BUFFER_SHIFT`,
1013                 // `device::MEM_TYPE_IMAGE_SHIFT`, `device::MEM_TYPE_TARGET_SHIFT`)
1014                 // denote the usage group.
1015                 let mut types = Vec::new();
1016                 for i in 0 .. MemoryGroup::NumGroups as _ {
1017                     types.extend(base_memory_types.iter().map(|mem_type| {
1018                         let mut ty = mem_type.clone();
1019 
1020                         // Images and Targets are not host visible as we can't create
1021                         // a corresponding buffer for mapping.
1022                         if i == MemoryGroup::ImageOnly as _ || i == MemoryGroup::TargetOnly as _ {
1023                             ty.properties.remove(Properties::CPU_VISIBLE);
1024                             // Coherent and cached can only be on memory types that are cpu visible
1025                             ty.properties.remove(Properties::COHERENT);
1026                             ty.properties.remove(Properties::CPU_CACHED);
1027                         }
1028                         ty
1029                     }));
1030                 }
1031                 types
1032             };
1033 
1034             let memory_heaps = {
1035                 // Get the IDXGIAdapter3 from the created device to query video memory information.
1036                 let adapter_id = unsafe { device.GetAdapterLuid() };
1037                 let adapter = {
1038                     let mut adapter = native::WeakPtr::<dxgi1_4::IDXGIAdapter3>::null();
1039                     unsafe {
1040                         assert_eq!(
1041                             winerror::S_OK,
1042                             self.factory.EnumAdapterByLuid(
1043                                 adapter_id,
1044                                 &dxgi1_4::IDXGIAdapter3::uuidof(),
1045                                 adapter.mut_void(),
1046                             )
1047                         );
1048                     }
1049                     adapter
1050                 };
1051 
1052                 let query_memory = |segment: dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP| unsafe {
1053                     let mut mem_info: dxgi1_4::DXGI_QUERY_VIDEO_MEMORY_INFO = mem::zeroed();
1054                     assert_eq!(
1055                         winerror::S_OK,
1056                         adapter.QueryVideoMemoryInfo(0, segment, &mut mem_info)
1057                     );
1058                     mem_info.Budget
1059                 };
1060 
1061                 let local = query_memory(dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP_LOCAL);
1062                 match memory_architecture {
1063                     MemoryArchitecture::NUMA => {
1064                         let non_local = query_memory(dxgi1_4::DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL);
1065                         vec![local, non_local]
1066                     }
1067                     _ => vec![local],
1068                 }
1069             };
1070             //TODO: find a way to get a tighter bound?
1071             let sample_count_mask = 0x3F;
1072 
1073             let physical_device = PhysicalDevice {
1074                 library: Arc::clone(&self.library),
1075                 adapter,
1076                 features:
1077                     // TODO: add more features, based on
1078                     // https://msdn.microsoft.com/de-de/library/windows/desktop/mt186615(v=vs.85).aspx
1079                     Features::ROBUST_BUFFER_ACCESS |
1080                     Features::IMAGE_CUBE_ARRAY |
1081                     Features::GEOMETRY_SHADER |
1082                     Features::TESSELLATION_SHADER |
1083                     Features::NON_FILL_POLYGON_MODE |
1084                     if depth_bounds_test_supported { Features::DEPTH_BOUNDS } else { Features::empty() } |
1085                     //logic_op: false, // Optional on feature level 11_0
1086                     Features::MULTI_DRAW_INDIRECT |
1087                     Features::FORMAT_BC |
1088                     Features::INSTANCE_RATE |
1089                     Features::SAMPLER_MIP_LOD_BIAS |
1090                     Features::SAMPLER_ANISOTROPY |
1091                     Features::SAMPLER_MIRROR_CLAMP_EDGE |
1092                     Features::NDC_Y_UP,
1093                 hints:
1094                     Hints::BASE_VERTEX_INSTANCE_DRAWING,
1095                 limits: Limits { // TODO
1096                     max_image_1d_size: d3d12::D3D12_REQ_TEXTURE1D_U_DIMENSION as _,
1097                     max_image_2d_size: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION as _,
1098                     max_image_3d_size: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION as _,
1099                     max_image_cube_size: d3d12::D3D12_REQ_TEXTURECUBE_DIMENSION as _,
1100                     max_image_array_layers: d3d12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
1101                     max_texel_elements: 0,
1102                     max_patch_size: 0,
1103                     max_viewports: d3d12::D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE as _,
1104                     max_viewport_dimensions: [d3d12::D3D12_VIEWPORT_BOUNDS_MAX as _; 2],
1105                     max_framebuffer_extent: hal::image::Extent { //TODO
1106                         width: 4096,
1107                         height: 4096,
1108                         depth: 1,
1109                     },
1110                     max_compute_work_group_count: [
1111                         d3d12::D3D12_CS_THREAD_GROUP_MAX_X,
1112                         d3d12::D3D12_CS_THREAD_GROUP_MAX_Y,
1113                         d3d12::D3D12_CS_THREAD_GROUP_MAX_Z,
1114                     ],
1115                     max_compute_work_group_size: [
1116                         d3d12::D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP,
1117                         1, //TODO
1118                         1, //TODO
1119                     ],
1120                     max_vertex_input_attributes: d3d12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT as _,
1121                     max_vertex_input_bindings: 31, //TODO
1122                     max_vertex_input_attribute_offset: 255, // TODO
1123                     max_vertex_input_binding_stride: d3d12::D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES as _,
1124                     max_vertex_output_components: 16, // TODO
1125                     min_texel_buffer_offset_alignment: 1, // TODO
1126                     min_uniform_buffer_offset_alignment: 256, // Required alignment for CBVs
1127                     min_storage_buffer_offset_alignment: 1, // TODO
1128                     framebuffer_color_sample_counts: sample_count_mask,
1129                     framebuffer_depth_sample_counts: sample_count_mask,
1130                     framebuffer_stencil_sample_counts: sample_count_mask,
1131                     max_color_attachments: d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as _,
1132                     buffer_image_granularity: 1,
1133                     non_coherent_atom_size: 1, //TODO: confirm
1134                     max_sampler_anisotropy: 16.,
1135                     optimal_buffer_copy_offset_alignment: d3d12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as _,
1136                     optimal_buffer_copy_pitch_alignment: d3d12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as _,
1137                     min_vertex_input_binding_stride_alignment: 1,
1138                     .. Limits::default() //TODO
1139                 },
1140                 format_properties: Arc::new(FormatProperties::new(device)),
1141                 private_caps: Capabilities {
1142                     heterogeneous_resource_heaps,
1143                     memory_architecture,
1144                 },
1145                 heap_properties,
1146                 memory_properties: adapter::MemoryProperties {
1147                     memory_types,
1148                     memory_heaps,
1149                 },
1150                 is_open: Arc::new(Mutex::new(false)),
1151             };
1152 
1153             let queue_families = QUEUE_FAMILIES.to_vec();
1154 
1155             adapters.push(adapter::Adapter {
1156                 info,
1157                 physical_device,
1158                 queue_families,
1159             });
1160         }
1161         adapters
1162     }
1163 
create_surface( &self, has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result<window::Surface, hal::window::InitError>1164     unsafe fn create_surface(
1165         &self,
1166         has_handle: &impl raw_window_handle::HasRawWindowHandle,
1167     ) -> Result<window::Surface, hal::window::InitError> {
1168         match has_handle.raw_window_handle() {
1169             raw_window_handle::RawWindowHandle::Windows(handle) => {
1170                 Ok(self.create_surface_from_hwnd(handle.hwnd))
1171             }
1172             _ => Err(hal::window::InitError::UnsupportedWindowHandle),
1173         }
1174     }
1175 
destroy_surface(&self, _surface: window::Surface)1176     unsafe fn destroy_surface(&self, _surface: window::Surface) {
1177         // TODO: Implement Surface cleanup
1178     }
1179 }
1180 
1181 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1182 pub enum Backend {}
1183 impl hal::Backend for Backend {
1184     type Instance = Instance;
1185     type PhysicalDevice = PhysicalDevice;
1186     type Device = Device;
1187 
1188     type Surface = window::Surface;
1189     type Swapchain = window::Swapchain;
1190 
1191     type QueueFamily = QueueFamily;
1192     type CommandQueue = CommandQueue;
1193     type CommandBuffer = command::CommandBuffer;
1194 
1195     type Memory = resource::Memory;
1196     type CommandPool = pool::CommandPool;
1197 
1198     type ShaderModule = resource::ShaderModule;
1199     type RenderPass = resource::RenderPass;
1200     type Framebuffer = resource::Framebuffer;
1201 
1202     type Buffer = resource::Buffer;
1203     type BufferView = resource::BufferView;
1204     type Image = resource::Image;
1205     type ImageView = resource::ImageView;
1206     type Sampler = resource::Sampler;
1207 
1208     type ComputePipeline = resource::ComputePipeline;
1209     type GraphicsPipeline = resource::GraphicsPipeline;
1210     type PipelineLayout = resource::PipelineLayout;
1211     type PipelineCache = ();
1212     type DescriptorSetLayout = resource::DescriptorSetLayout;
1213     type DescriptorPool = resource::DescriptorPool;
1214     type DescriptorSet = resource::DescriptorSet;
1215 
1216     type Fence = resource::Fence;
1217     type Semaphore = resource::Semaphore;
1218     type Event = ();
1219     type QueryPool = resource::QueryPool;
1220 }
1221 
validate_line_width(width: f32)1222 fn validate_line_width(width: f32) {
1223     // Note from the Vulkan spec:
1224     // > If the wide lines feature is not enabled, lineWidth must be 1.0
1225     // Simply assert and no-op because DX12 never exposes `Features::LINE_WIDTH`
1226     assert_eq!(width, 1.0);
1227 }
1228 
1229 #[derive(Clone, Copy, Debug, Default)]
1230 struct FormatInfo {
1231     properties: f::Properties,
1232     sample_count_mask: u8,
1233 }
1234 
1235 #[derive(Debug)]
1236 pub struct FormatProperties {
1237     info: Box<[Mutex<Option<FormatInfo>>]>,
1238     device: native::Device,
1239 }
1240 
1241 impl Drop for FormatProperties {
drop(&mut self)1242     fn drop(&mut self) {
1243         unsafe {
1244             self.device.destroy();
1245         }
1246     }
1247 }
1248 
1249 impl FormatProperties {
new(device: native::Device) -> Self1250     fn new(device: native::Device) -> Self {
1251         let mut buf = Vec::with_capacity(f::NUM_FORMATS);
1252         buf.push(Mutex::new(Some(FormatInfo::default())));
1253         for _ in 1 .. f::NUM_FORMATS {
1254             buf.push(Mutex::new(None))
1255         }
1256         FormatProperties {
1257             info: buf.into_boxed_slice(),
1258             device,
1259         }
1260     }
1261 
get(&self, idx: usize) -> FormatInfo1262     fn get(&self, idx: usize) -> FormatInfo {
1263         let mut guard = self.info[idx].lock().unwrap();
1264         if let Some(info) = *guard {
1265             return info;
1266         }
1267         let format: f::Format = unsafe { mem::transmute(idx as u32) };
1268         let dxgi_format = match conv::map_format(format) {
1269             Some(format) => format,
1270             None => {
1271                 let info = FormatInfo::default();
1272                 *guard = Some(info);
1273                 return info;
1274             }
1275         };
1276 
1277         let properties = {
1278             let mut props = f::Properties::default();
1279             let mut data = d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
1280                 Format: dxgi_format,
1281                 Support1: unsafe { mem::zeroed() },
1282                 Support2: unsafe { mem::zeroed() },
1283             };
1284             assert_eq!(winerror::S_OK, unsafe {
1285                 self.device.CheckFeatureSupport(
1286                     d3d12::D3D12_FEATURE_FORMAT_SUPPORT,
1287                     &mut data as *mut _ as *mut _,
1288                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
1289                 )
1290             });
1291             let can_buffer = 0 != data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_BUFFER;
1292             let can_image = 0
1293                 != data.Support1
1294                     & (d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE1D
1295                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE2D
1296                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE3D
1297                         | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE);
1298             let can_linear = can_image && !format.surface_desc().is_compressed();
1299             if can_image {
1300                 props.optimal_tiling |= f::ImageFeature::SAMPLED | f::ImageFeature::BLIT_SRC;
1301             }
1302             if can_linear {
1303                 props.linear_tiling |= f::ImageFeature::SAMPLED | f::ImageFeature::BLIT_SRC;
1304             }
1305             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER != 0 {
1306                 props.buffer_features |= f::BufferFeature::VERTEX;
1307             }
1308             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0 {
1309                 props.optimal_tiling |= f::ImageFeature::SAMPLED_LINEAR;
1310             }
1311             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0 {
1312                 props.optimal_tiling |=
1313                     f::ImageFeature::COLOR_ATTACHMENT | f::ImageFeature::BLIT_DST;
1314                 if can_linear {
1315                     props.linear_tiling |=
1316                         f::ImageFeature::COLOR_ATTACHMENT | f::ImageFeature::BLIT_DST;
1317                 }
1318             }
1319             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0 {
1320                 props.optimal_tiling |= f::ImageFeature::COLOR_ATTACHMENT_BLEND;
1321             }
1322             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL != 0 {
1323                 props.optimal_tiling |= f::ImageFeature::DEPTH_STENCIL_ATTACHMENT;
1324             }
1325             if data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD != 0 {
1326                 //TODO: check d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD ?
1327                 if can_buffer {
1328                     props.buffer_features |= f::BufferFeature::UNIFORM_TEXEL;
1329                 }
1330             }
1331             if data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD != 0 {
1332                 //TODO: other atomic flags?
1333                 if can_buffer {
1334                     props.buffer_features |= f::BufferFeature::STORAGE_TEXEL_ATOMIC;
1335                 }
1336                 if can_image {
1337                     props.optimal_tiling |= f::ImageFeature::STORAGE_ATOMIC;
1338                 }
1339             }
1340             if data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0 {
1341                 if can_buffer {
1342                     props.buffer_features |= f::BufferFeature::STORAGE_TEXEL;
1343                 }
1344                 if can_image {
1345                     props.optimal_tiling |= f::ImageFeature::STORAGE;
1346                 }
1347             }
1348             //TODO: blits, linear tiling
1349             props
1350         };
1351 
1352         let mut sample_count_mask = 0;
1353         for i in 0 .. 6 {
1354             let mut data = d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
1355                 Format: dxgi_format,
1356                 SampleCount: 1 << i,
1357                 Flags: 0,
1358                 NumQualityLevels: 0,
1359             };
1360             assert_eq!(winerror::S_OK, unsafe {
1361                 self.device.CheckFeatureSupport(
1362                     d3d12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
1363                     &mut data as *mut _ as *mut _,
1364                     mem::size_of::<d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS>() as _,
1365                 )
1366             });
1367             if data.NumQualityLevels != 0 {
1368                 sample_count_mask |= 1 << i;
1369             }
1370         }
1371 
1372         let info = FormatInfo {
1373             properties,
1374             sample_count_mask,
1375         };
1376         *guard = Some(info);
1377         info
1378     }
1379 }
1380