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 ¶meters,
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