1 use std::{collections::hash_map::Entry, ffi, iter, mem, ops::Range, ptr, slice, sync::Arc};
2 
3 use range_alloc::RangeAllocator;
4 use smallvec::SmallVec;
5 use spirv_cross::{hlsl, spirv, ErrorCode as SpirvErrorCode};
6 
7 use winapi::{
8     shared::{
9         dxgi, dxgi1_2, dxgi1_4, dxgiformat, dxgitype,
10         minwindef::{FALSE, TRUE, UINT},
11         windef, winerror,
12     },
13     um::{d3d12, d3dcompiler, synchapi, winbase, winnt},
14     Interface,
15 };
16 
17 use auxil::{spirv_cross_specialize_ast, ShaderStage};
18 use hal::{
19     buffer, device as d, format, format::Aspects, image, memory, memory::Requirements, pass,
20     pool::CommandPoolCreateFlags, pso, pso::VertexInputRate, query, queue::QueueFamilyId,
21     window as w,
22 };
23 
24 use crate::{
25     command as cmd, conv, descriptors_cpu, pool::CommandPool, resource as r, root_constants,
26     root_constants::RootConstant, window::Swapchain, Backend as B, Device, MemoryGroup,
27     MAX_VERTEX_BUFFERS, NUM_HEAP_PROPERTIES, QUEUE_FAMILIES,
28 };
29 use native::{PipelineStateSubobject, Subobject};
30 
31 // Register space used for root constants.
32 const ROOT_CONSTANT_SPACE: u32 = 0;
33 
34 const MEM_TYPE_MASK: u32 = 0x7;
35 const MEM_TYPE_SHIFT: u32 = 3;
36 
37 const MEM_TYPE_UNIVERSAL_SHIFT: u32 = MEM_TYPE_SHIFT * MemoryGroup::Universal as u32;
38 const MEM_TYPE_BUFFER_SHIFT: u32 = MEM_TYPE_SHIFT * MemoryGroup::BufferOnly as u32;
39 const MEM_TYPE_IMAGE_SHIFT: u32 = MEM_TYPE_SHIFT * MemoryGroup::ImageOnly as u32;
40 const MEM_TYPE_TARGET_SHIFT: u32 = MEM_TYPE_SHIFT * MemoryGroup::TargetOnly as u32;
41 
42 pub const IDENTITY_MAPPING: UINT = 0x1688; // D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
43 
wide_cstr(name: &str) -> Vec<u16>44 fn wide_cstr(name: &str) -> Vec<u16> {
45     name.encode_utf16().chain(iter::once(0)).collect()
46 }
47 
48 /// Emit error during shader module creation. Used if we don't expect an error
49 /// but might panic due to an exception in SPIRV-Cross.
gen_unexpected_error(stage: ShaderStage, err: SpirvErrorCode) -> pso::CreationError50 fn gen_unexpected_error(stage: ShaderStage, err: SpirvErrorCode) -> pso::CreationError {
51     let msg = match err {
52         SpirvErrorCode::CompilationError(msg) => msg,
53         SpirvErrorCode::Unhandled => "Unexpected error".into(),
54     };
55     let error = format!("SPIR-V unexpected error {:?}", msg);
56     pso::CreationError::ShaderCreationError(stage.to_flag(), error)
57 }
58 
59 /// Emit error during shader module creation. Used if we execute an query command.
gen_query_error(stage: ShaderStage, err: SpirvErrorCode) -> pso::CreationError60 fn gen_query_error(stage: ShaderStage, err: SpirvErrorCode) -> pso::CreationError {
61     let msg = match err {
62         SpirvErrorCode::CompilationError(msg) => msg,
63         SpirvErrorCode::Unhandled => "Unknown query error".into(),
64     };
65     let error = format!("SPIR-V query error {:?}", msg);
66     pso::CreationError::ShaderCreationError(stage.to_flag(), error)
67 }
68 
69 #[derive(Clone, Debug)]
70 pub(crate) struct ViewInfo {
71     pub(crate) resource: native::Resource,
72     pub(crate) kind: image::Kind,
73     pub(crate) caps: image::ViewCapabilities,
74     pub(crate) view_kind: image::ViewKind,
75     pub(crate) format: dxgiformat::DXGI_FORMAT,
76     pub(crate) component_mapping: UINT,
77     pub(crate) levels: Range<image::Level>,
78     pub(crate) layers: Range<image::Layer>,
79 }
80 
81 pub(crate) enum CommandSignature {
82     Draw,
83     DrawIndexed,
84     Dispatch,
85 }
86 
87 /// Compile a single shader entry point from a HLSL text shader
compile_shader( stage: ShaderStage, shader_model: hlsl::ShaderModel, features: &hal::Features, entry: &str, code: &[u8], ) -> Result<native::Blob, pso::CreationError>88 pub(crate) fn compile_shader(
89     stage: ShaderStage,
90     shader_model: hlsl::ShaderModel,
91     features: &hal::Features,
92     entry: &str,
93     code: &[u8],
94 ) -> Result<native::Blob, pso::CreationError> {
95     let stage_str = match stage {
96         ShaderStage::Vertex => "vs",
97         ShaderStage::Fragment => "ps",
98         ShaderStage::Compute => "cs",
99         _ => unimplemented!(),
100     };
101     let model_str = match shader_model {
102         hlsl::ShaderModel::V5_0 => "5_0",
103         hlsl::ShaderModel::V5_1 => "5_1",
104         hlsl::ShaderModel::V6_0 => "6_0",
105         _ => unimplemented!(),
106     };
107     let full_stage = format!("{}_{}\0", stage_str, model_str);
108 
109     let mut shader_data = native::Blob::null();
110     let mut error = native::Blob::null();
111     let entry = ffi::CString::new(entry).unwrap();
112     let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS;
113     if cfg!(debug_assertions) {
114         compile_flags |= d3dcompiler::D3DCOMPILE_DEBUG;
115     }
116     if features.contains(hal::Features::UNSIZED_DESCRIPTOR_ARRAY) {
117         compile_flags |= d3dcompiler::D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES;
118     }
119     let hr = unsafe {
120         d3dcompiler::D3DCompile(
121             code.as_ptr() as *const _,
122             code.len(),
123             ptr::null(),
124             ptr::null(),
125             ptr::null_mut(),
126             entry.as_ptr() as *const _,
127             full_stage.as_ptr() as *const i8,
128             compile_flags,
129             0,
130             shader_data.mut_void() as *mut *mut _,
131             error.mut_void() as *mut *mut _,
132         )
133     };
134     if !winerror::SUCCEEDED(hr) {
135         let message = unsafe {
136             let pointer = error.GetBufferPointer();
137             let size = error.GetBufferSize();
138             let slice = slice::from_raw_parts(pointer as *const u8, size as usize);
139             String::from_utf8_lossy(slice).into_owned()
140         };
141         unsafe {
142             error.destroy();
143         }
144         let error = format!("D3DCompile error {:x}: {}", hr, message);
145         Err(pso::CreationError::ShaderCreationError(
146             stage.to_flag(),
147             error,
148         ))
149     } else {
150         Ok(shader_data)
151     }
152 }
153 
154 #[repr(C)]
155 struct GraphicsPipelineStateSubobjectStream {
156     root_signature: PipelineStateSubobject<*mut d3d12::ID3D12RootSignature>,
157     vs: PipelineStateSubobject<d3d12::D3D12_SHADER_BYTECODE>,
158     ps: PipelineStateSubobject<d3d12::D3D12_SHADER_BYTECODE>,
159     ds: PipelineStateSubobject<d3d12::D3D12_SHADER_BYTECODE>,
160     hs: PipelineStateSubobject<d3d12::D3D12_SHADER_BYTECODE>,
161     gs: PipelineStateSubobject<d3d12::D3D12_SHADER_BYTECODE>,
162     stream_output: PipelineStateSubobject<d3d12::D3D12_STREAM_OUTPUT_DESC>,
163     blend: PipelineStateSubobject<d3d12::D3D12_BLEND_DESC>,
164     sample_mask: PipelineStateSubobject<UINT>,
165     rasterizer: PipelineStateSubobject<d3d12::D3D12_RASTERIZER_DESC>,
166     depth_stencil: PipelineStateSubobject<d3d12::D3D12_DEPTH_STENCIL_DESC1>,
167     input_layout: PipelineStateSubobject<d3d12::D3D12_INPUT_LAYOUT_DESC>,
168     ib_strip_cut_value: PipelineStateSubobject<d3d12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE>,
169     primitive_topology: PipelineStateSubobject<d3d12::D3D12_PRIMITIVE_TOPOLOGY_TYPE>,
170     render_target_formats: PipelineStateSubobject<d3d12::D3D12_RT_FORMAT_ARRAY>,
171     depth_stencil_format: PipelineStateSubobject<dxgiformat::DXGI_FORMAT>,
172     sample_desc: PipelineStateSubobject<dxgitype::DXGI_SAMPLE_DESC>,
173     node_mask: PipelineStateSubobject<UINT>,
174     cached_pso: PipelineStateSubobject<d3d12::D3D12_CACHED_PIPELINE_STATE>,
175     flags: PipelineStateSubobject<d3d12::D3D12_PIPELINE_STATE_FLAGS>,
176 }
177 
178 impl GraphicsPipelineStateSubobjectStream {
new( pso_desc: &d3d12::D3D12_GRAPHICS_PIPELINE_STATE_DESC, depth_bounds_test_enable: bool, ) -> Self179     fn new(
180         pso_desc: &d3d12::D3D12_GRAPHICS_PIPELINE_STATE_DESC,
181         depth_bounds_test_enable: bool,
182     ) -> Self {
183         GraphicsPipelineStateSubobjectStream {
184             root_signature: PipelineStateSubobject::new(
185                 Subobject::RootSignature,
186                 pso_desc.pRootSignature,
187             ),
188             vs: PipelineStateSubobject::new(Subobject::VS, pso_desc.VS),
189             ps: PipelineStateSubobject::new(Subobject::PS, pso_desc.PS),
190             ds: PipelineStateSubobject::new(Subobject::DS, pso_desc.DS),
191             hs: PipelineStateSubobject::new(Subobject::HS, pso_desc.HS),
192             gs: PipelineStateSubobject::new(Subobject::GS, pso_desc.GS),
193             stream_output: PipelineStateSubobject::new(
194                 Subobject::StreamOutput,
195                 pso_desc.StreamOutput,
196             ),
197             blend: PipelineStateSubobject::new(Subobject::Blend, pso_desc.BlendState),
198             sample_mask: PipelineStateSubobject::new(Subobject::SampleMask, pso_desc.SampleMask),
199             rasterizer: PipelineStateSubobject::new(
200                 Subobject::Rasterizer,
201                 pso_desc.RasterizerState,
202             ),
203             depth_stencil: PipelineStateSubobject::new(
204                 Subobject::DepthStencil1,
205                 d3d12::D3D12_DEPTH_STENCIL_DESC1 {
206                     DepthEnable: pso_desc.DepthStencilState.DepthEnable,
207                     DepthWriteMask: pso_desc.DepthStencilState.DepthWriteMask,
208                     DepthFunc: pso_desc.DepthStencilState.DepthFunc,
209                     StencilEnable: pso_desc.DepthStencilState.StencilEnable,
210                     StencilReadMask: pso_desc.DepthStencilState.StencilReadMask,
211                     StencilWriteMask: pso_desc.DepthStencilState.StencilWriteMask,
212                     FrontFace: pso_desc.DepthStencilState.FrontFace,
213                     BackFace: pso_desc.DepthStencilState.BackFace,
214                     DepthBoundsTestEnable: depth_bounds_test_enable as _,
215                 },
216             ),
217             input_layout: PipelineStateSubobject::new(Subobject::InputLayout, pso_desc.InputLayout),
218             ib_strip_cut_value: PipelineStateSubobject::new(
219                 Subobject::IBStripCut,
220                 pso_desc.IBStripCutValue,
221             ),
222             primitive_topology: PipelineStateSubobject::new(
223                 Subobject::PrimitiveTopology,
224                 pso_desc.PrimitiveTopologyType,
225             ),
226             render_target_formats: PipelineStateSubobject::new(
227                 Subobject::RTFormats,
228                 d3d12::D3D12_RT_FORMAT_ARRAY {
229                     RTFormats: pso_desc.RTVFormats,
230                     NumRenderTargets: pso_desc.NumRenderTargets,
231                 },
232             ),
233             depth_stencil_format: PipelineStateSubobject::new(
234                 Subobject::DSFormat,
235                 pso_desc.DSVFormat,
236             ),
237             sample_desc: PipelineStateSubobject::new(Subobject::SampleDesc, pso_desc.SampleDesc),
238             node_mask: PipelineStateSubobject::new(Subobject::NodeMask, pso_desc.NodeMask),
239             cached_pso: PipelineStateSubobject::new(Subobject::CachedPSO, pso_desc.CachedPSO),
240             flags: PipelineStateSubobject::new(Subobject::Flags, pso_desc.Flags),
241         }
242     }
243 }
244 
245 impl Device {
parse_spirv( stage: ShaderStage, raw_data: &[u32], ) -> Result<spirv::Ast<hlsl::Target>, pso::CreationError>246     fn parse_spirv(
247         stage: ShaderStage,
248         raw_data: &[u32],
249     ) -> Result<spirv::Ast<hlsl::Target>, pso::CreationError> {
250         let module = spirv::Module::from_words(raw_data);
251 
252         spirv::Ast::parse(&module).map_err(|err| {
253             let msg = match err {
254                 SpirvErrorCode::CompilationError(msg) => msg,
255                 SpirvErrorCode::Unhandled => "Unknown parsing error".into(),
256             };
257             let error = format!("SPIR-V parsing failed: {:?}", msg);
258             pso::CreationError::ShaderCreationError(stage.to_flag(), error)
259         })
260     }
261 
262     /// Introspects the input attributes of given SPIR-V shader and returns an optional vertex semantic remapping.
263     ///
264     /// The returned hashmap has attribute location as a key and an Optional remapping to a two part semantic.
265     ///
266     /// eg.
267     /// `2 -> None` means use default semantic `TEXCOORD2`
268     /// `2 -> Some((0, 2))` means use two part semantic `TEXCOORD0_2`. This is how matrices are represented by spirv-cross.
269     ///
270     /// This is a temporary workaround for https://github.com/KhronosGroup/SPIRV-Cross/issues/1512.
271     ///
272     /// This workaround also exists under the same name in the DX11 backend.
introspect_spirv_vertex_semantic_remapping( raw_data: &[u32], ) -> Result<auxil::FastHashMap<u32, Option<(u32, u32)>>, pso::CreationError>273     pub(crate) fn introspect_spirv_vertex_semantic_remapping(
274         raw_data: &[u32],
275     ) -> Result<auxil::FastHashMap<u32, Option<(u32, u32)>>, pso::CreationError> {
276         const SHADER_STAGE: ShaderStage = ShaderStage::Vertex;
277         // This is inefficient as we already parse it once before. This is a temporary workaround only called
278         // on vertex shaders. If this becomes permanent or shows up in profiles, deduplicate these as first course of action.
279         let ast = Self::parse_spirv(SHADER_STAGE, raw_data)?;
280 
281         let mut map = auxil::FastHashMap::default();
282 
283         let inputs = ast
284             .get_shader_resources()
285             .map_err(|err| gen_query_error(SHADER_STAGE, err))?
286             .stage_inputs;
287         for input in inputs {
288             let idx = ast
289                 .get_decoration(input.id, spirv::Decoration::Location)
290                 .map_err(|err| gen_query_error(SHADER_STAGE, err))?;
291 
292             let ty = ast
293                 .get_type(input.type_id)
294                 .map_err(|err| gen_query_error(SHADER_STAGE, err))?;
295 
296             match ty {
297                 spirv::Type::Boolean { columns, .. }
298                 | spirv::Type::Int { columns, .. }
299                 | spirv::Type::UInt { columns, .. }
300                 | spirv::Type::Half { columns, .. }
301                 | spirv::Type::Float { columns, .. }
302                 | spirv::Type::Double { columns, .. }
303                     if columns > 1 =>
304                 {
305                     for col in 0..columns {
306                         if let Some(_) = map.insert(idx + col, Some((idx, col))) {
307                             let error = format!(
308                                 "Shader has overlapping input attachments at location {}",
309                                 idx
310                             );
311                             return Err(pso::CreationError::ShaderCreationError(
312                                 SHADER_STAGE.to_flag(),
313                                 error,
314                             ));
315                         }
316                     }
317                 }
318                 _ => {
319                     if let Some(_) = map.insert(idx, None) {
320                         let error = format!(
321                             "Shader has overlapping input attachments at location {}",
322                             idx
323                         );
324                         return Err(pso::CreationError::ShaderCreationError(
325                             SHADER_STAGE.to_flag(),
326                             error,
327                         ));
328                     }
329                 }
330             }
331         }
332 
333         Ok(map)
334     }
335 
patch_spirv_resources( stage: ShaderStage, ast: &mut spirv::Ast<hlsl::Target>, layout: &r::PipelineLayout, ) -> Result<(), pso::CreationError>336     fn patch_spirv_resources(
337         stage: ShaderStage,
338         ast: &mut spirv::Ast<hlsl::Target>,
339         layout: &r::PipelineLayout,
340     ) -> Result<(), pso::CreationError> {
341         // Move the descriptor sets away to yield for the root constants at "space0".
342         let space_offset = if layout.shared.constants.is_empty() {
343             0
344         } else {
345             1
346         };
347         let shader_resources = ast
348             .get_shader_resources()
349             .map_err(|err| gen_query_error(stage, err))?;
350 
351         if space_offset != 0 {
352             for image in &shader_resources.separate_images {
353                 let set = ast
354                     .get_decoration(image.id, spirv::Decoration::DescriptorSet)
355                     .map_err(|err| gen_query_error(stage, err))?;
356                 ast.set_decoration(
357                     image.id,
358                     spirv::Decoration::DescriptorSet,
359                     space_offset + set,
360                 )
361                 .map_err(|err| gen_unexpected_error(stage, err))?;
362             }
363         }
364 
365         if space_offset != 0 {
366             for uniform_buffer in &shader_resources.uniform_buffers {
367                 let set = ast
368                     .get_decoration(uniform_buffer.id, spirv::Decoration::DescriptorSet)
369                     .map_err(|err| gen_query_error(stage, err))?;
370                 ast.set_decoration(
371                     uniform_buffer.id,
372                     spirv::Decoration::DescriptorSet,
373                     space_offset + set,
374                 )
375                 .map_err(|err| gen_unexpected_error(stage, err))?;
376             }
377         }
378 
379         for storage_buffer in &shader_resources.storage_buffers {
380             let set = ast
381                 .get_decoration(storage_buffer.id, spirv::Decoration::DescriptorSet)
382                 .map_err(|err| gen_query_error(stage, err))?;
383             let binding = ast
384                 .get_decoration(storage_buffer.id, spirv::Decoration::Binding)
385                 .map_err(|err| gen_query_error(stage, err))?;
386             if space_offset != 0 {
387                 ast.set_decoration(
388                     storage_buffer.id,
389                     spirv::Decoration::DescriptorSet,
390                     space_offset + set,
391                 )
392                 .map_err(|err| gen_unexpected_error(stage, err))?;
393             }
394             if !layout.elements[set as usize]
395                 .mutable_bindings
396                 .contains(&binding)
397             {
398                 ast.set_decoration(storage_buffer.id, spirv::Decoration::NonWritable, 1)
399                     .map_err(|err| gen_unexpected_error(stage, err))?
400             }
401         }
402 
403         for image in &shader_resources.storage_images {
404             let set = ast
405                 .get_decoration(image.id, spirv::Decoration::DescriptorSet)
406                 .map_err(|err| gen_query_error(stage, err))?;
407             let binding = ast
408                 .get_decoration(image.id, spirv::Decoration::Binding)
409                 .map_err(|err| gen_query_error(stage, err))?;
410             if space_offset != 0 {
411                 ast.set_decoration(
412                     image.id,
413                     spirv::Decoration::DescriptorSet,
414                     space_offset + set,
415                 )
416                 .map_err(|err| gen_unexpected_error(stage, err))?;
417             }
418             if !layout.elements[set as usize]
419                 .mutable_bindings
420                 .contains(&binding)
421             {
422                 ast.set_decoration(image.id, spirv::Decoration::NonWritable, 1)
423                     .map_err(|err| gen_unexpected_error(stage, err))?
424             }
425         }
426 
427         if space_offset != 0 {
428             for sampler in &shader_resources.separate_samplers {
429                 let set = ast
430                     .get_decoration(sampler.id, spirv::Decoration::DescriptorSet)
431                     .map_err(|err| gen_query_error(stage, err))?;
432                 ast.set_decoration(
433                     sampler.id,
434                     spirv::Decoration::DescriptorSet,
435                     space_offset + set,
436                 )
437                 .map_err(|err| gen_unexpected_error(stage, err))?;
438             }
439         }
440 
441         if space_offset != 0 {
442             for image in &shader_resources.sampled_images {
443                 let set = ast
444                     .get_decoration(image.id, spirv::Decoration::DescriptorSet)
445                     .map_err(|err| gen_query_error(stage, err))?;
446                 ast.set_decoration(
447                     image.id,
448                     spirv::Decoration::DescriptorSet,
449                     space_offset + set,
450                 )
451                 .map_err(|err| gen_unexpected_error(stage, err))?;
452             }
453         }
454 
455         if space_offset != 0 {
456             for input in &shader_resources.subpass_inputs {
457                 let set = ast
458                     .get_decoration(input.id, spirv::Decoration::DescriptorSet)
459                     .map_err(|err| gen_query_error(stage, err))?;
460                 ast.set_decoration(
461                     input.id,
462                     spirv::Decoration::DescriptorSet,
463                     space_offset + set,
464                 )
465                 .map_err(|err| gen_unexpected_error(stage, err))?;
466             }
467         }
468 
469         Ok(())
470     }
471 
translate_spirv( ast: &mut spirv::Ast<hlsl::Target>, shader_model: hlsl::ShaderModel, layout: &r::PipelineLayout, stage: ShaderStage, features: &hal::Features, entry_point: &str, ) -> Result<String, pso::CreationError>472     fn translate_spirv(
473         ast: &mut spirv::Ast<hlsl::Target>,
474         shader_model: hlsl::ShaderModel,
475         layout: &r::PipelineLayout,
476         stage: ShaderStage,
477         features: &hal::Features,
478         entry_point: &str,
479     ) -> Result<String, pso::CreationError> {
480         let mut compile_options = hlsl::CompilerOptions::default();
481         compile_options.shader_model = shader_model;
482         compile_options.vertex.invert_y = !features.contains(hal::Features::NDC_Y_UP);
483         compile_options.force_zero_initialized_variables = true;
484         compile_options.nonwritable_uav_texture_as_srv = true;
485         // these are technically incorrect, but better than panicking
486         compile_options.point_size_compat = true;
487         compile_options.point_coord_compat = true;
488         compile_options.entry_point = Some((entry_point.to_string(), conv::map_stage(stage)));
489 
490         let stage_flag = stage.to_flag();
491         let root_constant_layout = layout
492             .shared
493             .constants
494             .iter()
495             .filter_map(|constant| {
496                 if constant.stages.contains(stage_flag) {
497                     Some(hlsl::RootConstant {
498                         start: constant.range.start * 4,
499                         end: constant.range.end * 4,
500                         binding: constant.range.start,
501                         space: 0,
502                     })
503                 } else {
504                     None
505                 }
506             })
507             .collect();
508         ast.set_compiler_options(&compile_options)
509             .map_err(|err| gen_unexpected_error(stage, err))?;
510         ast.set_root_constant_layout(root_constant_layout)
511             .map_err(|err| gen_unexpected_error(stage, err))?;
512         ast.compile().map_err(|err| {
513             let msg = match err {
514                 SpirvErrorCode::CompilationError(msg) => msg,
515                 SpirvErrorCode::Unhandled => "Unknown compile error".into(),
516             };
517             let error = format!("SPIR-V compile failed: {}", msg);
518             pso::CreationError::ShaderCreationError(stage.to_flag(), error)
519         })
520     }
521 
522     // Extract entry point from shader module on pipeline creation.
523     // Returns compiled shader blob and bool to indicate if the shader should be
524     // destroyed after pipeline creation
extract_entry_point( stage: ShaderStage, source: &pso::EntryPoint<B>, layout: &r::PipelineLayout, features: &hal::Features, ) -> Result<(native::Blob, bool), pso::CreationError>525     fn extract_entry_point(
526         stage: ShaderStage,
527         source: &pso::EntryPoint<B>,
528         layout: &r::PipelineLayout,
529         features: &hal::Features,
530     ) -> Result<(native::Blob, bool), pso::CreationError> {
531         match *source.module {
532             r::ShaderModule::Compiled(ref shaders) => {
533                 // TODO: do we need to check for specialization constants?
534                 // Use precompiled shader, ignore specialization or layout.
535                 shaders
536                     .get(source.entry)
537                     .map(|src| (*src, false))
538                     .ok_or(pso::CreationError::MissingEntryPoint(source.entry.into()))
539             }
540             r::ShaderModule::Spirv(ref raw_data) => {
541                 let mut ast = Self::parse_spirv(stage, raw_data)?;
542                 spirv_cross_specialize_ast(&mut ast, &source.specialization)
543                     .map_err(pso::CreationError::InvalidSpecialization)?;
544                 Self::patch_spirv_resources(stage, &mut ast, layout)?;
545 
546                 let execution_model = conv::map_stage(stage);
547                 let shader_model = hlsl::ShaderModel::V5_1;
548                 let shader_code = Self::translate_spirv(
549                     &mut ast,
550                     shader_model,
551                     layout,
552                     stage,
553                     features,
554                     source.entry,
555                 )?;
556                 debug!("SPIRV-Cross generated shader:\n{}", shader_code);
557 
558                 let real_name = ast
559                     .get_cleansed_entry_point_name(source.entry, execution_model)
560                     .map_err(|err| gen_query_error(stage, err))?;
561 
562                 let shader = compile_shader(
563                     stage,
564                     shader_model,
565                     features,
566                     &real_name,
567                     shader_code.as_bytes(),
568                 )?;
569                 Ok((shader, true))
570             }
571         }
572     }
573 
create_command_signature( device: native::Device, ty: CommandSignature, ) -> native::CommandSignature574     pub(crate) fn create_command_signature(
575         device: native::Device,
576         ty: CommandSignature,
577     ) -> native::CommandSignature {
578         let (arg, stride) = match ty {
579             CommandSignature::Draw => (native::IndirectArgument::draw(), 16),
580             CommandSignature::DrawIndexed => (native::IndirectArgument::draw_indexed(), 20),
581             CommandSignature::Dispatch => (native::IndirectArgument::dispatch(), 12),
582         };
583 
584         let (signature, hr) =
585             device.create_command_signature(native::RootSignature::null(), &[arg], stride, 0);
586 
587         if !winerror::SUCCEEDED(hr) {
588             error!("error on command signature creation: {:x}", hr);
589         }
590         signature
591     }
592 
create_descriptor_heap_impl( device: native::Device, heap_type: native::DescriptorHeapType, shader_visible: bool, capacity: usize, ) -> r::DescriptorHeap593     pub(crate) fn create_descriptor_heap_impl(
594         device: native::Device,
595         heap_type: native::DescriptorHeapType,
596         shader_visible: bool,
597         capacity: usize,
598     ) -> r::DescriptorHeap {
599         assert_ne!(capacity, 0);
600 
601         let (heap, _hr) = device.create_descriptor_heap(
602             capacity as _,
603             heap_type,
604             if shader_visible {
605                 native::DescriptorHeapFlags::SHADER_VISIBLE
606             } else {
607                 native::DescriptorHeapFlags::empty()
608             },
609             0,
610         );
611 
612         let descriptor_size = device.get_descriptor_increment_size(heap_type);
613         let cpu_handle = heap.start_cpu_descriptor();
614         let gpu_handle = heap.start_gpu_descriptor();
615 
616         r::DescriptorHeap {
617             raw: heap,
618             handle_size: descriptor_size as _,
619             total_handles: capacity as _,
620             start: r::DualHandle {
621                 cpu: cpu_handle,
622                 gpu: gpu_handle,
623                 size: 0,
624             },
625         }
626     }
627 
view_image_as_render_target_impl( device: native::Device, handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE, info: &ViewInfo, ) -> Result<(), image::ViewCreationError>628     pub(crate) fn view_image_as_render_target_impl(
629         device: native::Device,
630         handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
631         info: &ViewInfo,
632     ) -> Result<(), image::ViewCreationError> {
633         #![allow(non_snake_case)]
634 
635         let mut desc = d3d12::D3D12_RENDER_TARGET_VIEW_DESC {
636             Format: info.format,
637             ViewDimension: 0,
638             u: unsafe { mem::zeroed() },
639         };
640 
641         let MipSlice = info.levels.start as _;
642         let FirstArraySlice = info.layers.start as _;
643         let ArraySize = (info.layers.end - info.layers.start) as _;
644         let is_msaa = info.kind.num_samples() > 1;
645         if info.levels.start + 1 != info.levels.end {
646             return Err(image::ViewCreationError::Level(info.levels.start));
647         }
648         if info.layers.end > info.kind.num_layers() {
649             return Err(image::ViewCreationError::Layer(
650                 image::LayerError::OutOfBounds,
651             ));
652         }
653 
654         match info.view_kind {
655             image::ViewKind::D1 => {
656                 assert_eq!(info.layers, 0..1);
657                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE1D;
658                 *unsafe { desc.u.Texture1D_mut() } = d3d12::D3D12_TEX1D_RTV { MipSlice }
659             }
660             image::ViewKind::D1Array => {
661                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
662                 *unsafe { desc.u.Texture1DArray_mut() } = d3d12::D3D12_TEX1D_ARRAY_RTV {
663                     MipSlice,
664                     FirstArraySlice,
665                     ArraySize,
666                 }
667             }
668             image::ViewKind::D2 if is_msaa => {
669                 assert_eq!(info.layers, 0..1);
670                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE2DMS;
671                 *unsafe { desc.u.Texture2DMS_mut() } = d3d12::D3D12_TEX2DMS_RTV {
672                     UnusedField_NothingToDefine: 0,
673                 }
674             }
675             image::ViewKind::D2 => {
676                 assert_eq!(info.layers, 0..1);
677                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE2D;
678                 *unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_RTV {
679                     MipSlice,
680                     PlaneSlice: 0, //TODO
681                 }
682             }
683             image::ViewKind::D2Array if is_msaa => {
684                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
685                 *unsafe { desc.u.Texture2DMSArray_mut() } = d3d12::D3D12_TEX2DMS_ARRAY_RTV {
686                     FirstArraySlice,
687                     ArraySize,
688                 }
689             }
690             image::ViewKind::D2Array => {
691                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
692                 *unsafe { desc.u.Texture2DArray_mut() } = d3d12::D3D12_TEX2D_ARRAY_RTV {
693                     MipSlice,
694                     FirstArraySlice,
695                     ArraySize,
696                     PlaneSlice: 0, //TODO
697                 }
698             }
699             image::ViewKind::D3 => {
700                 assert_eq!(info.layers, 0..1);
701                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE3D;
702                 *unsafe { desc.u.Texture3D_mut() } = d3d12::D3D12_TEX3D_RTV {
703                     MipSlice,
704                     FirstWSlice: 0,
705                     WSize: info.kind.extent().depth as _,
706                 }
707             }
708             image::ViewKind::Cube | image::ViewKind::CubeArray => {
709                 desc.ViewDimension = d3d12::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
710                 //TODO: double-check if any *6 are needed
711                 *unsafe { desc.u.Texture2DArray_mut() } = d3d12::D3D12_TEX2D_ARRAY_RTV {
712                     MipSlice,
713                     FirstArraySlice,
714                     ArraySize,
715                     PlaneSlice: 0, //TODO
716                 }
717             }
718         };
719 
720         unsafe {
721             device.CreateRenderTargetView(info.resource.as_mut_ptr(), &desc, handle);
722         }
723 
724         Ok(())
725     }
726 
view_image_as_render_target( &self, info: &ViewInfo, ) -> Result<descriptors_cpu::Handle, image::ViewCreationError>727     pub(crate) fn view_image_as_render_target(
728         &self,
729         info: &ViewInfo,
730     ) -> Result<descriptors_cpu::Handle, image::ViewCreationError> {
731         let handle = self.rtv_pool.lock().alloc_handle();
732         Self::view_image_as_render_target_impl(self.raw, handle.raw, info).map(|_| handle)
733     }
734 
view_image_as_depth_stencil_impl( device: native::Device, handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE, info: &ViewInfo, ) -> Result<(), image::ViewCreationError>735     pub(crate) fn view_image_as_depth_stencil_impl(
736         device: native::Device,
737         handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
738         info: &ViewInfo,
739     ) -> Result<(), image::ViewCreationError> {
740         #![allow(non_snake_case)]
741 
742         let mut desc = d3d12::D3D12_DEPTH_STENCIL_VIEW_DESC {
743             Format: info.format,
744             ViewDimension: 0,
745             Flags: 0,
746             u: unsafe { mem::zeroed() },
747         };
748 
749         let MipSlice = info.levels.start as _;
750         let FirstArraySlice = info.layers.start as _;
751         let ArraySize = (info.layers.end - info.layers.start) as _;
752         let is_msaa = info.kind.num_samples() > 1;
753         if info.levels.start + 1 != info.levels.end {
754             return Err(image::ViewCreationError::Level(info.levels.start));
755         }
756         if info.layers.end > info.kind.num_layers() {
757             return Err(image::ViewCreationError::Layer(
758                 image::LayerError::OutOfBounds,
759             ));
760         }
761 
762         match info.view_kind {
763             image::ViewKind::D1 => {
764                 assert_eq!(info.layers, 0..1);
765                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE1D;
766                 *unsafe { desc.u.Texture1D_mut() } = d3d12::D3D12_TEX1D_DSV { MipSlice }
767             }
768             image::ViewKind::D1Array => {
769                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
770                 *unsafe { desc.u.Texture1DArray_mut() } = d3d12::D3D12_TEX1D_ARRAY_DSV {
771                     MipSlice,
772                     FirstArraySlice,
773                     ArraySize,
774                 }
775             }
776             image::ViewKind::D2 if is_msaa => {
777                 assert_eq!(info.layers, 0..1);
778                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE2DMS;
779                 *unsafe { desc.u.Texture2DMS_mut() } = d3d12::D3D12_TEX2DMS_DSV {
780                     UnusedField_NothingToDefine: 0,
781                 }
782             }
783             image::ViewKind::D2 => {
784                 assert_eq!(info.layers, 0..1);
785                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE2D;
786                 *unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_DSV { MipSlice }
787             }
788             image::ViewKind::D2Array if is_msaa => {
789                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
790                 *unsafe { desc.u.Texture2DMSArray_mut() } = d3d12::D3D12_TEX2DMS_ARRAY_DSV {
791                     FirstArraySlice,
792                     ArraySize,
793                 }
794             }
795             image::ViewKind::D2Array => {
796                 desc.ViewDimension = d3d12::D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
797                 *unsafe { desc.u.Texture2DArray_mut() } = d3d12::D3D12_TEX2D_ARRAY_DSV {
798                     MipSlice,
799                     FirstArraySlice,
800                     ArraySize,
801                 }
802             }
803             image::ViewKind::D3 | image::ViewKind::Cube | image::ViewKind::CubeArray => {
804                 warn!(
805                     "3D and cube views are not supported for the image, kind: {:?}",
806                     info.kind
807                 );
808                 return Err(image::ViewCreationError::BadKind(info.view_kind));
809             }
810         };
811 
812         unsafe {
813             device.CreateDepthStencilView(info.resource.as_mut_ptr(), &desc, handle);
814         }
815 
816         Ok(())
817     }
818 
view_image_as_depth_stencil( &self, info: &ViewInfo, ) -> Result<descriptors_cpu::Handle, image::ViewCreationError>819     pub(crate) fn view_image_as_depth_stencil(
820         &self,
821         info: &ViewInfo,
822     ) -> Result<descriptors_cpu::Handle, image::ViewCreationError> {
823         let handle = self.dsv_pool.lock().alloc_handle();
824         Self::view_image_as_depth_stencil_impl(self.raw, handle.raw, info).map(|_| handle)
825     }
826 
build_image_as_shader_resource_desc( info: &ViewInfo, ) -> Result<d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC, image::ViewCreationError>827     pub(crate) fn build_image_as_shader_resource_desc(
828         info: &ViewInfo,
829     ) -> Result<d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC, image::ViewCreationError> {
830         #![allow(non_snake_case)]
831 
832         let mut desc = d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC {
833             Format: info.format,
834             ViewDimension: 0,
835             Shader4ComponentMapping: info.component_mapping,
836             u: unsafe { mem::zeroed() },
837         };
838 
839         let MostDetailedMip = info.levels.start as _;
840         let MipLevels = (info.levels.end - info.levels.start) as _;
841         let FirstArraySlice = info.layers.start as _;
842         let ArraySize = (info.layers.end - info.layers.start) as _;
843 
844         if info.layers.end > info.kind.num_layers() {
845             return Err(image::ViewCreationError::Layer(
846                 image::LayerError::OutOfBounds,
847             ));
848         }
849         let is_msaa = info.kind.num_samples() > 1;
850         let is_cube = info.caps.contains(image::ViewCapabilities::KIND_CUBE);
851 
852         match info.view_kind {
853             image::ViewKind::D1 => {
854                 assert_eq!(info.layers, 0..1);
855                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE1D;
856                 *unsafe { desc.u.Texture1D_mut() } = d3d12::D3D12_TEX1D_SRV {
857                     MostDetailedMip,
858                     MipLevels,
859                     ResourceMinLODClamp: 0.0,
860                 }
861             }
862             image::ViewKind::D1Array => {
863                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
864                 *unsafe { desc.u.Texture1DArray_mut() } = d3d12::D3D12_TEX1D_ARRAY_SRV {
865                     MostDetailedMip,
866                     MipLevels,
867                     FirstArraySlice,
868                     ArraySize,
869                     ResourceMinLODClamp: 0.0,
870                 }
871             }
872             image::ViewKind::D2 if is_msaa => {
873                 assert_eq!(info.layers, 0..1);
874                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE2DMS;
875                 *unsafe { desc.u.Texture2DMS_mut() } = d3d12::D3D12_TEX2DMS_SRV {
876                     UnusedField_NothingToDefine: 0,
877                 }
878             }
879             image::ViewKind::D2 => {
880                 assert_eq!(info.layers, 0..1);
881                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE2D;
882                 *unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_SRV {
883                     MostDetailedMip,
884                     MipLevels,
885                     PlaneSlice: 0, //TODO
886                     ResourceMinLODClamp: 0.0,
887                 }
888             }
889             image::ViewKind::D2Array if is_msaa => {
890                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
891                 *unsafe { desc.u.Texture2DMSArray_mut() } = d3d12::D3D12_TEX2DMS_ARRAY_SRV {
892                     FirstArraySlice,
893                     ArraySize,
894                 }
895             }
896             image::ViewKind::D2Array => {
897                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
898                 *unsafe { desc.u.Texture2DArray_mut() } = d3d12::D3D12_TEX2D_ARRAY_SRV {
899                     MostDetailedMip,
900                     MipLevels,
901                     FirstArraySlice,
902                     ArraySize,
903                     PlaneSlice: 0, //TODO
904                     ResourceMinLODClamp: 0.0,
905                 }
906             }
907             image::ViewKind::D3 => {
908                 assert_eq!(info.layers, 0..1);
909                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURE3D;
910                 *unsafe { desc.u.Texture3D_mut() } = d3d12::D3D12_TEX3D_SRV {
911                     MostDetailedMip,
912                     MipLevels,
913                     ResourceMinLODClamp: 0.0,
914                 }
915             }
916             image::ViewKind::Cube if is_cube => {
917                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURECUBE;
918                 *unsafe { desc.u.TextureCube_mut() } = d3d12::D3D12_TEXCUBE_SRV {
919                     MostDetailedMip,
920                     MipLevels,
921                     ResourceMinLODClamp: 0.0,
922                 }
923             }
924             image::ViewKind::CubeArray if is_cube => {
925                 assert_eq!(0, ArraySize % 6);
926                 desc.ViewDimension = d3d12::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
927                 *unsafe { desc.u.TextureCubeArray_mut() } = d3d12::D3D12_TEXCUBE_ARRAY_SRV {
928                     MostDetailedMip,
929                     MipLevels,
930                     First2DArrayFace: FirstArraySlice,
931                     NumCubes: ArraySize / 6,
932                     ResourceMinLODClamp: 0.0,
933                 }
934             }
935             image::ViewKind::Cube | image::ViewKind::CubeArray => {
936                 warn!(
937                     "Cube views are not supported for the image, kind: {:?}",
938                     info.kind
939                 );
940                 return Err(image::ViewCreationError::BadKind(info.view_kind));
941             }
942         }
943 
944         Ok(desc)
945     }
946 
view_image_as_shader_resource( &self, info: &ViewInfo, ) -> Result<descriptors_cpu::Handle, image::ViewCreationError>947     fn view_image_as_shader_resource(
948         &self,
949         info: &ViewInfo,
950     ) -> Result<descriptors_cpu::Handle, image::ViewCreationError> {
951         let desc = Self::build_image_as_shader_resource_desc(&info)?;
952         let handle = self.srv_uav_pool.lock().alloc_handle();
953         unsafe {
954             self.raw
955                 .CreateShaderResourceView(info.resource.as_mut_ptr(), &desc, handle.raw);
956         }
957 
958         Ok(handle)
959     }
960 
view_image_as_storage( &self, info: &ViewInfo, ) -> Result<descriptors_cpu::Handle, image::ViewCreationError>961     fn view_image_as_storage(
962         &self,
963         info: &ViewInfo,
964     ) -> Result<descriptors_cpu::Handle, image::ViewCreationError> {
965         #![allow(non_snake_case)]
966 
967         // Cannot make a storage image over multiple mips
968         if info.levels.start + 1 != info.levels.end {
969             return Err(image::ViewCreationError::Unsupported);
970         }
971 
972         let mut desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
973             Format: info.format,
974             ViewDimension: 0,
975             u: unsafe { mem::zeroed() },
976         };
977 
978         let MipSlice = info.levels.start as _;
979         let FirstArraySlice = info.layers.start as _;
980         let ArraySize = (info.layers.end - info.layers.start) as _;
981 
982         if info.layers.end > info.kind.num_layers() {
983             return Err(image::ViewCreationError::Layer(
984                 image::LayerError::OutOfBounds,
985             ));
986         }
987         if info.kind.num_samples() > 1 {
988             error!("MSAA images can't be viewed as UAV");
989             return Err(image::ViewCreationError::Unsupported);
990         }
991 
992         match info.view_kind {
993             image::ViewKind::D1 => {
994                 assert_eq!(info.layers, 0..1);
995                 desc.ViewDimension = d3d12::D3D12_UAV_DIMENSION_TEXTURE1D;
996                 *unsafe { desc.u.Texture1D_mut() } = d3d12::D3D12_TEX1D_UAV { MipSlice }
997             }
998             image::ViewKind::D1Array => {
999                 desc.ViewDimension = d3d12::D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
1000                 *unsafe { desc.u.Texture1DArray_mut() } = d3d12::D3D12_TEX1D_ARRAY_UAV {
1001                     MipSlice,
1002                     FirstArraySlice,
1003                     ArraySize,
1004                 }
1005             }
1006             image::ViewKind::D2 => {
1007                 assert_eq!(info.layers, 0..1);
1008                 desc.ViewDimension = d3d12::D3D12_UAV_DIMENSION_TEXTURE2D;
1009                 *unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_UAV {
1010                     MipSlice,
1011                     PlaneSlice: 0, //TODO
1012                 }
1013             }
1014             image::ViewKind::D2Array => {
1015                 desc.ViewDimension = d3d12::D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1016                 *unsafe { desc.u.Texture2DArray_mut() } = d3d12::D3D12_TEX2D_ARRAY_UAV {
1017                     MipSlice,
1018                     FirstArraySlice,
1019                     ArraySize,
1020                     PlaneSlice: 0, //TODO
1021                 }
1022             }
1023             image::ViewKind::D3 => {
1024                 assert_eq!(info.layers, 0..1);
1025                 desc.ViewDimension = d3d12::D3D12_UAV_DIMENSION_TEXTURE3D;
1026                 *unsafe { desc.u.Texture3D_mut() } = d3d12::D3D12_TEX3D_UAV {
1027                     MipSlice,
1028                     FirstWSlice: 0,
1029                     WSize: info.kind.extent().depth as _,
1030                 }
1031             }
1032             image::ViewKind::Cube | image::ViewKind::CubeArray => {
1033                 error!("Cubic images can't be viewed as UAV");
1034                 return Err(image::ViewCreationError::Unsupported);
1035             }
1036         }
1037 
1038         let handle = self.srv_uav_pool.lock().alloc_handle();
1039         unsafe {
1040             self.raw.CreateUnorderedAccessView(
1041                 info.resource.as_mut_ptr(),
1042                 ptr::null_mut(),
1043                 &desc,
1044                 handle.raw,
1045             );
1046         }
1047 
1048         Ok(handle)
1049     }
1050 
create_raw_fence(&self, signalled: bool) -> native::Fence1051     pub(crate) fn create_raw_fence(&self, signalled: bool) -> native::Fence {
1052         let mut handle = native::Fence::null();
1053         assert_eq!(winerror::S_OK, unsafe {
1054             self.raw.CreateFence(
1055                 if signalled { 1 } else { 0 },
1056                 d3d12::D3D12_FENCE_FLAG_NONE,
1057                 &d3d12::ID3D12Fence::uuidof(),
1058                 handle.mut_void(),
1059             )
1060         });
1061         handle
1062     }
1063 
create_swapchain_impl( &self, config: &w::SwapchainConfig, window_handle: windef::HWND, factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>, ) -> Result< ( native::WeakPtr<dxgi1_4::IDXGISwapChain3>, dxgiformat::DXGI_FORMAT, ), w::SwapchainError, >1064     pub(crate) fn create_swapchain_impl(
1065         &self,
1066         config: &w::SwapchainConfig,
1067         window_handle: windef::HWND,
1068         factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
1069     ) -> Result<
1070         (
1071             native::WeakPtr<dxgi1_4::IDXGISwapChain3>,
1072             dxgiformat::DXGI_FORMAT,
1073         ),
1074         w::SwapchainError,
1075     > {
1076         let mut swap_chain1 = native::WeakPtr::<dxgi1_2::IDXGISwapChain1>::null();
1077 
1078         //TODO: proper error type?
1079         let non_srgb_format = conv::map_format_nosrgb(config.format).unwrap();
1080 
1081         let mut flags = dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
1082         if config.present_mode.contains(w::PresentMode::IMMEDIATE) {
1083             flags |= dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
1084         }
1085 
1086         // TODO: double-check values
1087         let desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
1088             AlphaMode: dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
1089             BufferCount: config.image_count,
1090             Width: config.extent.width,
1091             Height: config.extent.height,
1092             Format: non_srgb_format,
1093             Flags: flags,
1094             BufferUsage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
1095             SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
1096                 Count: 1,
1097                 Quality: 0,
1098             },
1099             Scaling: dxgi1_2::DXGI_SCALING_STRETCH,
1100             Stereo: FALSE,
1101             SwapEffect: dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
1102         };
1103 
1104         unsafe {
1105             let hr = factory.CreateSwapChainForHwnd(
1106                 self.present_queue.as_mut_ptr() as *mut _,
1107                 window_handle,
1108                 &desc,
1109                 ptr::null(),
1110                 ptr::null_mut(),
1111                 swap_chain1.mut_void() as *mut *mut _,
1112             );
1113 
1114             if !winerror::SUCCEEDED(hr) {
1115                 error!("error on swapchain creation 0x{:x}", hr);
1116                 return Err(w::SwapchainError::Unknown);
1117             }
1118 
1119             let (swap_chain3, hr3) = swap_chain1.cast::<dxgi1_4::IDXGISwapChain3>();
1120             if !winerror::SUCCEEDED(hr3) {
1121                 error!("error on swapchain cast 0x{:x}", hr3);
1122             }
1123 
1124             swap_chain1.destroy();
1125             Ok((swap_chain3, non_srgb_format))
1126         }
1127     }
1128 
wrap_swapchain( &self, inner: native::WeakPtr<dxgi1_4::IDXGISwapChain3>, config: &w::SwapchainConfig, ) -> Swapchain1129     pub(crate) fn wrap_swapchain(
1130         &self,
1131         inner: native::WeakPtr<dxgi1_4::IDXGISwapChain3>,
1132         config: &w::SwapchainConfig,
1133     ) -> Swapchain {
1134         let waitable = unsafe {
1135             inner.SetMaximumFrameLatency(config.image_count);
1136             inner.GetFrameLatencyWaitableObject()
1137         };
1138 
1139         let rtv_desc = d3d12::D3D12_RENDER_TARGET_VIEW_DESC {
1140             Format: conv::map_format(config.format).unwrap(),
1141             ViewDimension: d3d12::D3D12_RTV_DIMENSION_TEXTURE2D,
1142             ..unsafe { mem::zeroed() }
1143         };
1144         let rtv_heap = Device::create_descriptor_heap_impl(
1145             self.raw,
1146             native::DescriptorHeapType::Rtv,
1147             false,
1148             config.image_count as _,
1149         );
1150 
1151         let mut resources = vec![native::Resource::null(); config.image_count as usize];
1152         for (i, res) in resources.iter_mut().enumerate() {
1153             let rtv_handle = rtv_heap.at(i as _, 0).cpu;
1154             unsafe {
1155                 inner.GetBuffer(i as _, &d3d12::ID3D12Resource::uuidof(), res.mut_void());
1156                 self.raw
1157                     .CreateRenderTargetView(res.as_mut_ptr(), &rtv_desc, rtv_handle);
1158             }
1159         }
1160 
1161         Swapchain {
1162             inner,
1163             rtv_heap,
1164             resources,
1165             waitable,
1166             usage: config.image_usage,
1167             acquired_count: 0,
1168         }
1169     }
1170 
bind_image_resource( &self, resource: native::WeakPtr<d3d12::ID3D12Resource>, image: &mut r::Image, place: r::Place, )1171     pub(crate) fn bind_image_resource(
1172         &self,
1173         resource: native::WeakPtr<d3d12::ID3D12Resource>,
1174         image: &mut r::Image,
1175         place: r::Place,
1176     ) {
1177         let image_unbound = image.expect_unbound();
1178         let num_layers = image_unbound.kind.num_layers();
1179 
1180         //TODO: the clear_Xv is incomplete. We should support clearing images created without XXX_ATTACHMENT usage.
1181         // for this, we need to check the format and force the `RENDER_TARGET` flag behind the user's back
1182         // if the format supports being rendered into, allowing us to create clear_Xv
1183         let info = ViewInfo {
1184             resource,
1185             kind: image_unbound.kind,
1186             caps: image::ViewCapabilities::empty(),
1187             view_kind: match image_unbound.kind {
1188                 image::Kind::D1(..) => image::ViewKind::D1Array,
1189                 image::Kind::D2(..) => image::ViewKind::D2Array,
1190                 image::Kind::D3(..) => image::ViewKind::D3,
1191             },
1192             format: image_unbound.desc.Format,
1193             component_mapping: IDENTITY_MAPPING,
1194             levels: 0..1,
1195             layers: 0..0,
1196         };
1197         let format_properties = self
1198             .format_properties
1199             .resolve(image_unbound.format as usize)
1200             .properties;
1201         let props = match image_unbound.tiling {
1202             image::Tiling::Optimal => format_properties.optimal_tiling,
1203             image::Tiling::Linear => format_properties.linear_tiling,
1204         };
1205         let can_clear_color = image_unbound
1206             .usage
1207             .intersects(image::Usage::TRANSFER_DST | image::Usage::COLOR_ATTACHMENT)
1208             && props.contains(format::ImageFeature::COLOR_ATTACHMENT);
1209         let can_clear_depth = image_unbound
1210             .usage
1211             .intersects(image::Usage::TRANSFER_DST | image::Usage::DEPTH_STENCIL_ATTACHMENT)
1212             && props.contains(format::ImageFeature::DEPTH_STENCIL_ATTACHMENT);
1213         let aspects = image_unbound.format.surface_desc().aspects;
1214 
1215         *image = r::Image::Bound(r::ImageBound {
1216             resource,
1217             place,
1218             surface_type: image_unbound.format.base_format().0,
1219             kind: image_unbound.kind,
1220             mip_levels: image_unbound.mip_levels,
1221             default_view_format: image_unbound.view_format,
1222             view_caps: image_unbound.view_caps,
1223             descriptor: image_unbound.desc,
1224             clear_cv: if aspects.contains(Aspects::COLOR) && can_clear_color {
1225                 let format = image_unbound.view_format.unwrap();
1226                 (0..num_layers)
1227                     .map(|layer| {
1228                         self.view_image_as_render_target(&ViewInfo {
1229                             format,
1230                             layers: layer..layer + 1,
1231                             ..info.clone()
1232                         })
1233                         .unwrap()
1234                     })
1235                     .collect()
1236             } else {
1237                 Vec::new()
1238             },
1239             clear_dv: if aspects.contains(Aspects::DEPTH) && can_clear_depth {
1240                 let format = image_unbound.dsv_format.unwrap();
1241                 (0..num_layers)
1242                     .map(|layer| {
1243                         self.view_image_as_depth_stencil(&ViewInfo {
1244                             format,
1245                             layers: layer..layer + 1,
1246                             ..info.clone()
1247                         })
1248                         .unwrap()
1249                     })
1250                     .collect()
1251             } else {
1252                 Vec::new()
1253             },
1254             clear_sv: if aspects.contains(Aspects::STENCIL) && can_clear_depth {
1255                 let format = image_unbound.dsv_format.unwrap();
1256                 (0..num_layers)
1257                     .map(|layer| {
1258                         self.view_image_as_depth_stencil(&ViewInfo {
1259                             format,
1260                             layers: layer..layer + 1,
1261                             ..info.clone()
1262                         })
1263                         .unwrap()
1264                     })
1265                     .collect()
1266             } else {
1267                 Vec::new()
1268             },
1269             requirements: image_unbound.requirements,
1270         });
1271     }
1272 }
1273 
1274 impl d::Device<B> for Device {
allocate_memory( &self, mem_type: hal::MemoryTypeId, size: u64, ) -> Result<r::Memory, d::AllocationError>1275     unsafe fn allocate_memory(
1276         &self,
1277         mem_type: hal::MemoryTypeId,
1278         size: u64,
1279     ) -> Result<r::Memory, d::AllocationError> {
1280         let mem_type = mem_type.0;
1281         let mem_base_id = mem_type % NUM_HEAP_PROPERTIES;
1282         let heap_property = &self.heap_properties[mem_base_id];
1283 
1284         let properties = d3d12::D3D12_HEAP_PROPERTIES {
1285             Type: d3d12::D3D12_HEAP_TYPE_CUSTOM,
1286             CPUPageProperty: heap_property.page_property,
1287             MemoryPoolPreference: heap_property.memory_pool,
1288             CreationNodeMask: 0,
1289             VisibleNodeMask: 0,
1290         };
1291 
1292         // Exposed memory types are grouped according to their capabilities.
1293         // See `MemoryGroup` for more details.
1294         let mem_group = mem_type / NUM_HEAP_PROPERTIES;
1295 
1296         let desc = d3d12::D3D12_HEAP_DESC {
1297             SizeInBytes: size,
1298             Properties: properties,
1299             Alignment: d3d12::D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT as _, // TODO: not always..?
1300             Flags: match mem_group {
1301                 0 => d3d12::D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES,
1302                 1 => d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
1303                 2 => d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES,
1304                 3 => d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES,
1305                 _ => unreachable!(),
1306             },
1307         };
1308 
1309         let mut heap = native::Heap::null();
1310         let hr = self
1311             .raw
1312             .clone()
1313             .CreateHeap(&desc, &d3d12::ID3D12Heap::uuidof(), heap.mut_void());
1314         if hr != winerror::S_OK {
1315             if hr != winerror::E_OUTOFMEMORY {
1316                 error!("Error in CreateHeap: 0x{:X}", hr);
1317             }
1318             return Err(d::OutOfMemory::Device.into());
1319         }
1320 
1321         // The first memory heap of each group corresponds to the default heap, which is can never
1322         // be mapped.
1323         // Devices supporting heap tier 1 can only created buffers on mem group 1 (ALLOW_ONLY_BUFFERS).
1324         // Devices supporting heap tier 2 always expose only mem group 0 and don't have any further restrictions.
1325         let is_mapable = mem_base_id != 0
1326             && (mem_group == MemoryGroup::Universal as _
1327                 || mem_group == MemoryGroup::BufferOnly as _);
1328 
1329         // Create a buffer resource covering the whole memory slice to be able to map the whole memory.
1330         let resource = if is_mapable {
1331             let mut resource = native::Resource::null();
1332             let desc = d3d12::D3D12_RESOURCE_DESC {
1333                 Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER,
1334                 Alignment: 0,
1335                 Width: size,
1336                 Height: 1,
1337                 DepthOrArraySize: 1,
1338                 MipLevels: 1,
1339                 Format: dxgiformat::DXGI_FORMAT_UNKNOWN,
1340                 SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
1341                     Count: 1,
1342                     Quality: 0,
1343                 },
1344                 Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1345                 Flags: d3d12::D3D12_RESOURCE_FLAG_NONE,
1346             };
1347 
1348             assert_eq!(
1349                 winerror::S_OK,
1350                 self.raw.clone().CreatePlacedResource(
1351                     heap.as_mut_ptr(),
1352                     0,
1353                     &desc,
1354                     d3d12::D3D12_RESOURCE_STATE_COMMON,
1355                     ptr::null(),
1356                     &d3d12::ID3D12Resource::uuidof(),
1357                     resource.mut_void(),
1358                 )
1359             );
1360 
1361             Some(resource)
1362         } else {
1363             None
1364         };
1365 
1366         Ok(r::Memory {
1367             heap,
1368             type_id: mem_type,
1369             size,
1370             resource,
1371         })
1372     }
1373 
create_command_pool( &self, family: QueueFamilyId, create_flags: CommandPoolCreateFlags, ) -> Result<CommandPool, d::OutOfMemory>1374     unsafe fn create_command_pool(
1375         &self,
1376         family: QueueFamilyId,
1377         create_flags: CommandPoolCreateFlags,
1378     ) -> Result<CommandPool, d::OutOfMemory> {
1379         let list_type = QUEUE_FAMILIES[family.0].native_type();
1380         Ok(CommandPool::new(
1381             self.raw,
1382             list_type,
1383             &self.shared,
1384             create_flags,
1385         ))
1386     }
1387 
destroy_command_pool(&self, _pool: CommandPool)1388     unsafe fn destroy_command_pool(&self, _pool: CommandPool) {}
1389 
create_render_pass<'a, Ia, Is, Id>( &self, attachments: Ia, subpasses: Is, dependencies: Id, ) -> Result<r::RenderPass, d::OutOfMemory> where Ia: Iterator<Item = pass::Attachment>, Is: Iterator<Item = pass::SubpassDesc<'a>>, Id: Iterator<Item = pass::SubpassDependency>,1390     unsafe fn create_render_pass<'a, Ia, Is, Id>(
1391         &self,
1392         attachments: Ia,
1393         subpasses: Is,
1394         dependencies: Id,
1395     ) -> Result<r::RenderPass, d::OutOfMemory>
1396     where
1397         Ia: Iterator<Item = pass::Attachment>,
1398         Is: Iterator<Item = pass::SubpassDesc<'a>>,
1399         Id: Iterator<Item = pass::SubpassDependency>,
1400     {
1401         #[derive(Copy, Clone, Debug, PartialEq)]
1402         enum SubState {
1403             New(d3d12::D3D12_RESOURCE_STATES),
1404             // Color attachment which will be resolved at the end of the subpass
1405             Resolve(d3d12::D3D12_RESOURCE_STATES),
1406             Preserve,
1407             Undefined,
1408         }
1409         /// Temporary information about every sub-pass
1410         struct SubInfo<'a> {
1411             desc: pass::SubpassDesc<'a>,
1412             /// States before the render-pass (in self.start)
1413             /// and after the render-pass (in self.end).
1414             external_dependencies: Range<image::Access>,
1415             /// Counts the number of dependencies that need to be resolved
1416             /// before starting this subpass.
1417             unresolved_dependencies: u16,
1418         }
1419         struct AttachmentInfo {
1420             sub_states: Vec<SubState>,
1421             last_state: d3d12::D3D12_RESOURCE_STATES,
1422             barrier_start_index: usize,
1423         }
1424 
1425         let attachments = attachments.collect::<SmallVec<[_; 5]>>();
1426         let mut sub_infos = subpasses
1427             .map(|desc| SubInfo {
1428                 desc: desc.clone(),
1429                 external_dependencies: image::Access::empty()..image::Access::empty(),
1430                 unresolved_dependencies: 0,
1431             })
1432             .collect::<SmallVec<[_; 1]>>();
1433         let dependencies = dependencies.collect::<SmallVec<[_; 2]>>();
1434 
1435         let mut att_infos = (0..attachments.len())
1436             .map(|_| AttachmentInfo {
1437                 sub_states: vec![SubState::Undefined; sub_infos.len()],
1438                 last_state: d3d12::D3D12_RESOURCE_STATE_COMMON, // is to be overwritten
1439                 barrier_start_index: 0,
1440             })
1441             .collect::<SmallVec<[_; 5]>>();
1442 
1443         for dep in &dependencies {
1444             match dep.passes {
1445                 Range {
1446                     start: None,
1447                     end: None,
1448                 } => {
1449                     error!("Unexpected external-external dependency!");
1450                 }
1451                 Range {
1452                     start: None,
1453                     end: Some(sid),
1454                 } => {
1455                     sub_infos[sid as usize].external_dependencies.start |= dep.accesses.start;
1456                 }
1457                 Range {
1458                     start: Some(sid),
1459                     end: None,
1460                 } => {
1461                     sub_infos[sid as usize].external_dependencies.end |= dep.accesses.end;
1462                 }
1463                 Range {
1464                     start: Some(from_sid),
1465                     end: Some(sid),
1466                 } => {
1467                     //Note: self-dependencies are ignored
1468                     if from_sid != sid {
1469                         sub_infos[sid as usize].unresolved_dependencies += 1;
1470                     }
1471                 }
1472             }
1473         }
1474 
1475         // Fill out subpass known layouts
1476         for (sid, sub_info) in sub_infos.iter().enumerate() {
1477             let sub = &sub_info.desc;
1478             for (i, &(id, _layout)) in sub.colors.iter().enumerate() {
1479                 let target_state = d3d12::D3D12_RESOURCE_STATE_RENDER_TARGET;
1480                 let state = match sub.resolves.get(i) {
1481                     Some(_) => SubState::Resolve(target_state),
1482                     None => SubState::New(target_state),
1483                 };
1484                 let old = mem::replace(&mut att_infos[id].sub_states[sid], state);
1485                 debug_assert_eq!(SubState::Undefined, old);
1486             }
1487             for &(id, layout) in sub.depth_stencil {
1488                 let state = SubState::New(match layout {
1489                     image::Layout::DepthStencilAttachmentOptimal => {
1490                         d3d12::D3D12_RESOURCE_STATE_DEPTH_WRITE
1491                     }
1492                     image::Layout::DepthStencilReadOnlyOptimal => {
1493                         d3d12::D3D12_RESOURCE_STATE_DEPTH_READ
1494                     }
1495                     image::Layout::General => d3d12::D3D12_RESOURCE_STATE_DEPTH_WRITE,
1496                     _ => {
1497                         error!("Unexpected depth/stencil layout: {:?}", layout);
1498                         d3d12::D3D12_RESOURCE_STATE_COMMON
1499                     }
1500                 });
1501                 let old = mem::replace(&mut att_infos[id].sub_states[sid], state);
1502                 debug_assert_eq!(SubState::Undefined, old);
1503             }
1504             for &(id, _layout) in sub.inputs {
1505                 let state = SubState::New(d3d12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
1506                 let old = mem::replace(&mut att_infos[id].sub_states[sid], state);
1507                 debug_assert_eq!(SubState::Undefined, old);
1508             }
1509             for &(id, _layout) in sub.resolves {
1510                 let state = SubState::New(d3d12::D3D12_RESOURCE_STATE_RESOLVE_DEST);
1511                 let old = mem::replace(&mut att_infos[id].sub_states[sid], state);
1512                 debug_assert_eq!(SubState::Undefined, old);
1513             }
1514             for &id in sub.preserves {
1515                 let old = mem::replace(&mut att_infos[id].sub_states[sid], SubState::Preserve);
1516                 debug_assert_eq!(SubState::Undefined, old);
1517             }
1518         }
1519 
1520         let mut rp = r::RenderPass {
1521             attachments: attachments.iter().cloned().collect(),
1522             subpasses: Vec::new(),
1523             post_barriers: Vec::new(),
1524             raw_name: Vec::new(),
1525         };
1526 
1527         while let Some(sid) = sub_infos
1528             .iter()
1529             .position(|si| si.unresolved_dependencies == 0)
1530         {
1531             for dep in &dependencies {
1532                 if dep.passes.start != dep.passes.end
1533                     && dep.passes.start == Some(sid as pass::SubpassId)
1534                 {
1535                     if let Some(other) = dep.passes.end {
1536                         sub_infos[other as usize].unresolved_dependencies -= 1;
1537                     }
1538                 }
1539             }
1540 
1541             let si = &mut sub_infos[sid];
1542             si.unresolved_dependencies = !0; // mark as done
1543 
1544             // Subpass barriers
1545             let mut pre_barriers = Vec::new();
1546             let mut post_barriers = Vec::new();
1547             for (att_id, (ai, att)) in att_infos.iter_mut().zip(attachments.iter()).enumerate() {
1548                 // Attachment wasn't used before, figure out the initial state
1549                 if ai.barrier_start_index == 0 {
1550                     //Note: the external dependencies are provided for all attachments that are
1551                     // first used in this sub-pass, so they may contain more states than we expect
1552                     // for this particular attachment.
1553                     ai.last_state = conv::map_image_resource_state(
1554                         si.external_dependencies.start,
1555                         att.layouts.start,
1556                     );
1557                 }
1558                 // Barrier from previous subpass to current or following subpasses.
1559                 match ai.sub_states[sid] {
1560                     SubState::Preserve => {
1561                         ai.barrier_start_index = rp.subpasses.len() + 1;
1562                     }
1563                     SubState::New(state) if state != ai.last_state => {
1564                         let barrier = r::BarrierDesc::new(att_id, ai.last_state..state);
1565                         match rp.subpasses.get_mut(ai.barrier_start_index) {
1566                             Some(past_subpass) => {
1567                                 let split = barrier.split();
1568                                 past_subpass.pre_barriers.push(split.start);
1569                                 pre_barriers.push(split.end);
1570                             }
1571                             None => pre_barriers.push(barrier),
1572                         }
1573                         ai.last_state = state;
1574                         ai.barrier_start_index = rp.subpasses.len() + 1;
1575                     }
1576                     SubState::Resolve(state) => {
1577                         // 1. Standard pre barrier to update state from previous pass into desired substate.
1578                         if state != ai.last_state {
1579                             let barrier = r::BarrierDesc::new(att_id, ai.last_state..state);
1580                             match rp.subpasses.get_mut(ai.barrier_start_index) {
1581                                 Some(past_subpass) => {
1582                                     let split = barrier.split();
1583                                     past_subpass.pre_barriers.push(split.start);
1584                                     pre_barriers.push(split.end);
1585                                 }
1586                                 None => pre_barriers.push(barrier),
1587                             }
1588                         }
1589 
1590                         // 2. Post Barrier at the end of the subpass into RESOLVE_SOURCE.
1591                         let resolve_state = d3d12::D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
1592                         let barrier = r::BarrierDesc::new(att_id, state..resolve_state);
1593                         post_barriers.push(barrier);
1594 
1595                         ai.last_state = resolve_state;
1596                         ai.barrier_start_index = rp.subpasses.len() + 1;
1597                     }
1598                     SubState::Undefined | SubState::New(_) => {}
1599                 };
1600             }
1601 
1602             rp.subpasses.push(r::SubpassDesc {
1603                 color_attachments: si.desc.colors.iter().cloned().collect(),
1604                 depth_stencil_attachment: si.desc.depth_stencil.cloned(),
1605                 input_attachments: si.desc.inputs.iter().cloned().collect(),
1606                 resolve_attachments: si.desc.resolves.iter().cloned().collect(),
1607                 pre_barriers,
1608                 post_barriers,
1609             });
1610         }
1611         // if this fails, our graph has cycles
1612         assert_eq!(rp.subpasses.len(), sub_infos.len());
1613         assert!(sub_infos.iter().all(|si| si.unresolved_dependencies == !0));
1614 
1615         // take care of the post-pass transitions at the end of the renderpass.
1616         for (att_id, (ai, att)) in att_infos.iter().zip(attachments.iter()).enumerate() {
1617             let state_dst = if ai.barrier_start_index == 0 {
1618                 // attachment wasn't used in any sub-pass?
1619                 continue;
1620             } else {
1621                 let si = &sub_infos[ai.barrier_start_index - 1];
1622                 conv::map_image_resource_state(si.external_dependencies.end, att.layouts.end)
1623             };
1624             if state_dst == ai.last_state {
1625                 continue;
1626             }
1627             let barrier = r::BarrierDesc::new(att_id, ai.last_state..state_dst);
1628             match rp.subpasses.get_mut(ai.barrier_start_index) {
1629                 Some(past_subpass) => {
1630                     let split = barrier.split();
1631                     past_subpass.pre_barriers.push(split.start);
1632                     rp.post_barriers.push(split.end);
1633                 }
1634                 None => rp.post_barriers.push(barrier),
1635             }
1636         }
1637 
1638         Ok(rp)
1639     }
1640 
create_pipeline_layout<'a, Is, Ic>( &self, sets: Is, push_constant_ranges: Ic, ) -> Result<r::PipelineLayout, d::OutOfMemory> where Is: Iterator<Item = &'a r::DescriptorSetLayout>, Ic: Iterator<Item = (pso::ShaderStageFlags, Range<u32>)>,1641     unsafe fn create_pipeline_layout<'a, Is, Ic>(
1642         &self,
1643         sets: Is,
1644         push_constant_ranges: Ic,
1645     ) -> Result<r::PipelineLayout, d::OutOfMemory>
1646     where
1647         Is: Iterator<Item = &'a r::DescriptorSetLayout>,
1648         Ic: Iterator<Item = (pso::ShaderStageFlags, Range<u32>)>,
1649     {
1650         // Pipeline layouts are implemented as RootSignature for D3D12.
1651         //
1652         // Push Constants are implemented as root constants.
1653         //
1654         // Each descriptor set layout will be one table entry of the root signature.
1655         // We have the additional restriction that SRV/CBV/UAV and samplers need to be
1656         // separated, so each set layout will actually occupy up to 2 entries!
1657         // SRV/CBV/UAV tables are added to the signature first, then Sampler tables,
1658         // and finally dynamic uniform descriptors.
1659         //
1660         // Dynamic uniform buffers are implemented as root descriptors.
1661         // This allows to handle the dynamic offsets properly, which would not be feasible
1662         // with a combination of root constant and descriptor table.
1663         //
1664         // Root signature layout:
1665         //     Root Constants: Register: Offest/4, Space: 0
1666         //     ...
1667         // DescriptorTable0: Space: 1 (SrvCbvUav)
1668         // DescriptorTable0: Space: 1 (Sampler)
1669         // Root Descriptors 0
1670         // DescriptorTable1: Space: 2 (SrvCbvUav)
1671         // Root Descriptors 1
1672         //     ...
1673 
1674         let sets = sets.collect::<Vec<_>>();
1675 
1676         let mut root_offset = 0u32;
1677         let root_constants = root_constants::split(push_constant_ranges)
1678             .iter()
1679             .map(|constant| {
1680                 assert!(constant.range.start <= constant.range.end);
1681                 root_offset += constant.range.end - constant.range.start;
1682 
1683                 RootConstant {
1684                     stages: constant.stages,
1685                     range: constant.range.start..constant.range.end,
1686                 }
1687             })
1688             .collect::<Vec<_>>();
1689 
1690         info!(
1691             "Creating a pipeline layout with {} sets and {} root constants",
1692             sets.len(),
1693             root_constants.len()
1694         );
1695 
1696         // Number of elements in the root signature.
1697         // Guarantees that no re-allocation is done, and our pointers are valid
1698         let mut parameters = Vec::with_capacity(root_constants.len() + sets.len() * 2);
1699         let mut parameter_offsets = Vec::with_capacity(parameters.capacity());
1700 
1701         // Convert root signature descriptions into root signature parameters.
1702         for root_constant in root_constants.iter() {
1703             debug!(
1704                 "\tRoot constant set={} range {:?}",
1705                 ROOT_CONSTANT_SPACE, root_constant.range
1706             );
1707             parameter_offsets.push(root_constant.range.start);
1708             parameters.push(native::RootParameter::constants(
1709                 conv::map_shader_visibility(root_constant.stages),
1710                 native::Binding {
1711                     register: root_constant.range.start as _,
1712                     space: ROOT_CONSTANT_SPACE,
1713                 },
1714                 (root_constant.range.end - root_constant.range.start) as _,
1715             ));
1716         }
1717 
1718         // Offest of `spaceN` for descriptor tables. Root constants will be in
1719         // `space0`.
1720         // This has to match `patch_spirv_resources` logic.
1721         let root_space_offset = if !root_constants.is_empty() { 1 } else { 0 };
1722 
1723         // Collect the whole number of bindings we will create upfront.
1724         // It allows us to preallocate enough storage to avoid reallocation,
1725         // which could cause invalid pointers.
1726         let total = sets
1727             .iter()
1728             .map(|desc_set| {
1729                 let mut sum = 0;
1730                 for binding in desc_set.bindings.iter() {
1731                     let content = r::DescriptorContent::from(binding.ty);
1732                     if !content.is_dynamic() {
1733                         sum += content.bits().count_ones() as usize;
1734                     }
1735                 }
1736                 sum
1737             })
1738             .sum();
1739         let mut ranges = Vec::with_capacity(total);
1740 
1741         let elements = sets
1742             .iter()
1743             .enumerate()
1744             .map(|(i, set)| {
1745                 let space = (root_space_offset + i) as u32;
1746                 let mut table_type = r::SetTableTypes::empty();
1747                 let root_table_offset = root_offset;
1748 
1749                 //TODO: split between sampler and non-sampler tables
1750                 let visibility = conv::map_shader_visibility(
1751                     set.bindings
1752                         .iter()
1753                         .fold(pso::ShaderStageFlags::empty(), |u, bind| {
1754                             u | bind.stage_flags
1755                         }),
1756                 );
1757 
1758                 for bind in set.bindings.iter() {
1759                     debug!("\tRange {:?} at space={}", bind, space);
1760                 }
1761 
1762                 let describe = |bind: &pso::DescriptorSetLayoutBinding, ty| {
1763                     native::DescriptorRange::new(
1764                         ty,
1765                         bind.count as _,
1766                         native::Binding {
1767                             register: bind.binding as _,
1768                             space,
1769                         },
1770                         d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
1771                     )
1772                 };
1773 
1774                 let mut mutable_bindings = auxil::FastHashSet::default();
1775 
1776                 // SRV/CBV/UAV descriptor tables
1777                 let mut range_base = ranges.len();
1778                 for bind in set.bindings.iter() {
1779                     let content = r::DescriptorContent::from(bind.ty);
1780                     if !content.is_dynamic() {
1781                         // Descriptor table ranges
1782                         if content.contains(r::DescriptorContent::CBV) {
1783                             ranges.push(describe(bind, native::DescriptorRangeType::CBV));
1784                         }
1785                         if content.contains(r::DescriptorContent::SRV) {
1786                             ranges.push(describe(bind, native::DescriptorRangeType::SRV));
1787                         }
1788                         if content.contains(r::DescriptorContent::UAV) {
1789                             ranges.push(describe(bind, native::DescriptorRangeType::UAV));
1790                             mutable_bindings.insert(bind.binding);
1791                         }
1792                     }
1793                 }
1794                 if ranges.len() > range_base {
1795                     parameter_offsets.push(root_offset);
1796                     parameters.push(native::RootParameter::descriptor_table(
1797                         visibility,
1798                         &ranges[range_base..],
1799                     ));
1800                     table_type |= r::SRV_CBV_UAV;
1801                     root_offset += 1;
1802                 }
1803 
1804                 // Sampler descriptor tables
1805                 range_base = ranges.len();
1806                 for bind in set.bindings.iter() {
1807                     let content = r::DescriptorContent::from(bind.ty);
1808                     if content.contains(r::DescriptorContent::SAMPLER) {
1809                         ranges.push(describe(bind, native::DescriptorRangeType::Sampler));
1810                     }
1811                 }
1812                 if ranges.len() > range_base {
1813                     parameter_offsets.push(root_offset);
1814                     parameters.push(native::RootParameter::descriptor_table(
1815                         visibility,
1816                         &ranges[range_base..],
1817                     ));
1818                     table_type |= r::SAMPLERS;
1819                     root_offset += 1;
1820                 }
1821 
1822                 // Root (dynamic) descriptor tables
1823                 for bind in set.bindings.iter() {
1824                     let content = r::DescriptorContent::from(bind.ty);
1825                     if content.is_dynamic() {
1826                         let binding = native::Binding {
1827                             register: bind.binding as _,
1828                             space,
1829                         };
1830 
1831                         if content.contains(r::DescriptorContent::CBV) {
1832                             parameter_offsets.push(root_offset);
1833                             parameters
1834                                 .push(native::RootParameter::cbv_descriptor(visibility, binding));
1835                             root_offset += 2; // root CBV costs 2 words
1836                         }
1837                         if content.contains(r::DescriptorContent::SRV) {
1838                             parameter_offsets.push(root_offset);
1839                             parameters
1840                                 .push(native::RootParameter::srv_descriptor(visibility, binding));
1841                             root_offset += 2; // root SRV costs 2 words
1842                         }
1843                         if content.contains(r::DescriptorContent::UAV) {
1844                             parameter_offsets.push(root_offset);
1845                             parameters
1846                                 .push(native::RootParameter::uav_descriptor(visibility, binding));
1847                             root_offset += 2; // root UAV costs 2 words
1848                         }
1849                     }
1850                 }
1851 
1852                 r::RootElement {
1853                     table: r::RootTable {
1854                         ty: table_type,
1855                         offset: root_table_offset as _,
1856                     },
1857                     mutable_bindings,
1858                 }
1859             })
1860             .collect();
1861 
1862         // Ensure that we didn't reallocate!
1863         debug_assert_eq!(ranges.len(), total);
1864         assert_eq!(parameters.len(), parameter_offsets.len());
1865 
1866         // TODO: error handling
1867         let (signature_raw, error) = match self.library.serialize_root_signature(
1868             native::RootSignatureVersion::V1_0,
1869             &parameters,
1870             &[],
1871             native::RootSignatureFlags::ALLOW_IA_INPUT_LAYOUT,
1872         ) {
1873             Ok((pair, hr)) if winerror::SUCCEEDED(hr) => pair,
1874             Ok((_, hr)) => panic!("Can't serialize root signature: {:?}", hr),
1875             Err(e) => panic!("Can't find serialization function: {:?}", e),
1876         };
1877 
1878         if !error.is_null() {
1879             error!(
1880                 "Root signature serialization error: {:?}",
1881                 error.as_c_str().to_str().unwrap()
1882             );
1883             error.destroy();
1884         }
1885 
1886         // TODO: error handling
1887         let (signature, _hr) = self.raw.create_root_signature(signature_raw, 0);
1888         signature_raw.destroy();
1889 
1890         Ok(r::PipelineLayout {
1891             shared: Arc::new(r::PipelineShared {
1892                 signature,
1893                 constants: root_constants,
1894                 parameter_offsets,
1895                 total_slots: root_offset,
1896             }),
1897             elements,
1898         })
1899     }
1900 
create_pipeline_cache(&self, _data: Option<&[u8]>) -> Result<(), d::OutOfMemory>1901     unsafe fn create_pipeline_cache(&self, _data: Option<&[u8]>) -> Result<(), d::OutOfMemory> {
1902         Ok(())
1903     }
1904 
get_pipeline_cache_data(&self, _cache: &()) -> Result<Vec<u8>, d::OutOfMemory>1905     unsafe fn get_pipeline_cache_data(&self, _cache: &()) -> Result<Vec<u8>, d::OutOfMemory> {
1906         //empty
1907         Ok(Vec::new())
1908     }
1909 
destroy_pipeline_cache(&self, _: ())1910     unsafe fn destroy_pipeline_cache(&self, _: ()) {
1911         //empty
1912     }
1913 
merge_pipeline_caches<'a, I>(&self, _: &mut (), _: I) -> Result<(), d::OutOfMemory> where I: Iterator<Item = &'a ()>,1914     unsafe fn merge_pipeline_caches<'a, I>(&self, _: &mut (), _: I) -> Result<(), d::OutOfMemory>
1915     where
1916         I: Iterator<Item = &'a ()>,
1917     {
1918         //empty
1919         Ok(())
1920     }
1921 
create_graphics_pipeline<'a>( &self, desc: &pso::GraphicsPipelineDesc<'a, B>, _cache: Option<&()>, ) -> Result<r::GraphicsPipeline, pso::CreationError>1922     unsafe fn create_graphics_pipeline<'a>(
1923         &self,
1924         desc: &pso::GraphicsPipelineDesc<'a, B>,
1925         _cache: Option<&()>,
1926     ) -> Result<r::GraphicsPipeline, pso::CreationError> {
1927         enum ShaderBc {
1928             Owned(native::Blob),
1929             Borrowed(native::Blob),
1930             None,
1931         }
1932         let features = &self.features;
1933         impl ShaderBc {
1934             pub fn shader(&self) -> native::Shader {
1935                 match *self {
1936                     ShaderBc::Owned(ref bc) | ShaderBc::Borrowed(ref bc) => {
1937                         native::Shader::from_blob(*bc)
1938                     }
1939                     ShaderBc::None => native::Shader::null(),
1940                 }
1941             }
1942         }
1943 
1944         let build_shader = |stage: ShaderStage,
1945                             source: Option<&pso::EntryPoint<'a, B>>|
1946          -> Result<ShaderBc, pso::CreationError> {
1947             let source = match source {
1948                 Some(src) => src,
1949                 None => return Ok(ShaderBc::None),
1950             };
1951 
1952             let (shader, owned) = Self::extract_entry_point(stage, source, desc.layout, features)?;
1953             Ok(if owned {
1954                 ShaderBc::Owned(shader)
1955             } else {
1956                 ShaderBc::Borrowed(shader)
1957             })
1958         };
1959 
1960         let vertex_buffers: Vec<pso::VertexBufferDesc> = Vec::new();
1961         let attributes: Vec<pso::AttributeDesc> = Vec::new();
1962         let mesh_input_assembler = pso::InputAssemblerDesc::new(pso::Primitive::TriangleList);
1963         let (vertex_buffers, attributes, input_assembler, vs, gs, hs, ds, _, _) =
1964             match desc.primitive_assembler {
1965                 pso::PrimitiveAssemblerDesc::Vertex {
1966                     buffers,
1967                     attributes,
1968                     ref input_assembler,
1969                     ref vertex,
1970                     ref tessellation,
1971                     ref geometry,
1972                 } => {
1973                     let (hs, ds) = if let Some(ts) = tessellation {
1974                         (Some(&ts.0), Some(&ts.1))
1975                     } else {
1976                         (None, None)
1977                     };
1978 
1979                     (
1980                         buffers,
1981                         attributes,
1982                         input_assembler,
1983                         Some(vertex),
1984                         geometry.as_ref(),
1985                         hs,
1986                         ds,
1987                         None,
1988                         None,
1989                     )
1990                 }
1991                 pso::PrimitiveAssemblerDesc::Mesh { ref task, ref mesh } => (
1992                     &vertex_buffers[..],
1993                     &attributes[..],
1994                     &mesh_input_assembler,
1995                     None,
1996                     None,
1997                     None,
1998                     None,
1999                     task.as_ref(),
2000                     Some(mesh),
2001                 ),
2002             };
2003 
2004         let vertex_semantic_remapping = if let Some(ref vs) = vs {
2005             // If we have a pre-compiled shader, we've lost the information we need to recover
2006             // this information, so just pretend like this workaround never existed and hope
2007             // for the best.
2008             if let crate::resource::ShaderModule::Spirv(ref spv) = vs.module {
2009                 Some(Self::introspect_spirv_vertex_semantic_remapping(spv)?)
2010             } else {
2011                 None
2012             }
2013         } else {
2014             None
2015         };
2016 
2017         let vs = build_shader(ShaderStage::Vertex, vs)?;
2018         let gs = build_shader(ShaderStage::Geometry, gs)?;
2019         let hs = build_shader(ShaderStage::Domain, hs)?;
2020         let ds = build_shader(ShaderStage::Hull, ds)?;
2021         let ps = build_shader(ShaderStage::Fragment, desc.fragment.as_ref())?;
2022 
2023         // Rebind vertex buffers, see native.rs for more details.
2024         let mut vertex_bindings = [None; MAX_VERTEX_BUFFERS];
2025         let mut vertex_strides = [0; MAX_VERTEX_BUFFERS];
2026 
2027         for buffer in vertex_buffers {
2028             vertex_strides[buffer.binding as usize] = buffer.stride;
2029         }
2030         // Fill in identity mapping where we don't need to adjust anything.
2031         for attrib in attributes {
2032             let binding = attrib.binding as usize;
2033             let stride = vertex_strides[attrib.binding as usize];
2034             if attrib.element.offset < stride {
2035                 vertex_bindings[binding] = Some(r::VertexBinding {
2036                     stride: vertex_strides[attrib.binding as usize],
2037                     offset: 0,
2038                     mapped_binding: binding,
2039                 });
2040             }
2041         }
2042 
2043         // See [`introspect_spirv_vertex_semantic_remapping`] for details of why this is needed.
2044         let semantics: Vec<_> = attributes
2045             .iter()
2046             .map(|attrib| {
2047                 let semantics = vertex_semantic_remapping
2048                     .as_ref()
2049                     .and_then(|map| map.get(&attrib.location));
2050                 match semantics {
2051                     Some(Some((major, minor))) => {
2052                         let name = std::borrow::Cow::Owned(format!("TEXCOORD{}_\0", major));
2053                         let location = *minor;
2054                         (name, location)
2055                     }
2056                     _ => {
2057                         let name = std::borrow::Cow::Borrowed("TEXCOORD\0");
2058                         let location = attrib.location;
2059                         (name, location)
2060                     }
2061                 }
2062             })
2063             .collect();
2064 
2065         // Define input element descriptions
2066         let input_element_descs = attributes
2067             .iter()
2068             .zip(semantics.iter())
2069             .filter_map(|(attrib, (semantic_name, semantic_index))| {
2070                 let buffer_desc = match vertex_buffers
2071                     .iter()
2072                     .find(|buffer_desc| buffer_desc.binding == attrib.binding)
2073                 {
2074                     Some(buffer_desc) => buffer_desc,
2075                     None => {
2076                         error!(
2077                             "Couldn't find associated vertex buffer description {:?}",
2078                             attrib.binding
2079                         );
2080                         return Some(Err(pso::CreationError::Other));
2081                     }
2082                 };
2083 
2084                 let (slot_class, step_rate) = match buffer_desc.rate {
2085                     VertexInputRate::Vertex => {
2086                         (d3d12::D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0)
2087                     }
2088                     VertexInputRate::Instance(divisor) => {
2089                         (d3d12::D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, divisor)
2090                     }
2091                 };
2092                 let format = attrib.element.format;
2093 
2094                 // Check if we need to add a new remapping in-case the offset is
2095                 // higher than the vertex stride.
2096                 // In this case we rebase the attribute to zero offset.
2097                 let binding = attrib.binding as usize;
2098                 let stride = vertex_strides[binding];
2099                 let offset = attrib.element.offset;
2100                 let (input_slot, offset) = if stride <= offset {
2101                     // Number of input attributes may not exceed bindings, see limits.
2102                     // We will always find at least one free binding.
2103                     let mapping = vertex_bindings.iter().position(Option::is_none).unwrap();
2104                     vertex_bindings[mapping] = Some(r::VertexBinding {
2105                         stride: vertex_strides[binding],
2106                         offset: offset,
2107                         mapped_binding: binding,
2108                     });
2109 
2110                     (mapping, 0)
2111                 } else {
2112                     (binding, offset)
2113                 };
2114 
2115                 Some(Ok(d3d12::D3D12_INPUT_ELEMENT_DESC {
2116                     SemanticName: semantic_name.as_ptr() as *const _, // Semantic name used by SPIRV-Cross
2117                     SemanticIndex: *semantic_index,
2118                     Format: match conv::map_format(format) {
2119                         Some(fm) => fm,
2120                         None => {
2121                             error!("Unable to find DXGI format for {:?}", format);
2122                             return Some(Err(pso::CreationError::Other));
2123                         }
2124                     },
2125                     InputSlot: input_slot as _,
2126                     AlignedByteOffset: offset,
2127                     InputSlotClass: slot_class,
2128                     InstanceDataStepRate: step_rate as _,
2129                 }))
2130             })
2131             .collect::<Result<Vec<_>, _>>()?;
2132 
2133         // TODO: check maximum number of rtvs
2134         // Get associated subpass information
2135         let pass = {
2136             let subpass = &desc.subpass;
2137             match subpass.main_pass.subpasses.get(subpass.index as usize) {
2138                 Some(subpass) => subpass,
2139                 None => return Err(pso::CreationError::InvalidSubpass(subpass.index)),
2140             }
2141         };
2142 
2143         // Get color attachment formats from subpass
2144         let (rtvs, num_rtvs) = {
2145             let mut rtvs = [dxgiformat::DXGI_FORMAT_UNKNOWN;
2146                 d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
2147             let mut num_rtvs = 0;
2148             for (rtv, target) in rtvs.iter_mut().zip(pass.color_attachments.iter()) {
2149                 let format = desc.subpass.main_pass.attachments[target.0].format;
2150                 *rtv = format
2151                     .and_then(conv::map_format)
2152                     .unwrap_or(dxgiformat::DXGI_FORMAT_UNKNOWN);
2153                 num_rtvs += 1;
2154             }
2155             (rtvs, num_rtvs)
2156         };
2157 
2158         let sample_desc = dxgitype::DXGI_SAMPLE_DESC {
2159             Count: match desc.multisampling {
2160                 Some(ref ms) => ms.rasterization_samples as _,
2161                 None => 1,
2162             },
2163             Quality: 0,
2164         };
2165 
2166         // Setup pipeline description
2167         let pso_desc = d3d12::D3D12_GRAPHICS_PIPELINE_STATE_DESC {
2168             pRootSignature: desc.layout.shared.signature.as_mut_ptr(),
2169             VS: *vs.shader(),
2170             PS: *ps.shader(),
2171             GS: *gs.shader(),
2172             DS: *ds.shader(),
2173             HS: *hs.shader(),
2174             StreamOutput: d3d12::D3D12_STREAM_OUTPUT_DESC {
2175                 pSODeclaration: ptr::null(),
2176                 NumEntries: 0,
2177                 pBufferStrides: ptr::null(),
2178                 NumStrides: 0,
2179                 RasterizedStream: 0,
2180             },
2181             BlendState: d3d12::D3D12_BLEND_DESC {
2182                 AlphaToCoverageEnable: desc.multisampling.as_ref().map_or(FALSE, |ms| {
2183                     if ms.alpha_coverage {
2184                         TRUE
2185                     } else {
2186                         FALSE
2187                     }
2188                 }),
2189                 IndependentBlendEnable: TRUE,
2190                 RenderTarget: conv::map_render_targets(&desc.blender.targets),
2191             },
2192             SampleMask: match desc.multisampling {
2193                 Some(ref ms) => ms.sample_mask as u32,
2194                 None => UINT::MAX,
2195             },
2196             RasterizerState: conv::map_rasterizer(&desc.rasterizer, desc.multisampling.is_some()),
2197             DepthStencilState: conv::map_depth_stencil(&desc.depth_stencil),
2198             InputLayout: d3d12::D3D12_INPUT_LAYOUT_DESC {
2199                 pInputElementDescs: if input_element_descs.is_empty() {
2200                     ptr::null()
2201                 } else {
2202                     input_element_descs.as_ptr()
2203                 },
2204                 NumElements: input_element_descs.len() as u32,
2205             },
2206             IBStripCutValue: match input_assembler.restart_index {
2207                 Some(hal::IndexType::U16) => d3d12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF,
2208                 Some(hal::IndexType::U32) => d3d12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF,
2209                 None => d3d12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED,
2210             },
2211             PrimitiveTopologyType: conv::map_topology_type(input_assembler.primitive),
2212             NumRenderTargets: num_rtvs,
2213             RTVFormats: rtvs,
2214             DSVFormat: pass
2215                 .depth_stencil_attachment
2216                 .and_then(|att_ref| {
2217                     desc.subpass.main_pass.attachments[att_ref.0]
2218                         .format
2219                         .and_then(|f| conv::map_format_dsv(f.base_format().0))
2220                 })
2221                 .unwrap_or(dxgiformat::DXGI_FORMAT_UNKNOWN),
2222             SampleDesc: sample_desc,
2223             NodeMask: 0,
2224             CachedPSO: d3d12::D3D12_CACHED_PIPELINE_STATE {
2225                 pCachedBlob: ptr::null(),
2226                 CachedBlobSizeInBytes: 0,
2227             },
2228             Flags: d3d12::D3D12_PIPELINE_STATE_FLAG_NONE,
2229         };
2230         let topology = conv::map_topology(input_assembler);
2231 
2232         // Create PSO
2233         let mut pipeline = native::PipelineState::null();
2234         let hr = if desc.depth_stencil.depth_bounds {
2235             // The DepthBoundsTestEnable option isn't available in the original D3D12_GRAPHICS_PIPELINE_STATE_DESC struct.
2236             // Instead, we must use the newer subobject stream method.
2237             let (device2, hr) = self.raw.cast::<d3d12::ID3D12Device2>();
2238             if winerror::SUCCEEDED(hr) {
2239                 let mut pss_stream = GraphicsPipelineStateSubobjectStream::new(&pso_desc, true);
2240                 let pss_desc = d3d12::D3D12_PIPELINE_STATE_STREAM_DESC {
2241                     SizeInBytes: mem::size_of_val(&pss_stream),
2242                     pPipelineStateSubobjectStream: &mut pss_stream as *mut _ as _,
2243                 };
2244                 device2.CreatePipelineState(
2245                     &pss_desc,
2246                     &d3d12::ID3D12PipelineState::uuidof(),
2247                     pipeline.mut_void(),
2248                 )
2249             } else {
2250                 hr
2251             }
2252         } else {
2253             self.raw.clone().CreateGraphicsPipelineState(
2254                 &pso_desc,
2255                 &d3d12::ID3D12PipelineState::uuidof(),
2256                 pipeline.mut_void(),
2257             )
2258         };
2259 
2260         let destroy_shader = |shader: ShaderBc| {
2261             if let ShaderBc::Owned(bc) = shader {
2262                 bc.destroy();
2263             }
2264         };
2265 
2266         destroy_shader(vs);
2267         destroy_shader(ps);
2268         destroy_shader(gs);
2269         destroy_shader(hs);
2270         destroy_shader(ds);
2271 
2272         if winerror::SUCCEEDED(hr) {
2273             let mut baked_states = desc.baked_states.clone();
2274             if !desc.depth_stencil.depth_bounds {
2275                 baked_states.depth_bounds = None;
2276             }
2277             if let Some(name) = desc.label {
2278                 let cwstr = wide_cstr(name);
2279                 pipeline.SetName(cwstr.as_ptr());
2280             }
2281 
2282             Ok(r::GraphicsPipeline {
2283                 raw: pipeline,
2284                 shared: Arc::clone(&desc.layout.shared),
2285                 topology,
2286                 vertex_bindings,
2287                 baked_states,
2288             })
2289         } else {
2290             let error = format!("Failed to build shader: {:x}", hr);
2291             Err(pso::CreationError::ShaderCreationError(
2292                 pso::ShaderStageFlags::GRAPHICS,
2293                 error,
2294             ))
2295         }
2296     }
2297 
create_compute_pipeline<'a>( &self, desc: &pso::ComputePipelineDesc<'a, B>, _cache: Option<&()>, ) -> Result<r::ComputePipeline, pso::CreationError>2298     unsafe fn create_compute_pipeline<'a>(
2299         &self,
2300         desc: &pso::ComputePipelineDesc<'a, B>,
2301         _cache: Option<&()>,
2302     ) -> Result<r::ComputePipeline, pso::CreationError> {
2303         let (cs, cs_destroy) = Self::extract_entry_point(
2304             ShaderStage::Compute,
2305             &desc.shader,
2306             desc.layout,
2307             &self.features,
2308         )?;
2309 
2310         let (pipeline, hr) = self.raw.create_compute_pipeline_state(
2311             desc.layout.shared.signature,
2312             native::Shader::from_blob(cs),
2313             0,
2314             native::CachedPSO::null(),
2315             native::PipelineStateFlags::empty(),
2316         );
2317 
2318         if cs_destroy {
2319             cs.destroy();
2320         }
2321 
2322         if winerror::SUCCEEDED(hr) {
2323             if let Some(name) = desc.label {
2324                 let cwstr = wide_cstr(name);
2325                 pipeline.SetName(cwstr.as_ptr());
2326             }
2327 
2328             Ok(r::ComputePipeline {
2329                 raw: pipeline,
2330                 shared: Arc::clone(&desc.layout.shared),
2331             })
2332         } else {
2333             let error = format!("Failed to build shader: {:x}", hr);
2334             Err(pso::CreationError::ShaderCreationError(
2335                 pso::ShaderStageFlags::COMPUTE,
2336                 error,
2337             ))
2338         }
2339     }
2340 
create_framebuffer<I>( &self, _renderpass: &r::RenderPass, _attachments: I, extent: image::Extent, ) -> Result<r::Framebuffer, d::OutOfMemory>2341     unsafe fn create_framebuffer<I>(
2342         &self,
2343         _renderpass: &r::RenderPass,
2344         _attachments: I,
2345         extent: image::Extent,
2346     ) -> Result<r::Framebuffer, d::OutOfMemory> {
2347         Ok(r::Framebuffer {
2348             layers: extent.depth as _,
2349         })
2350     }
2351 
create_shader_module( &self, raw_data: &[u32], ) -> Result<r::ShaderModule, d::ShaderError>2352     unsafe fn create_shader_module(
2353         &self,
2354         raw_data: &[u32],
2355     ) -> Result<r::ShaderModule, d::ShaderError> {
2356         Ok(r::ShaderModule::Spirv(raw_data.into()))
2357     }
2358 
create_buffer( &self, mut size: u64, usage: buffer::Usage, _sparse: memory::SparseFlags, ) -> Result<r::Buffer, buffer::CreationError>2359     unsafe fn create_buffer(
2360         &self,
2361         mut size: u64,
2362         usage: buffer::Usage,
2363         _sparse: memory::SparseFlags,
2364     ) -> Result<r::Buffer, buffer::CreationError> {
2365         if usage.contains(buffer::Usage::UNIFORM) {
2366             // Constant buffer view sizes need to be aligned.
2367             // Coupled with the offset alignment we can enforce an aligned CBV size
2368             // on descriptor updates.
2369             let mask = d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64 - 1;
2370             size = (size + mask) & !mask;
2371         }
2372         if usage.contains(buffer::Usage::TRANSFER_DST) {
2373             // minimum of 1 word for the clear UAV
2374             size = size.max(4);
2375         }
2376 
2377         let type_mask_shift = if self.private_caps.heterogeneous_resource_heaps {
2378             MEM_TYPE_UNIVERSAL_SHIFT
2379         } else {
2380             MEM_TYPE_BUFFER_SHIFT
2381         };
2382 
2383         let requirements = memory::Requirements {
2384             size,
2385             alignment: d3d12::D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT as u64,
2386             type_mask: MEM_TYPE_MASK << type_mask_shift,
2387         };
2388 
2389         Ok(r::Buffer::Unbound(r::BufferUnbound {
2390             requirements,
2391             usage,
2392             name: None,
2393         }))
2394     }
2395 
get_buffer_requirements(&self, buffer: &r::Buffer) -> Requirements2396     unsafe fn get_buffer_requirements(&self, buffer: &r::Buffer) -> Requirements {
2397         match buffer {
2398             r::Buffer::Unbound(b) => b.requirements,
2399             r::Buffer::Bound(b) => b.requirements,
2400         }
2401     }
2402 
bind_buffer_memory( &self, memory: &r::Memory, offset: u64, buffer: &mut r::Buffer, ) -> Result<(), d::BindError>2403     unsafe fn bind_buffer_memory(
2404         &self,
2405         memory: &r::Memory,
2406         offset: u64,
2407         buffer: &mut r::Buffer,
2408     ) -> Result<(), d::BindError> {
2409         let buffer_unbound = buffer.expect_unbound();
2410         if buffer_unbound.requirements.type_mask & (1 << memory.type_id) == 0 {
2411             error!(
2412                 "Bind memory failure: supported mask 0x{:x}, given id {}",
2413                 buffer_unbound.requirements.type_mask, memory.type_id
2414             );
2415             return Err(d::BindError::WrongMemory);
2416         }
2417         if offset + buffer_unbound.requirements.size > memory.size {
2418             return Err(d::BindError::OutOfBounds);
2419         }
2420 
2421         let mut resource = native::Resource::null();
2422         let desc = d3d12::D3D12_RESOURCE_DESC {
2423             Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER,
2424             Alignment: 0,
2425             Width: buffer_unbound.requirements.size,
2426             Height: 1,
2427             DepthOrArraySize: 1,
2428             MipLevels: 1,
2429             Format: dxgiformat::DXGI_FORMAT_UNKNOWN,
2430             SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
2431                 Count: 1,
2432                 Quality: 0,
2433             },
2434             Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
2435             Flags: conv::map_buffer_flags(buffer_unbound.usage),
2436         };
2437 
2438         assert_eq!(
2439             winerror::S_OK,
2440             self.raw.clone().CreatePlacedResource(
2441                 memory.heap.as_mut_ptr(),
2442                 offset,
2443                 &desc,
2444                 d3d12::D3D12_RESOURCE_STATE_COMMON,
2445                 ptr::null(),
2446                 &d3d12::ID3D12Resource::uuidof(),
2447                 resource.mut_void(),
2448             )
2449         );
2450 
2451         if let Some(ref name) = buffer_unbound.name {
2452             resource.SetName(name.as_ptr());
2453         }
2454 
2455         let clear_uav = if buffer_unbound.usage.contains(buffer::Usage::TRANSFER_DST) {
2456             let handle = self.srv_uav_pool.lock().alloc_handle();
2457             let mut view_desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
2458                 Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
2459                 ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
2460                 u: mem::zeroed(),
2461             };
2462 
2463             *view_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
2464                 FirstElement: 0,
2465                 NumElements: (buffer_unbound.requirements.size / 4) as _,
2466                 StructureByteStride: 0,
2467                 CounterOffsetInBytes: 0,
2468                 Flags: d3d12::D3D12_BUFFER_UAV_FLAG_RAW,
2469             };
2470 
2471             self.raw.CreateUnorderedAccessView(
2472                 resource.as_mut_ptr(),
2473                 ptr::null_mut(),
2474                 &view_desc,
2475                 handle.raw,
2476             );
2477             Some(handle)
2478         } else {
2479             None
2480         };
2481 
2482         *buffer = r::Buffer::Bound(r::BufferBound {
2483             resource,
2484             requirements: buffer_unbound.requirements,
2485             clear_uav,
2486         });
2487 
2488         Ok(())
2489     }
2490 
create_buffer_view( &self, buffer: &r::Buffer, format: Option<format::Format>, sub: buffer::SubRange, ) -> Result<r::BufferView, buffer::ViewCreationError>2491     unsafe fn create_buffer_view(
2492         &self,
2493         buffer: &r::Buffer,
2494         format: Option<format::Format>,
2495         sub: buffer::SubRange,
2496     ) -> Result<r::BufferView, buffer::ViewCreationError> {
2497         let buffer = buffer.expect_bound();
2498         let buffer_features = {
2499             let idx = format.map(|fmt| fmt as usize).unwrap_or(0);
2500             self.format_properties
2501                 .resolve(idx)
2502                 .properties
2503                 .buffer_features
2504         };
2505         let (format, format_desc) = match format.and_then(conv::map_format) {
2506             Some(fmt) => (fmt, format.unwrap().surface_desc()),
2507             None => return Err(buffer::ViewCreationError::UnsupportedFormat(format)),
2508         };
2509 
2510         let start = sub.offset;
2511         let size = sub.size.unwrap_or(buffer.requirements.size - start);
2512 
2513         let bytes_per_texel = (format_desc.bits / 8) as u64;
2514         // Check if it adheres to the texel buffer offset limit
2515         assert_eq!(start % bytes_per_texel, 0);
2516         let first_element = start / bytes_per_texel;
2517         let num_elements = size / bytes_per_texel; // rounds down to next smaller size
2518 
2519         let handle_srv = if buffer_features.contains(format::BufferFeature::UNIFORM_TEXEL) {
2520             let mut desc = d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC {
2521                 Format: format,
2522                 ViewDimension: d3d12::D3D12_SRV_DIMENSION_BUFFER,
2523                 Shader4ComponentMapping: IDENTITY_MAPPING,
2524                 u: mem::zeroed(),
2525             };
2526 
2527             *desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_SRV {
2528                 FirstElement: first_element,
2529                 NumElements: num_elements as _,
2530                 StructureByteStride: bytes_per_texel as _,
2531                 Flags: d3d12::D3D12_BUFFER_SRV_FLAG_NONE,
2532             };
2533 
2534             let handle = self.srv_uav_pool.lock().alloc_handle();
2535             self.raw.clone().CreateShaderResourceView(
2536                 buffer.resource.as_mut_ptr(),
2537                 &desc,
2538                 handle.raw,
2539             );
2540             Some(handle)
2541         } else {
2542             None
2543         };
2544 
2545         let handle_uav = if buffer_features.intersects(
2546             format::BufferFeature::STORAGE_TEXEL | format::BufferFeature::STORAGE_TEXEL_ATOMIC,
2547         ) {
2548             let mut desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
2549                 Format: format,
2550                 ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
2551                 u: mem::zeroed(),
2552             };
2553 
2554             *desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
2555                 FirstElement: first_element,
2556                 NumElements: num_elements as _,
2557                 StructureByteStride: bytes_per_texel as _,
2558                 Flags: d3d12::D3D12_BUFFER_UAV_FLAG_NONE,
2559                 CounterOffsetInBytes: 0,
2560             };
2561 
2562             let handle = self.srv_uav_pool.lock().alloc_handle();
2563             self.raw.clone().CreateUnorderedAccessView(
2564                 buffer.resource.as_mut_ptr(),
2565                 ptr::null_mut(),
2566                 &desc,
2567                 handle.raw,
2568             );
2569             Some(handle)
2570         } else {
2571             None
2572         };
2573 
2574         return Ok(r::BufferView {
2575             handle_srv,
2576             handle_uav,
2577         });
2578     }
2579 
create_image( &self, kind: image::Kind, mip_levels: image::Level, format: format::Format, tiling: image::Tiling, usage: image::Usage, sparse: memory::SparseFlags, view_caps: image::ViewCapabilities, ) -> Result<r::Image, image::CreationError>2580     unsafe fn create_image(
2581         &self,
2582         kind: image::Kind,
2583         mip_levels: image::Level,
2584         format: format::Format,
2585         tiling: image::Tiling,
2586         usage: image::Usage,
2587         sparse: memory::SparseFlags,
2588         view_caps: image::ViewCapabilities,
2589     ) -> Result<r::Image, image::CreationError> {
2590         assert!(mip_levels <= kind.compute_num_levels());
2591 
2592         let base_format = format.base_format();
2593         let format_desc = base_format.0.desc();
2594         let bytes_per_block = (format_desc.bits / 8) as _;
2595         let block_dim = format_desc.dim;
2596         let view_format = conv::map_format(format);
2597         let extent = kind.extent();
2598 
2599         let format_info = self.format_properties.resolve(format as usize);
2600         let (layout, features) = if sparse.contains(memory::SparseFlags::SPARSE_BINDING) {
2601             (
2602                 d3d12::D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE,
2603                 format_info.properties.optimal_tiling,
2604             )
2605         } else {
2606             match tiling {
2607                 image::Tiling::Optimal => (
2608                     d3d12::D3D12_TEXTURE_LAYOUT_UNKNOWN,
2609                     format_info.properties.optimal_tiling,
2610                 ),
2611                 image::Tiling::Linear => (
2612                     d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
2613                     format_info.properties.linear_tiling,
2614                 ),
2615             }
2616         };
2617         if format_info.sample_count_mask & kind.num_samples() == 0 {
2618             return Err(image::CreationError::Samples(kind.num_samples()));
2619         }
2620 
2621         let desc = d3d12::D3D12_RESOURCE_DESC {
2622             Dimension: match kind {
2623                 image::Kind::D1(..) => d3d12::D3D12_RESOURCE_DIMENSION_TEXTURE1D,
2624                 image::Kind::D2(..) => d3d12::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
2625                 image::Kind::D3(..) => d3d12::D3D12_RESOURCE_DIMENSION_TEXTURE3D,
2626             },
2627             Alignment: 0,
2628             Width: extent.width as _,
2629             Height: extent.height as _,
2630             DepthOrArraySize: if extent.depth > 1 {
2631                 extent.depth as _
2632             } else {
2633                 kind.num_layers() as _
2634             },
2635             MipLevels: mip_levels as _,
2636             Format: if format_desc.is_compressed() {
2637                 view_format.unwrap()
2638             } else {
2639                 match conv::map_surface_type(base_format.0) {
2640                     Some(format) => format,
2641                     None => return Err(image::CreationError::Format(format)),
2642                 }
2643             },
2644             SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
2645                 Count: kind.num_samples() as _,
2646                 Quality: 0,
2647             },
2648             Layout: layout,
2649             Flags: conv::map_image_flags(usage, features),
2650         };
2651 
2652         let alloc_info = self.raw.clone().GetResourceAllocationInfo(0, 1, &desc);
2653 
2654         // Image flags which require RT/DS heap due to internal implementation.
2655         let target_flags = d3d12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET
2656             | d3d12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
2657         let type_mask_shift = if self.private_caps.heterogeneous_resource_heaps {
2658             MEM_TYPE_UNIVERSAL_SHIFT
2659         } else if desc.Flags & target_flags != 0 {
2660             MEM_TYPE_TARGET_SHIFT
2661         } else {
2662             MEM_TYPE_IMAGE_SHIFT
2663         };
2664 
2665         Ok(r::Image::Unbound(r::ImageUnbound {
2666             view_format,
2667             dsv_format: conv::map_format_dsv(base_format.0),
2668             desc,
2669             requirements: memory::Requirements {
2670                 size: alloc_info.SizeInBytes,
2671                 alignment: alloc_info.Alignment,
2672                 type_mask: MEM_TYPE_MASK << type_mask_shift,
2673             },
2674             format,
2675             kind,
2676             mip_levels,
2677             usage,
2678             tiling,
2679             view_caps,
2680             bytes_per_block,
2681             block_dim,
2682             name: None,
2683         }))
2684     }
2685 
get_image_requirements(&self, image: &r::Image) -> Requirements2686     unsafe fn get_image_requirements(&self, image: &r::Image) -> Requirements {
2687         match image {
2688             r::Image::Bound(i) => i.requirements,
2689             r::Image::Unbound(i) => i.requirements,
2690         }
2691     }
2692 
get_image_subresource_footprint( &self, image: &r::Image, sub: image::Subresource, ) -> image::SubresourceFootprint2693     unsafe fn get_image_subresource_footprint(
2694         &self,
2695         image: &r::Image,
2696         sub: image::Subresource,
2697     ) -> image::SubresourceFootprint {
2698         let mut num_rows = 0;
2699         let mut total_bytes = 0;
2700         let _desc = match image {
2701             r::Image::Bound(i) => i.descriptor,
2702             r::Image::Unbound(i) => i.desc,
2703         };
2704         let footprint = {
2705             let mut footprint = mem::zeroed();
2706             self.raw.GetCopyableFootprints(
2707                 image.get_desc(),
2708                 image.calc_subresource(sub.level as _, sub.layer as _, 0),
2709                 1,
2710                 0,
2711                 &mut footprint,
2712                 &mut num_rows,
2713                 ptr::null_mut(), // row size in bytes
2714                 &mut total_bytes,
2715             );
2716             footprint
2717         };
2718 
2719         let depth_pitch = (footprint.Footprint.RowPitch * num_rows) as buffer::Offset;
2720         let array_pitch = footprint.Footprint.Depth as buffer::Offset * depth_pitch;
2721         image::SubresourceFootprint {
2722             slice: footprint.Offset..footprint.Offset + total_bytes,
2723             row_pitch: footprint.Footprint.RowPitch as _,
2724             depth_pitch,
2725             array_pitch,
2726         }
2727     }
2728 
bind_image_memory( &self, memory: &r::Memory, offset: u64, image: &mut r::Image, ) -> Result<(), d::BindError>2729     unsafe fn bind_image_memory(
2730         &self,
2731         memory: &r::Memory,
2732         offset: u64,
2733         image: &mut r::Image,
2734     ) -> Result<(), d::BindError> {
2735         let image_unbound = image.expect_unbound();
2736         if image_unbound.requirements.type_mask & (1 << memory.type_id) == 0 {
2737             error!(
2738                 "Bind memory failure: supported mask 0x{:x}, given id {}",
2739                 image_unbound.requirements.type_mask, memory.type_id
2740             );
2741             return Err(d::BindError::WrongMemory);
2742         }
2743         if offset + image_unbound.requirements.size > memory.size {
2744             return Err(d::BindError::OutOfBounds);
2745         }
2746 
2747         let mut resource = native::Resource::null();
2748 
2749         assert_eq!(
2750             winerror::S_OK,
2751             self.raw.clone().CreatePlacedResource(
2752                 memory.heap.as_mut_ptr(),
2753                 offset,
2754                 &image_unbound.desc,
2755                 d3d12::D3D12_RESOURCE_STATE_COMMON,
2756                 ptr::null(),
2757                 &d3d12::ID3D12Resource::uuidof(),
2758                 resource.mut_void(),
2759             )
2760         );
2761 
2762         if let Some(ref name) = image_unbound.name {
2763             resource.SetName(name.as_ptr());
2764         }
2765 
2766         self.bind_image_resource(
2767             resource,
2768             image,
2769             r::Place::Heap {
2770                 raw: memory.heap.clone(),
2771                 offset,
2772             },
2773         );
2774 
2775         Ok(())
2776     }
2777 
create_image_view( &self, image: &r::Image, view_kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, usage: image::Usage, range: image::SubresourceRange, ) -> Result<r::ImageView, image::ViewCreationError>2778     unsafe fn create_image_view(
2779         &self,
2780         image: &r::Image,
2781         view_kind: image::ViewKind,
2782         format: format::Format,
2783         swizzle: format::Swizzle,
2784         usage: image::Usage,
2785         range: image::SubresourceRange,
2786     ) -> Result<r::ImageView, image::ViewCreationError> {
2787         let image = image.expect_bound();
2788         let is_array = image.kind.num_layers() > 1;
2789         let mip_levels = (
2790             range.level_start,
2791             range.level_start + range.resolve_level_count(image.mip_levels),
2792         );
2793         let layers = (
2794             range.layer_start,
2795             range.layer_start + range.resolve_layer_count(image.kind.num_layers()),
2796         );
2797         let surface_format = format.base_format().0;
2798 
2799         let info = ViewInfo {
2800             resource: image.resource,
2801             kind: image.kind,
2802             caps: image.view_caps,
2803             // D3D12 doesn't allow looking at a single slice of an array as a non-array
2804             view_kind: if is_array && view_kind == image::ViewKind::D2 {
2805                 image::ViewKind::D2Array
2806             } else if is_array && view_kind == image::ViewKind::D1 {
2807                 image::ViewKind::D1Array
2808             } else {
2809                 view_kind
2810             },
2811             format: conv::map_format(format).ok_or(image::ViewCreationError::BadFormat(format))?,
2812             component_mapping: conv::map_swizzle(swizzle),
2813             levels: mip_levels.0..mip_levels.1,
2814             layers: layers.0..layers.1,
2815         };
2816 
2817         //Note: we allow RTV/DSV/SRV/UAV views to fail to be created here,
2818         // because we don't know if the user will even need to use them.
2819         //Update: now we have `usage`, but some of the users (like `wgpu`)
2820         // still don't know ahead of time what it needs to be.
2821 
2822         Ok(r::ImageView {
2823             resource: image.resource,
2824             handle_srv: if usage.intersects(image::Usage::SAMPLED | image::Usage::INPUT_ATTACHMENT)
2825             {
2826                 let info = if range.aspects.contains(format::Aspects::DEPTH) {
2827                     conv::map_format_shader_depth(surface_format).map(|format| ViewInfo {
2828                         format,
2829                         ..info.clone()
2830                     })
2831                 } else if range.aspects.contains(format::Aspects::STENCIL) {
2832                     // Vulkan/gfx expects stencil to be read from the R channel,
2833                     // while DX12 exposes it in "G" always.
2834                     let new_swizzle = conv::swizzle_rg(swizzle);
2835                     conv::map_format_shader_stencil(surface_format).map(|format| ViewInfo {
2836                         format,
2837                         component_mapping: conv::map_swizzle(new_swizzle),
2838                         ..info.clone()
2839                     })
2840                 } else {
2841                     Some(info.clone())
2842                 };
2843                 if let Some(ref info) = info {
2844                     self.view_image_as_shader_resource(&info).ok()
2845                 } else {
2846                     None
2847                 }
2848             } else {
2849                 None
2850             },
2851             handle_rtv: if usage.contains(image::Usage::COLOR_ATTACHMENT) {
2852                 // This view is not necessarily going to be rendered to, even
2853                 // if the image supports that in general.
2854                 match self.view_image_as_render_target(&info) {
2855                     Ok(handle) => r::RenderTargetHandle::Pool(handle),
2856                     Err(_) => r::RenderTargetHandle::None,
2857                 }
2858             } else {
2859                 r::RenderTargetHandle::None
2860             },
2861             handle_uav: if usage.contains(image::Usage::STORAGE) {
2862                 self.view_image_as_storage(&info).ok()
2863             } else {
2864                 None
2865             },
2866             handle_dsv: if usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) {
2867                 match conv::map_format_dsv(surface_format) {
2868                     Some(dsv_format) => self
2869                         .view_image_as_depth_stencil(&ViewInfo {
2870                             format: dsv_format,
2871                             ..info
2872                         })
2873                         .ok(),
2874                     None => None,
2875                 }
2876             } else {
2877                 None
2878             },
2879             dxgi_format: image.default_view_format.unwrap(),
2880             num_levels: image.descriptor.MipLevels as image::Level,
2881             mip_levels,
2882             layers,
2883             kind: info.kind,
2884         })
2885     }
2886 
create_sampler( &self, info: &image::SamplerDesc, ) -> Result<r::Sampler, d::AllocationError>2887     unsafe fn create_sampler(
2888         &self,
2889         info: &image::SamplerDesc,
2890     ) -> Result<r::Sampler, d::AllocationError> {
2891         if !info.normalized {
2892             warn!("Sampler with unnormalized coordinates is not supported!");
2893         }
2894         let handle = match self.samplers.map.lock().entry(info.clone()) {
2895             Entry::Occupied(e) => *e.get(),
2896             Entry::Vacant(e) => {
2897                 let handle = self.samplers.pool.lock().alloc_handle();
2898                 let info = e.key();
2899                 let op = match info.comparison {
2900                     Some(_) => d3d12::D3D12_FILTER_REDUCTION_TYPE_COMPARISON,
2901                     None => d3d12::D3D12_FILTER_REDUCTION_TYPE_STANDARD,
2902                 };
2903                 self.raw.create_sampler(
2904                     handle.raw,
2905                     conv::map_filter(
2906                         info.mag_filter,
2907                         info.min_filter,
2908                         info.mip_filter,
2909                         op,
2910                         info.anisotropy_clamp,
2911                     ),
2912                     [
2913                         conv::map_wrap(info.wrap_mode.0),
2914                         conv::map_wrap(info.wrap_mode.1),
2915                         conv::map_wrap(info.wrap_mode.2),
2916                     ],
2917                     info.lod_bias.0,
2918                     info.anisotropy_clamp.map_or(0, |aniso| aniso as u32),
2919                     conv::map_comparison(info.comparison.unwrap_or(pso::Comparison::Always)),
2920                     info.border.into(),
2921                     info.lod_range.start.0..info.lod_range.end.0,
2922                 );
2923                 *e.insert(handle)
2924             }
2925         };
2926         Ok(r::Sampler { handle })
2927     }
2928 
create_descriptor_pool<I>( &self, max_sets: usize, ranges: I, _flags: pso::DescriptorPoolCreateFlags, ) -> Result<r::DescriptorPool, d::OutOfMemory> where I: Iterator<Item = pso::DescriptorRangeDesc>,2929     unsafe fn create_descriptor_pool<I>(
2930         &self,
2931         max_sets: usize,
2932         ranges: I,
2933         _flags: pso::DescriptorPoolCreateFlags,
2934     ) -> Result<r::DescriptorPool, d::OutOfMemory>
2935     where
2936         I: Iterator<Item = pso::DescriptorRangeDesc>,
2937     {
2938         // Descriptor pools are implemented as slices of the global descriptor heaps.
2939         // A descriptor pool will occupy a contiguous space in each heap (CBV/SRV/UAV and Sampler) depending
2940         // on the total requested amount of descriptors.
2941 
2942         let mut num_srv_cbv_uav = 0;
2943         let mut num_samplers = 0;
2944 
2945         let ranges = ranges.collect::<Vec<_>>();
2946 
2947         info!("create_descriptor_pool with {} max sets", max_sets);
2948         for desc in &ranges {
2949             let content = r::DescriptorContent::from(desc.ty);
2950             debug!("\tcontent {:?}", content);
2951             if content.contains(r::DescriptorContent::CBV) {
2952                 num_srv_cbv_uav += desc.count;
2953             }
2954             if content.contains(r::DescriptorContent::SRV) {
2955                 num_srv_cbv_uav += desc.count;
2956             }
2957             if content.contains(r::DescriptorContent::UAV) {
2958                 num_srv_cbv_uav += desc.count;
2959             }
2960             if content.contains(r::DescriptorContent::SAMPLER) {
2961                 num_samplers += desc.count;
2962             }
2963         }
2964 
2965         info!(
2966             "total {} views and {} samplers",
2967             num_srv_cbv_uav, num_samplers
2968         );
2969 
2970         // Allocate slices of the global GPU descriptor heaps.
2971         let heap_srv_cbv_uav = {
2972             let view_heap = &self.heap_srv_cbv_uav.0;
2973 
2974             let range = match num_srv_cbv_uav {
2975                 0 => 0..0,
2976                 _ => self
2977                     .heap_srv_cbv_uav
2978                     .1
2979                     .lock()
2980                     .allocate_range(num_srv_cbv_uav as _)
2981                     .map_err(|e| {
2982                         warn!("View pool allocation error: {:?}", e);
2983                         d::OutOfMemory::Host
2984                     })?,
2985             };
2986 
2987             r::DescriptorHeapSlice {
2988                 heap: view_heap.raw.clone(),
2989                 handle_size: view_heap.handle_size as _,
2990                 range_allocator: RangeAllocator::new(range),
2991                 start: view_heap.start,
2992             }
2993         };
2994 
2995         Ok(r::DescriptorPool {
2996             heap_srv_cbv_uav,
2997             heap_raw_sampler: self.samplers.heap.raw,
2998             pools: ranges,
2999             max_size: max_sets as _,
3000         })
3001     }
3002 
create_descriptor_set_layout<'a, I, J>( &self, bindings: I, _immutable_samplers: J, ) -> Result<r::DescriptorSetLayout, d::OutOfMemory> where I: Iterator<Item = pso::DescriptorSetLayoutBinding>, J: Iterator<Item = &'a r::Sampler>,3003     unsafe fn create_descriptor_set_layout<'a, I, J>(
3004         &self,
3005         bindings: I,
3006         _immutable_samplers: J,
3007     ) -> Result<r::DescriptorSetLayout, d::OutOfMemory>
3008     where
3009         I: Iterator<Item = pso::DescriptorSetLayoutBinding>,
3010         J: Iterator<Item = &'a r::Sampler>,
3011     {
3012         Ok(r::DescriptorSetLayout {
3013             bindings: bindings.collect(),
3014         })
3015     }
3016 
write_descriptor_set<'a, I>(&self, op: pso::DescriptorSetWrite<'a, B, I>) where I: Iterator<Item = pso::Descriptor<'a, B>>,3017     unsafe fn write_descriptor_set<'a, I>(&self, op: pso::DescriptorSetWrite<'a, B, I>)
3018     where
3019         I: Iterator<Item = pso::Descriptor<'a, B>>,
3020     {
3021         let mut descriptor_updater = self.descriptor_updater.lock();
3022         descriptor_updater.reset();
3023 
3024         let mut accum = descriptors_cpu::MultiCopyAccumulator::default();
3025         debug!("write_descriptor_set");
3026 
3027         let mut offset = op.array_offset as u64;
3028         let mut target_binding = op.binding as usize;
3029         let base_sampler_offset = op.set.sampler_offset(op.binding, op.array_offset);
3030         trace!("\tsampler offset {}", base_sampler_offset);
3031         let mut sampler_offset = base_sampler_offset;
3032         debug!("\tbinding {} array offset {}", target_binding, offset);
3033 
3034         for descriptor in op.descriptors {
3035             // spill over the writes onto the next binding
3036             while offset >= op.set.binding_infos[target_binding].count {
3037                 target_binding += 1;
3038                 offset = 0;
3039             }
3040             let bind_info = &mut op.set.binding_infos[target_binding];
3041             let mut src_cbv = None;
3042             let mut src_srv = None;
3043             let mut src_uav = None;
3044 
3045             match descriptor {
3046                 pso::Descriptor::Buffer(buffer, ref sub) => {
3047                     let buffer = buffer.expect_bound();
3048 
3049                     if bind_info.content.is_dynamic() {
3050                         // Root Descriptor
3051                         let buffer_address = (*buffer.resource).GetGPUVirtualAddress();
3052                         // Descriptor sets need to be externally synchronized according to specification
3053                         bind_info.dynamic_descriptors[offset as usize].gpu_buffer_location =
3054                             buffer_address + sub.offset;
3055                     } else {
3056                         // Descriptor table
3057                         let size = sub.size_to(buffer.requirements.size);
3058 
3059                         if bind_info.content.contains(r::DescriptorContent::CBV) {
3060                             // Making the size field of buffer requirements for uniform
3061                             // buffers a multiple of 256 and setting the required offset
3062                             // alignment to 256 allows us to patch the size here.
3063                             // We can always enforce the size to be aligned to 256 for
3064                             // CBVs without going out-of-bounds.
3065                             let mask = d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1;
3066                             let desc = d3d12::D3D12_CONSTANT_BUFFER_VIEW_DESC {
3067                                 BufferLocation: (*buffer.resource).GetGPUVirtualAddress()
3068                                     + sub.offset,
3069                                 SizeInBytes: (size as u32 + mask) as u32 & !mask,
3070                             };
3071                             let handle = descriptor_updater.alloc_handle(self.raw);
3072                             self.raw.CreateConstantBufferView(&desc, handle);
3073                             src_cbv = Some(handle);
3074                         }
3075                         if bind_info.content.contains(r::DescriptorContent::SRV) {
3076                             assert_eq!(size % 4, 0);
3077                             let mut desc = d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC {
3078                                 Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
3079                                 Shader4ComponentMapping: IDENTITY_MAPPING,
3080                                 ViewDimension: d3d12::D3D12_SRV_DIMENSION_BUFFER,
3081                                 u: mem::zeroed(),
3082                             };
3083                             *desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_SRV {
3084                                 FirstElement: sub.offset as _,
3085                                 NumElements: (size / 4) as _,
3086                                 StructureByteStride: 0,
3087                                 Flags: d3d12::D3D12_BUFFER_SRV_FLAG_RAW,
3088                             };
3089                             let handle = descriptor_updater.alloc_handle(self.raw);
3090                             self.raw.CreateShaderResourceView(
3091                                 buffer.resource.as_mut_ptr(),
3092                                 &desc,
3093                                 handle,
3094                             );
3095                             src_srv = Some(handle);
3096                         }
3097                         if bind_info.content.contains(r::DescriptorContent::UAV) {
3098                             assert_eq!(size % 4, 0);
3099                             let mut desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
3100                                 Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
3101                                 ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
3102                                 u: mem::zeroed(),
3103                             };
3104                             *desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
3105                                 FirstElement: sub.offset as _,
3106                                 NumElements: (size / 4) as _,
3107                                 StructureByteStride: 0,
3108                                 CounterOffsetInBytes: 0,
3109                                 Flags: d3d12::D3D12_BUFFER_UAV_FLAG_RAW,
3110                             };
3111                             let handle = descriptor_updater.alloc_handle(self.raw);
3112                             self.raw.CreateUnorderedAccessView(
3113                                 buffer.resource.as_mut_ptr(),
3114                                 ptr::null_mut(),
3115                                 &desc,
3116                                 handle,
3117                             );
3118                             src_uav = Some(handle);
3119                         }
3120                     }
3121                 }
3122                 pso::Descriptor::Image(image, _layout) => {
3123                     if bind_info.content.contains(r::DescriptorContent::SRV) {
3124                         src_srv = image.handle_srv.map(|h| h.raw);
3125                     }
3126                     if bind_info.content.contains(r::DescriptorContent::UAV) {
3127                         src_uav = image.handle_uav.map(|h| h.raw);
3128                     }
3129                 }
3130                 pso::Descriptor::CombinedImageSampler(image, _layout, sampler) => {
3131                     src_srv = image.handle_srv.map(|h| h.raw);
3132                     op.set.sampler_origins[sampler_offset] = sampler.handle.raw;
3133                     sampler_offset += 1;
3134                 }
3135                 pso::Descriptor::Sampler(sampler) => {
3136                     op.set.sampler_origins[sampler_offset] = sampler.handle.raw;
3137                     sampler_offset += 1;
3138                 }
3139                 pso::Descriptor::TexelBuffer(buffer_view) => {
3140                     if bind_info.content.contains(r::DescriptorContent::SRV) {
3141                         let handle = buffer_view.handle_srv
3142                             .expect("SRV handle of the storage texel buffer is zero (not supported by specified format)");
3143                         src_srv = Some(handle.raw);
3144                     }
3145                     if bind_info.content.contains(r::DescriptorContent::UAV) {
3146                         let handle = buffer_view.handle_uav
3147                             .expect("UAV handle of the storage texel buffer is zero (not supported by specified format)");
3148                         src_uav = Some(handle.raw);
3149                     }
3150                 }
3151             }
3152 
3153             if let Some(handle) = src_cbv {
3154                 trace!("\tcbv offset {}", offset);
3155                 accum.src_views.add(handle, 1);
3156                 accum
3157                     .dst_views
3158                     .add(bind_info.view_range.as_ref().unwrap().at(offset), 1);
3159             }
3160             if let Some(handle) = src_srv {
3161                 trace!("\tsrv offset {}", offset);
3162                 accum.src_views.add(handle, 1);
3163                 accum
3164                     .dst_views
3165                     .add(bind_info.view_range.as_ref().unwrap().at(offset), 1);
3166             }
3167             if let Some(handle) = src_uav {
3168                 let uav_offset = if bind_info.content.contains(r::DescriptorContent::SRV) {
3169                     bind_info.count + offset
3170                 } else {
3171                     offset
3172                 };
3173                 trace!("\tuav offset {}", uav_offset);
3174                 accum.src_views.add(handle, 1);
3175                 accum
3176                     .dst_views
3177                     .add(bind_info.view_range.as_ref().unwrap().at(uav_offset), 1);
3178             }
3179 
3180             offset += 1;
3181         }
3182 
3183         if sampler_offset != base_sampler_offset {
3184             op.set
3185                 .update_samplers(&self.samplers.heap, &self.samplers.origins, &mut accum);
3186         }
3187 
3188         accum.flush(self.raw);
3189     }
3190 
copy_descriptor_set<'a>(&self, op: pso::DescriptorSetCopy<'a, B>)3191     unsafe fn copy_descriptor_set<'a>(&self, op: pso::DescriptorSetCopy<'a, B>) {
3192         let mut accum = descriptors_cpu::MultiCopyAccumulator::default();
3193 
3194         let src_info = &op.src_set.binding_infos[op.src_binding as usize];
3195         let dst_info = &op.dst_set.binding_infos[op.dst_binding as usize];
3196 
3197         if let (Some(src_range), Some(dst_range)) =
3198             (src_info.view_range.as_ref(), dst_info.view_range.as_ref())
3199         {
3200             assert!(op.src_array_offset + op.count <= src_range.handle.size as usize);
3201             assert!(op.dst_array_offset + op.count <= dst_range.handle.size as usize);
3202             let count = op.count as u32;
3203             accum
3204                 .src_views
3205                 .add(src_range.at(op.src_array_offset as _), count);
3206             accum
3207                 .dst_views
3208                 .add(dst_range.at(op.dst_array_offset as _), count);
3209 
3210             if (src_info.content & dst_info.content)
3211                 .contains(r::DescriptorContent::SRV | r::DescriptorContent::UAV)
3212             {
3213                 assert!(
3214                     src_info.count as usize + op.src_array_offset + op.count
3215                         <= src_range.handle.size as usize
3216                 );
3217                 assert!(
3218                     dst_info.count as usize + op.dst_array_offset + op.count
3219                         <= dst_range.handle.size as usize
3220                 );
3221                 accum.src_views.add(
3222                     src_range.at(src_info.count + op.src_array_offset as u64),
3223                     count,
3224                 );
3225                 accum.dst_views.add(
3226                     dst_range.at(dst_info.count + op.dst_array_offset as u64),
3227                     count,
3228                 );
3229             }
3230         }
3231 
3232         if dst_info.content.contains(r::DescriptorContent::SAMPLER) {
3233             let src_offset = op
3234                 .src_set
3235                 .sampler_offset(op.src_binding, op.src_array_offset);
3236             let dst_offset = op
3237                 .dst_set
3238                 .sampler_offset(op.dst_binding, op.dst_array_offset);
3239             op.dst_set.sampler_origins[dst_offset..dst_offset + op.count]
3240                 .copy_from_slice(&op.src_set.sampler_origins[src_offset..src_offset + op.count]);
3241 
3242             op.dst_set
3243                 .update_samplers(&self.samplers.heap, &self.samplers.origins, &mut accum);
3244         }
3245 
3246         accum.flush(self.raw.clone());
3247     }
3248 
map_memory( &self, memory: &mut r::Memory, segment: memory::Segment, ) -> Result<*mut u8, d::MapError>3249     unsafe fn map_memory(
3250         &self,
3251         memory: &mut r::Memory,
3252         segment: memory::Segment,
3253     ) -> Result<*mut u8, d::MapError> {
3254         let mem = memory
3255             .resource
3256             .expect("Memory not created with a memory type exposing `CPU_VISIBLE`");
3257         let mut ptr = ptr::null_mut();
3258         assert_eq!(
3259             winerror::S_OK,
3260             (*mem).Map(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 }, &mut ptr)
3261         );
3262         ptr = ptr.offset(segment.offset as isize);
3263         Ok(ptr as *mut _)
3264     }
3265 
unmap_memory(&self, memory: &mut r::Memory)3266     unsafe fn unmap_memory(&self, memory: &mut r::Memory) {
3267         if let Some(mem) = memory.resource {
3268             (*mem).Unmap(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 });
3269         }
3270     }
3271 
flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory> where I: Iterator<Item = (&'a r::Memory, memory::Segment)>,3272     unsafe fn flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory>
3273     where
3274         I: Iterator<Item = (&'a r::Memory, memory::Segment)>,
3275     {
3276         for (memory, ref segment) in ranges {
3277             if let Some(mem) = memory.resource {
3278                 // map and immediately unmap, hoping that dx12 drivers internally cache
3279                 // currently mapped buffers.
3280                 assert_eq!(
3281                     winerror::S_OK,
3282                     (*mem).Map(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 }, ptr::null_mut())
3283                 );
3284 
3285                 let start = segment.offset;
3286                 let end = segment.size.map_or(memory.size, |s| start + s); // TODO: only need to be end of current mapping
3287 
3288                 (*mem).Unmap(
3289                     0,
3290                     &d3d12::D3D12_RANGE {
3291                         Begin: start as _,
3292                         End: end as _,
3293                     },
3294                 );
3295             }
3296         }
3297 
3298         Ok(())
3299     }
3300 
invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory> where I: Iterator<Item = (&'a r::Memory, memory::Segment)>,3301     unsafe fn invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory>
3302     where
3303         I: Iterator<Item = (&'a r::Memory, memory::Segment)>,
3304     {
3305         for (memory, ref segment) in ranges {
3306             if let Some(mem) = memory.resource {
3307                 let start = segment.offset;
3308                 let end = segment.size.map_or(memory.size, |s| start + s); // TODO: only need to be end of current mapping
3309 
3310                 // map and immediately unmap, hoping that dx12 drivers internally cache
3311                 // currently mapped buffers.
3312                 assert_eq!(
3313                     winerror::S_OK,
3314                     (*mem).Map(
3315                         0,
3316                         &d3d12::D3D12_RANGE {
3317                             Begin: start as _,
3318                             End: end as _,
3319                         },
3320                         ptr::null_mut(),
3321                     )
3322                 );
3323 
3324                 (*mem).Unmap(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 });
3325             }
3326         }
3327 
3328         Ok(())
3329     }
3330 
create_semaphore(&self) -> Result<r::Semaphore, d::OutOfMemory>3331     fn create_semaphore(&self) -> Result<r::Semaphore, d::OutOfMemory> {
3332         let fence = self.create_fence(false)?;
3333         Ok(r::Semaphore { raw: fence.raw })
3334     }
3335 
create_fence(&self, signalled: bool) -> Result<r::Fence, d::OutOfMemory>3336     fn create_fence(&self, signalled: bool) -> Result<r::Fence, d::OutOfMemory> {
3337         Ok(r::Fence {
3338             raw: self.create_raw_fence(signalled),
3339         })
3340     }
3341 
reset_fence(&self, fence: &mut r::Fence) -> Result<(), d::OutOfMemory>3342     unsafe fn reset_fence(&self, fence: &mut r::Fence) -> Result<(), d::OutOfMemory> {
3343         assert_eq!(winerror::S_OK, fence.raw.signal(0));
3344         Ok(())
3345     }
3346 
wait_for_fences<'a, I>( &self, fences: I, wait: d::WaitFor, timeout_ns: u64, ) -> Result<bool, d::WaitError> where I: Iterator<Item = &'a r::Fence>,3347     unsafe fn wait_for_fences<'a, I>(
3348         &self,
3349         fences: I,
3350         wait: d::WaitFor,
3351         timeout_ns: u64,
3352     ) -> Result<bool, d::WaitError>
3353     where
3354         I: Iterator<Item = &'a r::Fence>,
3355     {
3356         let mut count = 0;
3357         let mut events = self.events.lock();
3358 
3359         for fence in fences {
3360             if count == events.len() {
3361                 events.push(native::Event::create(false, false));
3362             }
3363             let event = events[count];
3364             synchapi::ResetEvent(event.0);
3365             assert_eq!(winerror::S_OK, fence.raw.set_event_on_completion(event, 1));
3366             count += 1;
3367         }
3368 
3369         let all = match wait {
3370             d::WaitFor::Any => FALSE,
3371             d::WaitFor::All => TRUE,
3372         };
3373 
3374         let hr = {
3375             // This block handles overflow when converting to u32 and always rounds up
3376             // The Vulkan specification allows to wait more than specified
3377             let timeout_ms = {
3378                 if timeout_ns > (<u32>::MAX as u64) * 1_000_000 {
3379                     <u32>::MAX
3380                 } else {
3381                     ((timeout_ns + 999_999) / 1_000_000) as u32
3382                 }
3383             };
3384 
3385             synchapi::WaitForMultipleObjects(
3386                 count as u32,
3387                 events.as_ptr() as *const _,
3388                 all,
3389                 timeout_ms,
3390             )
3391         };
3392 
3393         const WAIT_OBJECT_LAST: u32 = winbase::WAIT_OBJECT_0 + winnt::MAXIMUM_WAIT_OBJECTS;
3394         const WAIT_ABANDONED_LAST: u32 = winbase::WAIT_ABANDONED_0 + winnt::MAXIMUM_WAIT_OBJECTS;
3395         match hr {
3396             winbase::WAIT_OBJECT_0..=WAIT_OBJECT_LAST => Ok(true),
3397             winbase::WAIT_ABANDONED_0..=WAIT_ABANDONED_LAST => Ok(true), //TODO?
3398             winbase::WAIT_FAILED => Err(d::WaitError::DeviceLost(d::DeviceLost)),
3399             winerror::WAIT_TIMEOUT => Ok(false),
3400             _ => panic!("Unexpected wait status 0x{:X}", hr),
3401         }
3402     }
3403 
get_fence_status(&self, fence: &r::Fence) -> Result<bool, d::DeviceLost>3404     unsafe fn get_fence_status(&self, fence: &r::Fence) -> Result<bool, d::DeviceLost> {
3405         match fence.raw.GetCompletedValue() {
3406             0 => Ok(false),
3407             1 => Ok(true),
3408             _ => Err(d::DeviceLost),
3409         }
3410     }
3411 
create_event(&self) -> Result<(), d::OutOfMemory>3412     fn create_event(&self) -> Result<(), d::OutOfMemory> {
3413         unimplemented!()
3414     }
3415 
get_event_status(&self, _event: &()) -> Result<bool, d::WaitError>3416     unsafe fn get_event_status(&self, _event: &()) -> Result<bool, d::WaitError> {
3417         unimplemented!()
3418     }
3419 
set_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory>3420     unsafe fn set_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory> {
3421         unimplemented!()
3422     }
3423 
reset_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory>3424     unsafe fn reset_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory> {
3425         unimplemented!()
3426     }
3427 
free_memory(&self, memory: r::Memory)3428     unsafe fn free_memory(&self, memory: r::Memory) {
3429         memory.heap.destroy();
3430         if let Some(buffer) = memory.resource {
3431             buffer.destroy();
3432         }
3433     }
3434 
create_query_pool( &self, query_ty: query::Type, count: query::Id, ) -> Result<r::QueryPool, query::CreationError>3435     unsafe fn create_query_pool(
3436         &self,
3437         query_ty: query::Type,
3438         count: query::Id,
3439     ) -> Result<r::QueryPool, query::CreationError> {
3440         let heap_ty = match query_ty {
3441             query::Type::Occlusion => native::QueryHeapType::Occlusion,
3442             query::Type::PipelineStatistics(_) => native::QueryHeapType::PipelineStatistics,
3443             query::Type::Timestamp => native::QueryHeapType::Timestamp,
3444         };
3445 
3446         let (query_heap, hr) = self.raw.create_query_heap(heap_ty, count, 0);
3447         assert_eq!(winerror::S_OK, hr);
3448 
3449         Ok(r::QueryPool {
3450             raw: query_heap,
3451             ty: query_ty,
3452         })
3453     }
3454 
destroy_query_pool(&self, pool: r::QueryPool)3455     unsafe fn destroy_query_pool(&self, pool: r::QueryPool) {
3456         pool.raw.destroy();
3457     }
3458 
get_query_pool_results( &self, pool: &r::QueryPool, queries: Range<query::Id>, data: &mut [u8], stride: buffer::Stride, flags: query::ResultFlags, ) -> Result<bool, d::WaitError>3459     unsafe fn get_query_pool_results(
3460         &self,
3461         pool: &r::QueryPool,
3462         queries: Range<query::Id>,
3463         data: &mut [u8],
3464         stride: buffer::Stride,
3465         flags: query::ResultFlags,
3466     ) -> Result<bool, d::WaitError> {
3467         let num_queries = queries.end - queries.start;
3468         let size = 8 * num_queries as u64;
3469         let buffer_desc = d3d12::D3D12_RESOURCE_DESC {
3470             Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER,
3471             Alignment: 0,
3472             Width: size,
3473             Height: 1,
3474             DepthOrArraySize: 1,
3475             MipLevels: 1,
3476             Format: dxgiformat::DXGI_FORMAT_UNKNOWN,
3477             SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
3478                 Count: 1,
3479                 Quality: 0,
3480             },
3481             Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
3482             Flags: d3d12::D3D12_RESOURCE_FLAG_NONE,
3483         };
3484 
3485         let properties = d3d12::D3D12_HEAP_PROPERTIES {
3486             Type: d3d12::D3D12_HEAP_TYPE_READBACK,
3487             CPUPageProperty: d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
3488             MemoryPoolPreference: d3d12::D3D12_MEMORY_POOL_UNKNOWN,
3489             CreationNodeMask: 0,
3490             VisibleNodeMask: 0,
3491         };
3492 
3493         let heap_desc = d3d12::D3D12_HEAP_DESC {
3494             SizeInBytes: size,
3495             Properties: properties,
3496             Alignment: 0,
3497             Flags: d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
3498         };
3499 
3500         let mut heap = native::Heap::null();
3501         assert_eq!(
3502             self.raw
3503                 .clone()
3504                 .CreateHeap(&heap_desc, &d3d12::ID3D12Heap::uuidof(), heap.mut_void()),
3505             winerror::S_OK
3506         );
3507 
3508         let mut temp_buffer = native::Resource::null();
3509         assert_eq!(
3510             winerror::S_OK,
3511             self.raw.clone().CreatePlacedResource(
3512                 heap.as_mut_ptr(),
3513                 0,
3514                 &buffer_desc,
3515                 d3d12::D3D12_RESOURCE_STATE_COPY_DEST,
3516                 ptr::null(),
3517                 &d3d12::ID3D12Resource::uuidof(),
3518                 temp_buffer.mut_void(),
3519             )
3520         );
3521 
3522         let list_type = native::CmdListType::Direct;
3523         let (com_allocator, hr_alloc) = self.raw.create_command_allocator(list_type);
3524         assert_eq!(
3525             winerror::S_OK,
3526             hr_alloc,
3527             "error on command allocator creation: {:x}",
3528             hr_alloc
3529         );
3530         let (com_list, hr_list) = self.raw.create_graphics_command_list(
3531             list_type,
3532             com_allocator,
3533             native::PipelineState::null(),
3534             0,
3535         );
3536         assert_eq!(
3537             winerror::S_OK,
3538             hr_list,
3539             "error on command list creation: {:x}",
3540             hr_list
3541         );
3542 
3543         let query_ty = match pool.ty {
3544             query::Type::Occlusion => d3d12::D3D12_QUERY_TYPE_OCCLUSION,
3545             query::Type::PipelineStatistics(_) => d3d12::D3D12_QUERY_TYPE_PIPELINE_STATISTICS,
3546             query::Type::Timestamp => d3d12::D3D12_QUERY_TYPE_TIMESTAMP,
3547         };
3548         com_list.ResolveQueryData(
3549             pool.raw.as_mut_ptr(),
3550             query_ty,
3551             queries.start,
3552             num_queries,
3553             temp_buffer.as_mut_ptr(),
3554             0,
3555         );
3556         com_list.close();
3557 
3558         self.queues[0]
3559             .raw
3560             .ExecuteCommandLists(1, &(com_list.as_mut_ptr() as *mut _));
3561 
3562         if !flags.contains(query::ResultFlags::WAIT) {
3563             warn!("Can't really not wait here")
3564         }
3565         let result = self.queues[0].wait_idle_impl();
3566         if result.is_ok() {
3567             let mut ptr = ptr::null_mut();
3568             assert_eq!(
3569                 winerror::S_OK,
3570                 temp_buffer.Map(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 }, &mut ptr)
3571             );
3572             let src_data = slice::from_raw_parts(ptr as *const u64, num_queries as usize);
3573             for (i, &value) in src_data.iter().enumerate() {
3574                 let dst = data.as_mut_ptr().add(i * stride as usize);
3575                 if flags.contains(query::ResultFlags::BITS_64) {
3576                     *(dst as *mut u64) = value;
3577                 } else {
3578                     *(dst as *mut u32) = value as u32;
3579                 }
3580             }
3581             temp_buffer.Unmap(0, &d3d12::D3D12_RANGE { Begin: 0, End: 0 });
3582         }
3583 
3584         temp_buffer.destroy();
3585         heap.destroy();
3586         com_list.destroy();
3587         com_allocator.destroy();
3588 
3589         match result {
3590             Ok(()) => Ok(true),
3591             Err(e) => Err(e.into()),
3592         }
3593     }
3594 
destroy_shader_module(&self, shader_lib: r::ShaderModule)3595     unsafe fn destroy_shader_module(&self, shader_lib: r::ShaderModule) {
3596         if let r::ShaderModule::Compiled(shaders) = shader_lib {
3597             for (_, blob) in shaders {
3598                 blob.destroy();
3599             }
3600         }
3601     }
3602 
destroy_render_pass(&self, _rp: r::RenderPass)3603     unsafe fn destroy_render_pass(&self, _rp: r::RenderPass) {
3604         // Just drop
3605     }
3606 
destroy_pipeline_layout(&self, layout: r::PipelineLayout)3607     unsafe fn destroy_pipeline_layout(&self, layout: r::PipelineLayout) {
3608         layout.shared.signature.destroy();
3609     }
3610 
destroy_graphics_pipeline(&self, pipeline: r::GraphicsPipeline)3611     unsafe fn destroy_graphics_pipeline(&self, pipeline: r::GraphicsPipeline) {
3612         pipeline.raw.destroy();
3613     }
3614 
destroy_compute_pipeline(&self, pipeline: r::ComputePipeline)3615     unsafe fn destroy_compute_pipeline(&self, pipeline: r::ComputePipeline) {
3616         pipeline.raw.destroy();
3617     }
3618 
destroy_framebuffer(&self, _fb: r::Framebuffer)3619     unsafe fn destroy_framebuffer(&self, _fb: r::Framebuffer) {
3620         // Just drop
3621     }
3622 
destroy_buffer(&self, buffer: r::Buffer)3623     unsafe fn destroy_buffer(&self, buffer: r::Buffer) {
3624         match buffer {
3625             r::Buffer::Bound(buffer) => {
3626                 if let Some(handle) = buffer.clear_uav {
3627                     self.srv_uav_pool.lock().free_handle(handle);
3628                 }
3629                 buffer.resource.destroy();
3630             }
3631             r::Buffer::Unbound(_) => {}
3632         }
3633     }
3634 
destroy_buffer_view(&self, view: r::BufferView)3635     unsafe fn destroy_buffer_view(&self, view: r::BufferView) {
3636         let mut pool = self.srv_uav_pool.lock();
3637         if let Some(handle) = view.handle_srv {
3638             pool.free_handle(handle);
3639         }
3640         if let Some(handle) = view.handle_uav {
3641             pool.free_handle(handle);
3642         }
3643     }
3644 
destroy_image(&self, image: r::Image)3645     unsafe fn destroy_image(&self, image: r::Image) {
3646         match image {
3647             r::Image::Bound(image) => {
3648                 let mut dsv_pool = self.dsv_pool.lock();
3649                 for handle in image.clear_cv {
3650                     self.rtv_pool.lock().free_handle(handle);
3651                 }
3652                 for handle in image.clear_dv {
3653                     dsv_pool.free_handle(handle);
3654                 }
3655                 for handle in image.clear_sv {
3656                     dsv_pool.free_handle(handle);
3657                 }
3658                 image.resource.destroy();
3659             }
3660             r::Image::Unbound(_) => {}
3661         }
3662     }
3663 
destroy_image_view(&self, view: r::ImageView)3664     unsafe fn destroy_image_view(&self, view: r::ImageView) {
3665         if let Some(handle) = view.handle_srv {
3666             self.srv_uav_pool.lock().free_handle(handle);
3667         }
3668         if let Some(handle) = view.handle_uav {
3669             self.srv_uav_pool.lock().free_handle(handle);
3670         }
3671         if let r::RenderTargetHandle::Pool(handle) = view.handle_rtv {
3672             self.rtv_pool.lock().free_handle(handle);
3673         }
3674         if let Some(handle) = view.handle_dsv {
3675             self.dsv_pool.lock().free_handle(handle);
3676         }
3677     }
3678 
destroy_sampler(&self, _sampler: r::Sampler)3679     unsafe fn destroy_sampler(&self, _sampler: r::Sampler) {
3680         // We don't destroy samplers, they are permanently cached
3681     }
3682 
destroy_descriptor_pool(&self, pool: r::DescriptorPool)3683     unsafe fn destroy_descriptor_pool(&self, pool: r::DescriptorPool) {
3684         let view_range = pool.heap_srv_cbv_uav.range_allocator.initial_range();
3685         if view_range.start < view_range.end {
3686             self.heap_srv_cbv_uav
3687                 .1
3688                 .lock()
3689                 .free_range(view_range.clone());
3690         }
3691     }
3692 
destroy_descriptor_set_layout(&self, _layout: r::DescriptorSetLayout)3693     unsafe fn destroy_descriptor_set_layout(&self, _layout: r::DescriptorSetLayout) {
3694         // Just drop
3695     }
3696 
destroy_fence(&self, fence: r::Fence)3697     unsafe fn destroy_fence(&self, fence: r::Fence) {
3698         fence.raw.destroy();
3699     }
3700 
destroy_semaphore(&self, semaphore: r::Semaphore)3701     unsafe fn destroy_semaphore(&self, semaphore: r::Semaphore) {
3702         semaphore.raw.destroy();
3703     }
3704 
destroy_event(&self, _event: ())3705     unsafe fn destroy_event(&self, _event: ()) {
3706         unimplemented!()
3707     }
3708 
wait_idle(&self) -> Result<(), d::OutOfMemory>3709     fn wait_idle(&self) -> Result<(), d::OutOfMemory> {
3710         for queue in &self.queues {
3711             queue.wait_idle_impl()?;
3712         }
3713         Ok(())
3714     }
3715 
set_image_name(&self, image: &mut r::Image, name: &str)3716     unsafe fn set_image_name(&self, image: &mut r::Image, name: &str) {
3717         let cwstr = wide_cstr(name);
3718         match *image {
3719             r::Image::Unbound(ref mut image) => image.name = Some(cwstr),
3720             r::Image::Bound(ref image) => {
3721                 image.resource.SetName(cwstr.as_ptr());
3722             }
3723         }
3724     }
3725 
set_buffer_name(&self, buffer: &mut r::Buffer, name: &str)3726     unsafe fn set_buffer_name(&self, buffer: &mut r::Buffer, name: &str) {
3727         let cwstr = wide_cstr(name);
3728         match *buffer {
3729             r::Buffer::Unbound(ref mut buffer) => buffer.name = Some(cwstr),
3730             r::Buffer::Bound(ref buffer) => {
3731                 buffer.resource.SetName(cwstr.as_ptr());
3732             }
3733         }
3734     }
3735 
set_command_buffer_name(&self, command_buffer: &mut cmd::CommandBuffer, name: &str)3736     unsafe fn set_command_buffer_name(&self, command_buffer: &mut cmd::CommandBuffer, name: &str) {
3737         let cwstr = wide_cstr(name);
3738         if !command_buffer.raw.is_null() {
3739             command_buffer.raw.SetName(cwstr.as_ptr());
3740         }
3741         command_buffer.raw_name = cwstr;
3742     }
3743 
set_semaphore_name(&self, semaphore: &mut r::Semaphore, name: &str)3744     unsafe fn set_semaphore_name(&self, semaphore: &mut r::Semaphore, name: &str) {
3745         let cwstr = wide_cstr(name);
3746         semaphore.raw.SetName(cwstr.as_ptr());
3747     }
3748 
set_fence_name(&self, fence: &mut r::Fence, name: &str)3749     unsafe fn set_fence_name(&self, fence: &mut r::Fence, name: &str) {
3750         let cwstr = wide_cstr(name);
3751         fence.raw.SetName(cwstr.as_ptr());
3752     }
3753 
set_framebuffer_name(&self, _framebuffer: &mut r::Framebuffer, _name: &str)3754     unsafe fn set_framebuffer_name(&self, _framebuffer: &mut r::Framebuffer, _name: &str) {
3755         // ignored
3756     }
3757 
set_render_pass_name(&self, render_pass: &mut r::RenderPass, name: &str)3758     unsafe fn set_render_pass_name(&self, render_pass: &mut r::RenderPass, name: &str) {
3759         render_pass.raw_name = wide_cstr(name);
3760     }
3761 
set_descriptor_set_name(&self, descriptor_set: &mut r::DescriptorSet, name: &str)3762     unsafe fn set_descriptor_set_name(&self, descriptor_set: &mut r::DescriptorSet, name: &str) {
3763         descriptor_set.raw_name = wide_cstr(name);
3764     }
3765 
set_descriptor_set_layout_name( &self, _descriptor_set_layout: &mut r::DescriptorSetLayout, _name: &str, )3766     unsafe fn set_descriptor_set_layout_name(
3767         &self,
3768         _descriptor_set_layout: &mut r::DescriptorSetLayout,
3769         _name: &str,
3770     ) {
3771         // ignored
3772     }
3773 
set_pipeline_layout_name(&self, pipeline_layout: &mut r::PipelineLayout, name: &str)3774     unsafe fn set_pipeline_layout_name(&self, pipeline_layout: &mut r::PipelineLayout, name: &str) {
3775         let cwstr = wide_cstr(name);
3776         pipeline_layout.shared.signature.SetName(cwstr.as_ptr());
3777     }
3778 
start_capture(&self)3779     fn start_capture(&self) {
3780         //TODO
3781     }
3782 
stop_capture(&self)3783     fn stop_capture(&self) {
3784         //TODO
3785     }
3786 }
3787 
3788 #[test]
test_identity_mapping()3789 fn test_identity_mapping() {
3790     assert_eq!(conv::map_swizzle(format::Swizzle::NO), IDENTITY_MAPPING);
3791 }
3792