Skip to main content

dxwr/
command_list.rs

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>;