1use super::command_list_type::*;
2use super::descriptor_heap_type::*;
3use super::resource_barriers::*;
4use super::*;
5use windows::Win32::Graphics::{Direct3D::*, Direct3D12::*, Dxgi::Common::DXGI_FORMAT};
6use windows::core::Interface;
7
8#[derive(Clone, Debug)]
9#[repr(transparent)]
10pub struct Viewport(pub D3D12_VIEWPORT);
11
12impl Viewport {
13 #[inline]
14 pub fn new() -> Self {
15 Self(D3D12_VIEWPORT {
16 MaxDepth: 1.0,
17 ..Default::default()
18 })
19 }
20
21 #[inline]
22 pub fn top_left_x(mut self, x: f32) -> Self {
23 self.0.TopLeftX = x;
24 self
25 }
26
27 #[inline]
28 pub fn top_left_y(mut self, y: f32) -> Self {
29 self.0.TopLeftY = y;
30 self
31 }
32
33 #[inline]
34 pub fn width(mut self, width: f32) -> Self {
35 self.0.Width = width;
36 self
37 }
38
39 #[inline]
40 pub fn height(mut self, height: f32) -> Self {
41 self.0.Height = height;
42 self
43 }
44
45 #[inline]
46 pub fn min_depth(mut self, d: f32) -> Self {
47 self.0.MinDepth = d;
48 self
49 }
50
51 #[inline]
52 pub fn max_depth(mut self, d: f32) -> Self {
53 self.0.MaxDepth = d;
54 self
55 }
56}
57
58impl Default for Viewport {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64#[derive(Clone, Debug)]
65#[repr(transparent)]
66pub struct VertexBufferView {
67 view: D3D12_VERTEX_BUFFER_VIEW,
68}
69
70impl VertexBufferView {
71 #[inline]
72 #[allow(clippy::new_without_default)]
73 pub fn new() -> Self {
74 Self {
75 view: D3D12_VERTEX_BUFFER_VIEW::default(),
76 }
77 }
78
79 #[inline]
80 pub fn buffer_location(mut self, loc: GpuVirtualAddress) -> Self {
81 self.view.BufferLocation = loc.0;
82 self
83 }
84
85 #[inline]
86 pub fn size_in_bytes(mut self, size: u32) -> Self {
87 self.view.SizeInBytes = size;
88 self
89 }
90
91 #[inline]
92 pub fn stride_in_bytes(mut self, stride: u32) -> Self {
93 self.view.StrideInBytes = stride;
94 self
95 }
96}
97
98#[derive(Clone, Debug)]
99#[repr(transparent)]
100pub struct IndexBufferView {
101 view: D3D12_INDEX_BUFFER_VIEW,
102}
103
104impl IndexBufferView {
105 #[inline]
106 #[allow(clippy::new_without_default)]
107 pub fn new() -> Self {
108 Self {
109 view: D3D12_INDEX_BUFFER_VIEW::default(),
110 }
111 }
112
113 #[inline]
114 pub fn buffer_location(mut self, loc: GpuVirtualAddress) -> Self {
115 self.view.BufferLocation = loc.0;
116 self
117 }
118
119 #[inline]
120 pub fn size_in_bytes(mut self, size: u32) -> Self {
121 self.view.SizeInBytes = size;
122 self
123 }
124
125 #[inline]
126 pub fn format(mut self, format: DXGI_FORMAT) -> Self {
127 self.view.Format = format;
128 self
129 }
130}
131
132pub struct DiscardRegion<'a> {
133 region: D3D12_DISCARD_REGION,
134 _a: std::marker::PhantomData<&'a ()>,
135}
136
137impl DiscardRegion<'_> {
138 #[inline]
139 #[allow(clippy::new_without_default)]
140 pub fn new() -> Self {
141 Self {
142 region: D3D12_DISCARD_REGION::default(),
143 _a: std::marker::PhantomData,
144 }
145 }
146
147 #[inline]
148 pub fn rects(self, rects: &[Rect]) -> DiscardRegion<'_> {
149 let rects = as_rect_slice(rects);
150 DiscardRegion {
151 region: D3D12_DISCARD_REGION {
152 NumRects: rects.len() as u32,
153 pRects: rects.as_ptr(),
154 ..self.region
155 },
156 _a: std::marker::PhantomData,
157 }
158 }
159
160 #[inline]
161 pub fn first_subresource(mut self, subresource: u32) -> Self {
162 self.region.FirstSubresource = subresource;
163 self
164 }
165
166 #[inline]
167 pub fn num_subresource(mut self, n: u32) -> Self {
168 self.region.NumSubresources = n;
169 self
170 }
171}
172
173#[derive(Clone, Debug)]
174#[repr(transparent)]
175pub struct DispatchRaysDesc(D3D12_DISPATCH_RAYS_DESC);
176
177impl DispatchRaysDesc {
178 #[inline]
179 #[allow(clippy::new_without_default)]
180 pub fn new() -> Self {
181 Self(D3D12_DISPATCH_RAYS_DESC::default())
182 }
183
184 #[inline]
185 pub fn ray_generation_shader_record(mut self, range: GpuVirtualAddressRange) -> Self {
186 self.0.RayGenerationShaderRecord = range.0;
187 self
188 }
189
190 #[inline]
191 pub fn miss_shader_table(mut self, value: GpuVirtualAddressRangeAndStride) -> Self {
192 self.0.MissShaderTable = value.0;
193 self
194 }
195
196 #[inline]
197 pub fn hit_group_table(mut self, value: GpuVirtualAddressRangeAndStride) -> Self {
198 self.0.HitGroupTable = value.0;
199 self
200 }
201
202 #[inline]
203 pub fn callable_shader_table(mut self, value: GpuVirtualAddressRangeAndStride) -> Self {
204 self.0.CallableShaderTable = value.0;
205 self
206 }
207
208 #[inline]
209 pub fn width(mut self, width: u32) -> Self {
210 self.0.Width = width;
211 self
212 }
213
214 #[inline]
215 pub fn height(mut self, height: u32) -> Self {
216 self.0.Height = height;
217 self
218 }
219
220 #[inline]
221 pub fn depth(mut self, depth: u32) -> Self {
222 self.0.Depth = depth;
223 self
224 }
225}
226
227#[derive(Clone, Debug)]
228#[repr(transparent)]
229pub struct StreamOutputBufferView(D3D12_STREAM_OUTPUT_BUFFER_VIEW);
230
231impl StreamOutputBufferView {
232 #[inline]
233 #[allow(clippy::new_without_default)]
234 pub fn new() -> Self {
235 Self(D3D12_STREAM_OUTPUT_BUFFER_VIEW::default())
236 }
237
238 #[inline]
239 pub fn buffer_location(mut self, loc: GpuVirtualAddress) -> Self {
240 self.0.BufferLocation = loc.0;
241 self
242 }
243
244 #[inline]
245 pub fn size_in_bytes(mut self, size: u64) -> Self {
246 self.0.SizeInBytes = size;
247 self
248 }
249
250 #[inline]
251 pub fn buffer_filled_size_location(mut self, v: u64) -> Self {
252 self.0.BufferFilledSizeLocation = v;
253 self
254 }
255}
256
257pub trait ClearUnorderedAccessView: Sized {
258 fn call(
259 cmd_list: &ID3D12GraphicsCommandList7,
260 view_gpu_handle: &GpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
261 view_cpu_handle: &CpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
262 resource: &Resource,
263 values: &[Self; 4],
264 rects: &[Rect],
265 );
266}
267
268impl ClearUnorderedAccessView for f32 {
269 fn call(
270 cmd_list: &ID3D12GraphicsCommandList7,
271 view_gpu_handle: &GpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
272 view_cpu_handle: &CpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
273 resource: &Resource,
274 values: &[Self; 4],
275 rects: &[Rect],
276 ) {
277 unsafe {
278 cmd_list.ClearUnorderedAccessViewFloat(
279 view_gpu_handle.handle(),
280 view_cpu_handle.handle(),
281 resource.handle(),
282 values,
283 as_rect_slice(rects),
284 );
285 }
286 }
287}
288
289impl ClearUnorderedAccessView for u32 {
290 fn call(
291 cmd_list: &ID3D12GraphicsCommandList7,
292 view_gpu_handle: &GpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
293 view_cpu_handle: &CpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
294 resource: &Resource,
295 values: &[Self; 4],
296 rects: &[Rect],
297 ) {
298 unsafe {
299 cmd_list.ClearUnorderedAccessViewUint(
300 view_gpu_handle.handle(),
301 view_cpu_handle.handle(),
302 resource.handle(),
303 values,
304 as_rect_slice(rects),
305 );
306 }
307 }
308}
309
310pub trait SetComputeRoot32BitConstants {
311 fn call(
312 self,
313 cmd_list: &ID3D12GraphicsCommandList7,
314 root_parameter_index: u32,
315 dest_offset_in_32bit_values: u32,
316 );
317}
318
319impl SetComputeRoot32BitConstants for u32 {
320 fn call(
321 self,
322 cmd_list: &ID3D12GraphicsCommandList7,
323 root_parameter_index: u32,
324 dest_offset_in_32bit_values: u32,
325 ) {
326 unsafe {
327 cmd_list.SetComputeRoot32BitConstant(
328 root_parameter_index,
329 self,
330 dest_offset_in_32bit_values,
331 );
332 }
333 }
334}
335
336impl SetComputeRoot32BitConstants for &[u32] {
337 fn call(
338 self,
339 cmd_list: &ID3D12GraphicsCommandList7,
340 root_parameter_index: u32,
341 dest_offset_in_32bit_values: u32,
342 ) {
343 unsafe {
344 cmd_list.SetComputeRoot32BitConstants(
345 root_parameter_index,
346 self.len() as u32,
347 self.as_ptr() as *const std::ffi::c_void,
348 dest_offset_in_32bit_values,
349 );
350 }
351 }
352}
353
354pub trait SetGraphicsRoot32BitConstants {
355 fn call(
356 self,
357 cmd_list: &ID3D12GraphicsCommandList7,
358 root_parameter_index: u32,
359 dest_offset_in_32bit_values: u32,
360 );
361}
362
363impl SetGraphicsRoot32BitConstants for u32 {
364 fn call(
365 self,
366 cmd_list: &ID3D12GraphicsCommandList7,
367 root_parameter_index: u32,
368 dest_offset_in_32bit_values: u32,
369 ) {
370 unsafe {
371 cmd_list.SetGraphicsRoot32BitConstant(
372 root_parameter_index,
373 self,
374 dest_offset_in_32bit_values,
375 );
376 }
377 }
378}
379
380impl SetGraphicsRoot32BitConstants for &[u32] {
381 fn call(
382 self,
383 cmd_list: &ID3D12GraphicsCommandList7,
384 root_parameter_index: u32,
385 dest_offset_in_32bit_values: u32,
386 ) {
387 unsafe {
388 cmd_list.SetGraphicsRoot32BitConstants(
389 root_parameter_index,
390 self.len() as u32,
391 self.as_ptr() as *const std::ffi::c_void,
392 dest_offset_in_32bit_values,
393 );
394 }
395 }
396}
397
398pub trait PipelineStateType {
399 fn call(&self, cmd_list: &ID3D12GraphicsCommandList7);
400}
401
402#[derive(Clone)]
403pub struct TextureCopyLocation(D3D12_TEXTURE_COPY_LOCATION);
404
405impl TextureCopyLocation {
406 #[inline]
407 pub fn placed_footprint(
408 resource: &Resource,
409 placed_footprint: PlacedSubresourceFootprint,
410 ) -> Self {
411 Self(D3D12_TEXTURE_COPY_LOCATION {
412 pResource: std::mem::ManuallyDrop::new(Some(resource.handle().clone())),
413 Type: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
414 Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
415 PlacedFootprint: placed_footprint.into(),
416 },
417 })
418 }
419
420 #[inline]
421 pub fn subresource_index(resource: &Resource, index: u32) -> Self {
422 Self(D3D12_TEXTURE_COPY_LOCATION {
423 pResource: std::mem::ManuallyDrop::new(Some(resource.handle().clone())),
424 Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
425 Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
426 SubresourceIndex: index,
427 },
428 })
429 }
430}
431
432impl Drop for TextureCopyLocation {
433 fn drop(&mut self) {
434 unsafe {
435 std::mem::ManuallyDrop::drop(&mut self.0.pResource);
436 }
437 }
438}
439
440pub struct Commands<'a, T> {
441 cmd_list: &'a ID3D12GraphicsCommandList7,
442 _t: std::marker::PhantomData<T>,
443}
444
445impl<T> Commands<'_, T> {
446 #[inline]
447 pub fn clear_depth_stencil_view(
448 &self,
449 dsv: &CpuDescriptorHandle<Dsv>,
450 depth: Option<f32>,
451 stencil: Option<u8>,
452 rects: Option<&[Rect]>,
453 ) {
454 let flags = depth.map_or(0, |_| D3D12_CLEAR_FLAG_DEPTH.0)
455 | stencil.map_or(0, |_| D3D12_CLEAR_FLAG_STENCIL.0);
456 unsafe {
457 self.cmd_list.ClearDepthStencilView(
458 dsv.handle(),
459 D3D12_CLEAR_FLAGS(flags),
460 depth.unwrap_or(0.0),
461 stencil.unwrap_or(0),
462 rects.map(as_rect_slice),
463 );
464 }
465 }
466
467 #[inline]
468 pub fn clear_render_target_view(
469 &self,
470 rtv: &CpuDescriptorHandle<Rtv>,
471 color: &[f32; 4],
472 rects: Option<&[Rect]>,
473 ) {
474 unsafe {
475 self.cmd_list
476 .ClearRenderTargetView(rtv.handle(), color, rects.map(as_rect_slice));
477 }
478 }
479
480 #[inline]
481 pub fn clear_unordered_access_view<U>(
482 &self,
483 view_gpu_handle_in_current_heap: &GpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
484 view_cpu_handle: &CpuDescriptorHandle<descriptor_heap_type::CbvSrvUav>,
485 resource: &Resource,
486 values: &[U; 4],
487 rects: &[Rect],
488 ) where
489 U: ClearUnorderedAccessView,
490 {
491 U::call(
492 self.cmd_list,
493 view_gpu_handle_in_current_heap,
494 view_cpu_handle,
495 resource,
496 values,
497 rects,
498 );
499 }
500
501 #[inline]
502 pub fn copy_buffer_region(
503 &self,
504 src: &Resource,
505 src_offset: u64,
506 dest: &Resource,
507 dest_offset: u64,
508 num_bytes: u64,
509 ) {
510 unsafe {
511 self.cmd_list.CopyBufferRegion(
512 dest.handle(),
513 dest_offset,
514 src.handle(),
515 src_offset,
516 num_bytes,
517 );
518 }
519 }
520
521 #[inline]
522 pub fn copy_resource(&self, src: &Resource, dest: &Resource) {
523 unsafe {
524 self.cmd_list.CopyResource(dest.handle(), src.handle());
525 }
526 }
527
528 #[inline]
529 pub fn copy_texture_region(
530 &self,
531 src: &TextureCopyLocation,
532 src_box: Option<&D3D12_BOX>,
533 dest: &TextureCopyLocation,
534 dest_x: u32,
535 dest_y: u32,
536 dest_z: u32,
537 ) {
538 unsafe {
539 self.cmd_list.CopyTextureRegion(
540 &dest.0,
541 dest_x,
542 dest_y,
543 dest_z,
544 &src.0,
545 src_box.map(|s| s as *const _),
546 );
547 }
548 }
549
550 #[inline]
551 pub fn dispatch(
552 &self,
553 thread_group_count_x: u32,
554 thread_group_count_y: u32,
555 thread_group_count_z: u32,
556 ) {
557 unsafe {
558 self.cmd_list.Dispatch(
559 thread_group_count_x,
560 thread_group_count_y,
561 thread_group_count_z,
562 );
563 }
564 }
565
566 #[inline]
567 pub fn dispatch_mesh(
568 &self,
569 thread_group_count_x: u32,
570 thread_group_count_y: u32,
571 thread_group_count_z: u32,
572 ) {
573 unsafe {
574 self.cmd_list.DispatchMesh(
575 thread_group_count_x,
576 thread_group_count_y,
577 thread_group_count_z,
578 );
579 }
580 }
581
582 #[inline]
583 pub fn dispatch_rays(&self, desc: &DispatchRaysDesc) {
584 unsafe {
585 self.cmd_list.DispatchRays(&desc.0);
586 }
587 }
588
589 #[inline]
590 pub fn draw_indexed_instanced(
591 &self,
592 index_count_per_instance: u32,
593 instance_count: u32,
594 start_index_location: u32,
595 base_vertex_location: i32,
596 start_instance_location: u32,
597 ) {
598 unsafe {
599 self.cmd_list.DrawIndexedInstanced(
600 index_count_per_instance,
601 instance_count,
602 start_index_location,
603 base_vertex_location,
604 start_instance_location,
605 );
606 }
607 }
608
609 #[inline]
610 pub fn draw_instanced(
611 &self,
612 vertex_count_per_instance: u32,
613 instance_count: u32,
614 start_verte_location: u32,
615 start_instance_location: u32,
616 ) {
617 unsafe {
618 self.cmd_list.DrawInstanced(
619 vertex_count_per_instance,
620 instance_count,
621 start_verte_location,
622 start_instance_location,
623 );
624 }
625 }
626
627 #[inline]
628 pub fn execute_bundle(&self, cmd_list: &GraphicsCommandList<Bundle>) {
629 unsafe {
630 self.cmd_list.ExecuteBundle(&cmd_list.handle);
631 }
632 }
633
634 #[inline]
635 pub fn ia_set_index_buffer(&self, view: Option<&IndexBufferView>) {
636 unsafe {
637 self.cmd_list
638 .IASetIndexBuffer(view.map(|v| v as *const _ as *const D3D12_INDEX_BUFFER_VIEW));
639 }
640 }
641
642 #[inline]
643 pub fn ia_set_primitive_topology(&self, topology: D3D_PRIMITIVE_TOPOLOGY) {
644 unsafe {
645 self.cmd_list.IASetPrimitiveTopology(topology);
646 }
647 }
648
649 #[inline]
650 pub fn ia_set_vertex_buffers(&self, start_slot: u32, views: Option<&[VertexBufferView]>) {
651 unsafe {
652 let views = views.map(|views| {
653 std::slice::from_raw_parts(
654 views.as_ptr() as *const D3D12_VERTEX_BUFFER_VIEW,
655 views.len(),
656 )
657 });
658 self.cmd_list.IASetVertexBuffers(start_slot, views);
659 }
660 }
661
662 #[inline]
663 pub fn om_set_blend_factor(&self, factor: &[f32; 4]) {
664 unsafe {
665 self.cmd_list.OMSetBlendFactor(Some(factor));
666 }
667 }
668
669 #[inline]
670 pub fn om_set_render_targets(
671 &self,
672 rtvs: Option<&[&CpuDescriptorHandle<Rtv>]>,
673 rts_single_handle_to_descriptor_range: bool,
674 depth_stencil: Option<&CpuDescriptorHandle<Dsv>>,
675 ) {
676 let rtvs = rtvs.map(|rtvs| rtvs.iter().map(|rtv| rtv.handle()).collect::<Vec<_>>());
677 let depth_stencil = depth_stencil.map(|ds| ds.handle());
678 unsafe {
679 self.cmd_list.OMSetRenderTargets(
680 rtvs.as_ref().map_or(0, |r| r.len() as u32),
681 rtvs.as_ref().map(|r| r.as_ptr()),
682 rts_single_handle_to_descriptor_range,
683 depth_stencil.as_ref().map(|ds| ds as *const _),
684 );
685 }
686 }
687
688 #[inline]
689 pub fn om_set_stencil_ref(&self, stencil_ref: u32) {
690 unsafe {
691 self.cmd_list.OMSetStencilRef(stencil_ref);
692 }
693 }
694
695 #[inline]
696 pub fn resolve_subresource(
697 &self,
698 src: &Resource,
699 src_subresource: u32,
700 dest: &Resource,
701 dest_resource: u32,
702 format: DXGI_FORMAT,
703 ) {
704 unsafe {
705 self.cmd_list.ResolveSubresource(
706 dest.handle(),
707 dest_resource,
708 src.handle(),
709 src_subresource,
710 format,
711 );
712 }
713 }
714
715 #[inline]
716 pub fn resource_barrier(&self, barriers: &[impl ResourceBarrier]) {
717 let barriers = barriers
718 .iter()
719 .map(|b| b.as_raw().clone())
720 .collect::<Vec<_>>();
721 unsafe {
722 self.cmd_list.ResourceBarrier(&barriers);
723 }
724 }
725
726 #[inline]
727 pub fn rs_set_scissor_rects(&self, rects: &[Rect]) {
728 unsafe {
729 let rects = std::slice::from_raw_parts(
730 rects.as_ptr() as *const windows::Win32::Foundation::RECT,
731 rects.len(),
732 );
733 self.cmd_list.RSSetScissorRects(rects);
734 }
735 }
736
737 #[inline]
738 pub fn rs_set_viewports(&self, viewports: &[Viewport]) {
739 unsafe {
740 let viewports = std::slice::from_raw_parts(
741 viewports.as_ptr() as *const D3D12_VIEWPORT,
742 viewports.len(),
743 );
744 self.cmd_list.RSSetViewports(viewports);
745 }
746 }
747
748 #[inline]
749 pub fn set_descriptor_heaps(
750 &self,
751 cbv_srv_uav: Option<&DescriptorHeap<CbvSrvUav>>,
752 sampler: Option<&DescriptorHeap<Sampler>>,
753 ) {
754 unsafe {
755 #[allow(clippy::unnecessary_unwrap)]
756 if cbv_srv_uav.is_some() && sampler.is_some() {
757 self.cmd_list.SetDescriptorHeaps(&[
758 Some(cbv_srv_uav.unwrap().handle().clone()),
759 Some(sampler.unwrap().handle().clone()),
760 ]);
761 } else if let Some(cbv_srv_uav) = cbv_srv_uav {
762 self.cmd_list
763 .SetDescriptorHeaps(&[Some(cbv_srv_uav.handle().clone())]);
764 } else if let Some(sampler) = sampler {
765 self.cmd_list
766 .SetDescriptorHeaps(&[Some(sampler.handle().clone())]);
767 }
768 }
769 }
770
771 #[inline]
772 pub fn clear_state(&self, state: Option<&PipelineState>) {
773 unsafe {
774 self.cmd_list.ClearState(state.map(|s| s.handle()));
775 }
776 }
777
778 #[inline]
779 pub fn set_pipeline_state(&self, state: &impl PipelineStateType) {
780 state.call(self.cmd_list);
781 }
782
783 #[inline]
784 pub fn set_graphics_root_signature(&self, root_sig: &RootSignature) {
785 unsafe {
786 self.cmd_list.SetGraphicsRootSignature(root_sig.handle());
787 }
788 }
789
790 #[inline]
791 pub fn set_graphics_root_32bit_constants<U>(
792 &self,
793 root_parameter_index: u32,
794 src_data: U,
795 dest_offset_in_32bit_values: u32,
796 ) where
797 U: SetGraphicsRoot32BitConstants,
798 {
799 SetGraphicsRoot32BitConstants::call(
800 src_data,
801 self.cmd_list,
802 root_parameter_index,
803 dest_offset_in_32bit_values,
804 );
805 }
806
807 #[inline]
808 pub fn set_graphics_root_descriptor_table<D>(
809 &self,
810 root_parameter_index: u32,
811 base_descriptor: &GpuDescriptorHandle<D>,
812 ) {
813 unsafe {
814 self.cmd_list
815 .SetGraphicsRootDescriptorTable(root_parameter_index, base_descriptor.handle());
816 }
817 }
818
819 #[inline]
820 pub fn set_graphics_root_constant_buffer_view(
821 &self,
822 root_parameter_index: u32,
823 location: GpuVirtualAddress,
824 ) {
825 unsafe {
826 self.cmd_list
827 .SetGraphicsRootConstantBufferView(root_parameter_index, location.0);
828 }
829 }
830
831 #[inline]
832 pub fn set_graphics_root_shader_resource_view(
833 &self,
834 root_parameter_index: u32,
835 location: GpuVirtualAddress,
836 ) {
837 unsafe {
838 self.cmd_list
839 .SetGraphicsRootShaderResourceView(root_parameter_index, location.0);
840 }
841 }
842
843 #[inline]
844 pub fn set_graphics_root_unordered_access_view(
845 &self,
846 root_parameter_index: u32,
847 location: GpuVirtualAddress,
848 ) {
849 unsafe {
850 self.cmd_list
851 .SetGraphicsRootUnorderedAccessView(root_parameter_index, location.0);
852 }
853 }
854
855 #[inline]
856 pub fn set_compute_root_signature(&self, root_sig: &RootSignature) {
857 unsafe {
858 self.cmd_list.SetComputeRootSignature(root_sig.handle());
859 }
860 }
861
862 #[inline]
863 pub fn set_compute_root_32bit_constants<U>(
864 &self,
865 root_parameter_index: u32,
866 src_data: U,
867 dest_offset_in_32bit_values: u32,
868 ) where
869 U: SetComputeRoot32BitConstants,
870 {
871 SetComputeRoot32BitConstants::call(
872 src_data,
873 self.cmd_list,
874 root_parameter_index,
875 dest_offset_in_32bit_values,
876 );
877 }
878
879 #[inline]
880 pub fn set_compute_root_descriptor_table<D>(
881 &self,
882 root_parameter_index: u32,
883 base_descriptor: &GpuDescriptorHandle<D>,
884 ) {
885 unsafe {
886 self.cmd_list
887 .SetComputeRootDescriptorTable(root_parameter_index, base_descriptor.handle());
888 }
889 }
890
891 #[inline]
892 pub fn set_compute_root_constant_buffer_view(
893 &self,
894 root_parameter_index: u32,
895 location: GpuVirtualAddress,
896 ) {
897 unsafe {
898 self.cmd_list
899 .SetComputeRootConstantBufferView(root_parameter_index, location.0);
900 }
901 }
902
903 #[inline]
904 pub fn set_compute_root_shader_resource_view(
905 &self,
906 root_parameter_index: u32,
907 location: GpuVirtualAddress,
908 ) {
909 unsafe {
910 self.cmd_list
911 .SetComputeRootShaderResourceView(root_parameter_index, location.0);
912 }
913 }
914
915 #[inline]
916 pub fn set_compute_root_unordered_access_view(
917 &self,
918 root_parameter_index: u32,
919 location: GpuVirtualAddress,
920 ) {
921 unsafe {
922 self.cmd_list
923 .SetComputeRootUnorderedAccessView(root_parameter_index, location.0);
924 }
925 }
926
927 #[inline]
928 pub fn so_set_targets(&self, start_slot: u32, views: Option<&[StreamOutputBufferView]>) {
929 unsafe {
930 let views = views.map(|views| {
931 std::slice::from_raw_parts(
932 views.as_ptr() as *const D3D12_STREAM_OUTPUT_BUFFER_VIEW,
933 views.len(),
934 )
935 });
936 self.cmd_list.SOSetTargets(start_slot, views);
937 }
938 }
939
940 #[inline]
941 pub fn build_raytracing_acceleration_structure(
942 &self,
943 desc: &BuildRaytracingAccelerationStructureDesc,
944 ) {
945 unsafe {
946 self.cmd_list
947 .BuildRaytracingAccelerationStructure(&desc.0, None);
948 }
949 }
950}
951
952impl Commands<'_, Direct> {
953 #[inline]
954 pub fn discard_resource(&self, resource: &Resource, region: Option<&DiscardRegion>) {
955 unsafe {
956 self.cmd_list.DiscardResource(
957 resource.handle(),
958 region.map(|r| &r.region as *const D3D12_DISCARD_REGION),
959 );
960 }
961 }
962}
963
964impl Commands<'_, Compute> {
965 #[inline]
966 pub fn discard_resource(&self, resource: &Resource, region: Option<&DiscardRegion>) {
967 unsafe {
968 self.cmd_list.DiscardResource(
969 resource.handle(),
970 region.map(|r| &r.region as *const D3D12_DISCARD_REGION),
971 );
972 }
973 }
974}
975
976impl Commands<'_, Bundle> {}
977
978pub struct Builder<T> {
979 device: ID3D12Device,
980 node_mask: u32,
981 name: Option<String>,
982 _t: std::marker::PhantomData<T>,
983}
984
985impl<T> Builder<T>
986where
987 T: CommandListType,
988{
989 fn new<U>(device: &U) -> Self
990 where
991 U: Into<ID3D12Device> + Clone,
992 {
993 let device: ID3D12Device = device.clone().into();
994 Self {
995 device,
996 node_mask: 0,
997 name: None,
998 _t: std::marker::PhantomData,
999 }
1000 }
1001
1002 #[inline]
1003 pub fn node_mask(mut self, mask: u32) -> Self {
1004 self.node_mask = mask;
1005 self
1006 }
1007
1008 #[inline]
1009 pub fn name(mut self, name: impl AsRef<str>) -> Self {
1010 self.name = Some(name.as_ref().to_string());
1011 self
1012 }
1013
1014 #[inline]
1015 pub fn build(self) -> windows::core::Result<GraphicsCommandList<T>> {
1016 let tmp_allocator: ID3D12CommandAllocator =
1017 unsafe { self.device.CreateCommandAllocator(T::VALUE)? };
1018 let handle: ID3D12GraphicsCommandList7 = unsafe {
1019 self.device
1020 .CreateCommandList(self.node_mask, T::VALUE, &tmp_allocator, None)?
1021 };
1022 let name = self.name.map(|n| Name::new(&handle, n));
1023 unsafe { handle.Close()? };
1024 Ok(GraphicsCommandList {
1025 handle,
1026 name,
1027 _t: std::marker::PhantomData,
1028 })
1029 }
1030}
1031
1032pub trait CommandList<T> {
1033 fn as_raw_command_list(&self) -> ID3D12CommandList;
1034}
1035
1036#[derive(Clone, Debug)]
1037pub struct GraphicsCommandList<T = ()> {
1038 handle: ID3D12GraphicsCommandList7,
1039 name: Option<Name>,
1040 _t: std::marker::PhantomData<T>,
1041}
1042
1043impl GraphicsCommandList<()> {
1044 #[inline]
1045 pub fn new_direct(device: &Device) -> Builder<Direct> {
1046 Builder::new(device.handle())
1047 }
1048
1049 #[inline]
1050 pub fn new_compute(device: &Device) -> Builder<Compute> {
1051 Builder::new(device.handle())
1052 }
1053
1054 #[inline]
1055 pub fn new_bundle(device: &Device) -> Builder<Bundle> {
1056 Builder::new(device.handle())
1057 }
1058
1059 #[inline]
1060 pub fn new_copy(device: &Device) -> Builder<Copy> {
1061 Builder::new(device.handle())
1062 }
1063}
1064
1065impl<T> GraphicsCommandList<T>
1066where
1067 T: CommandListType,
1068{
1069 #[inline]
1070 pub fn record<F, R>(&self, allocator: &CommandAllocator<T>, f: F) -> windows::core::Result<R>
1071 where
1072 F: FnOnce(Commands<T>) -> R,
1073 {
1074 unsafe {
1075 allocator.reset()?;
1076 self.handle.Reset(allocator.handle(), None)?;
1077 let ret = f(Commands {
1078 cmd_list: &self.handle,
1079 _t: std::marker::PhantomData,
1080 });
1081 self.handle.Close()?;
1082 Ok(ret)
1083 }
1084 }
1085
1086 #[inline]
1087 pub fn handle(&self) -> &ID3D12GraphicsCommandList7 {
1088 &self.handle
1089 }
1090
1091 #[inline]
1092 pub fn name(&self) -> Option<&str> {
1093 self.name.as_ref().map(|n| n.as_str())
1094 }
1095
1096 #[inline]
1097 pub fn set_name(&mut self, name: impl AsRef<str>) {
1098 self.name = Some(Name::new(self.handle(), name));
1099 }
1100}
1101
1102impl GraphicsCommandList<command_list_type::Direct> {
1103 #[inline]
1104 #[allow(clippy::new_ret_no_self)]
1105 pub fn new(device: &Device) -> Builder<command_list_type::Direct> {
1106 Builder::new(device.handle())
1107 }
1108}
1109
1110impl GraphicsCommandList<command_list_type::Compute> {
1111 #[inline]
1112 #[allow(clippy::new_ret_no_self)]
1113 pub fn new(device: &Device) -> Builder<command_list_type::Compute> {
1114 Builder::new(device.handle())
1115 }
1116}
1117
1118impl GraphicsCommandList<command_list_type::Bundle> {
1119 #[inline]
1120 #[allow(clippy::new_ret_no_self)]
1121 pub fn new(device: &Device) -> Builder<command_list_type::Bundle> {
1122 Builder::new(device.handle())
1123 }
1124}
1125
1126impl GraphicsCommandList<command_list_type::Copy> {
1127 #[inline]
1128 #[allow(clippy::new_ret_no_self)]
1129 pub fn new(device: &Device) -> Builder<command_list_type::Copy> {
1130 Builder::new(device.handle())
1131 }
1132}
1133
1134impl GraphicsCommandList<command_list_type::VideoDecode> {
1135 #[inline]
1136 #[allow(clippy::new_ret_no_self)]
1137 pub fn new(device: &Device) -> Builder<command_list_type::VideoDecode> {
1138 Builder::new(device.handle())
1139 }
1140}
1141
1142impl GraphicsCommandList<command_list_type::VideoEncode> {
1143 #[inline]
1144 #[allow(clippy::new_ret_no_self)]
1145 pub fn new(device: &Device) -> Builder<command_list_type::VideoEncode> {
1146 Builder::new(device.handle())
1147 }
1148}
1149
1150impl GraphicsCommandList<command_list_type::VideoProcess> {
1151 #[inline]
1152 #[allow(clippy::new_ret_no_self)]
1153 pub fn new(device: &Device) -> Builder<command_list_type::VideoProcess> {
1154 Builder::new(device.handle())
1155 }
1156}
1157
1158impl<T> CommandList<T> for GraphicsCommandList<T>
1159where
1160 T: CommandListType,
1161{
1162 fn as_raw_command_list(&self) -> ID3D12CommandList {
1163 self.handle().cast().unwrap()
1164 }
1165}
1166
1167pub type DirectGraphicsCommandList = GraphicsCommandList<command_list_type::Direct>;
1168pub type ComputeGraphicsCommandList = GraphicsCommandList<command_list_type::Compute>;
1169pub type BundleGraphicsCommandList = GraphicsCommandList<command_list_type::Bundle>;
1170pub type CopyGraphicsCommandList = GraphicsCommandList<command_list_type::Copy>;
1171
1172pub type DirectCommands<'a> = Commands<'a, command_list_type::Direct>;
1173pub type ComputeCommands<'a> = Commands<'a, command_list::Compute>;
1174pub type BundleCommands<'a> = Commands<'a, command_list_type::Bundle>;
1175pub type CopyCommands<'a> = Commands<'a, command_list_type::Copy>;