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