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