1 //! Graphics command list
2 
3 use crate::{
4     com::WeakPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format,
5     GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, RootIndex,
6     RootSignature, Subresource, VertexCount, VertexOffset, WorkGroupCount, HRESULT,
7 };
8 use std::{mem, ptr};
9 use winapi::um::d3d12;
10 
11 #[repr(u32)]
12 #[derive(Clone, Copy)]
13 pub enum CmdListType {
14     Direct = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT,
15     Bundle = d3d12::D3D12_COMMAND_LIST_TYPE_BUNDLE,
16     Compute = d3d12::D3D12_COMMAND_LIST_TYPE_COMPUTE,
17     Copy = d3d12::D3D12_COMMAND_LIST_TYPE_COPY,
18     // VideoDecode = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
19     // VideoProcess = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
20 }
21 
22 bitflags! {
23     pub struct ClearFlags: u32 {
24         const DEPTH = d3d12::D3D12_CLEAR_FLAG_DEPTH;
25         const STENCIL = d3d12::D3D12_CLEAR_FLAG_STENCIL;
26     }
27 }
28 
29 #[repr(transparent)]
30 pub struct IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC);
31 
32 impl IndirectArgument {
draw() -> Self33     pub fn draw() -> Self {
34         IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
35             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
36             ..unsafe { mem::zeroed() }
37         })
38     }
39 
draw_indexed() -> Self40     pub fn draw_indexed() -> Self {
41         IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
42             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
43             ..unsafe { mem::zeroed() }
44         })
45     }
46 
dispatch() -> Self47     pub fn dispatch() -> Self {
48         IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
49             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
50             ..unsafe { mem::zeroed() }
51         })
52     }
53 
vertex_buffer(slot: u32) -> Self54     pub fn vertex_buffer(slot: u32) -> Self {
55         let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
56             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW,
57             ..unsafe { mem::zeroed() }
58         };
59         *unsafe { desc.u.VertexBuffer_mut() } =
60             d3d12::D3D12_INDIRECT_ARGUMENT_DESC_VertexBuffer { Slot: slot };
61         IndirectArgument(desc)
62     }
63 
constant(root_index: RootIndex, dest_offset_words: u32, count: u32) -> Self64     pub fn constant(root_index: RootIndex, dest_offset_words: u32, count: u32) -> Self {
65         let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
66             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
67             ..unsafe { mem::zeroed() }
68         };
69         *unsafe { desc.u.Constant_mut() } = d3d12::D3D12_INDIRECT_ARGUMENT_DESC_Constant {
70             RootParameterIndex: root_index,
71             DestOffsetIn32BitValues: dest_offset_words,
72             Num32BitValuesToSet: count,
73         };
74         IndirectArgument(desc)
75     }
76 
constant_buffer_view(root_index: RootIndex) -> Self77     pub fn constant_buffer_view(root_index: RootIndex) -> Self {
78         let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
79             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW,
80             ..unsafe { mem::zeroed() }
81         };
82         *unsafe { desc.u.ConstantBufferView_mut() } =
83             d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ConstantBufferView {
84                 RootParameterIndex: root_index,
85             };
86         IndirectArgument(desc)
87     }
88 
shader_resource_view(root_index: RootIndex) -> Self89     pub fn shader_resource_view(root_index: RootIndex) -> Self {
90         let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
91             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW,
92             ..unsafe { mem::zeroed() }
93         };
94         *unsafe { desc.u.ShaderResourceView_mut() } =
95             d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ShaderResourceView {
96                 RootParameterIndex: root_index,
97             };
98         IndirectArgument(desc)
99     }
100 
unordered_access_view(root_index: RootIndex) -> Self101     pub fn unordered_access_view(root_index: RootIndex) -> Self {
102         let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
103             Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW,
104             ..unsafe { mem::zeroed() }
105         };
106         *unsafe { desc.u.UnorderedAccessView_mut() } =
107             d3d12::D3D12_INDIRECT_ARGUMENT_DESC_UnorderedAccessView {
108                 RootParameterIndex: root_index,
109             };
110         IndirectArgument(desc)
111     }
112 }
113 
114 #[repr(transparent)]
115 pub struct ResourceBarrier(d3d12::D3D12_RESOURCE_BARRIER);
116 
117 impl ResourceBarrier {
transition( resource: Resource, subresource: Subresource, state_before: d3d12::D3D12_RESOURCE_STATES, state_after: d3d12::D3D12_RESOURCE_STATES, flags: d3d12::D3D12_RESOURCE_BARRIER_FLAGS, ) -> Self118     pub fn transition(
119         resource: Resource,
120         subresource: Subresource,
121         state_before: d3d12::D3D12_RESOURCE_STATES,
122         state_after: d3d12::D3D12_RESOURCE_STATES,
123         flags: d3d12::D3D12_RESOURCE_BARRIER_FLAGS,
124     ) -> Self {
125         let mut barrier = d3d12::D3D12_RESOURCE_BARRIER {
126             Type: d3d12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
127             Flags: flags,
128             ..unsafe { mem::zeroed() }
129         };
130         unsafe {
131             *barrier.u.Transition_mut() = d3d12::D3D12_RESOURCE_TRANSITION_BARRIER {
132                 pResource: resource.as_mut_ptr(),
133                 Subresource: subresource,
134                 StateBefore: state_before,
135                 StateAfter: state_after,
136             };
137         }
138         ResourceBarrier(barrier)
139     }
140 }
141 
142 pub type CommandSignature = WeakPtr<d3d12::ID3D12CommandSignature>;
143 pub type CommandList = WeakPtr<d3d12::ID3D12CommandList>;
144 pub type GraphicsCommandList = WeakPtr<d3d12::ID3D12GraphicsCommandList>;
145 
146 impl GraphicsCommandList {
as_list(&self) -> CommandList147     pub fn as_list(&self) -> CommandList {
148         unsafe { CommandList::from_raw(self.as_mut_ptr() as *mut _) }
149     }
150 
close(&self) -> HRESULT151     pub fn close(&self) -> HRESULT {
152         unsafe { self.Close() }
153     }
154 
reset(&self, allocator: CommandAllocator, initial_pso: PipelineState) -> HRESULT155     pub fn reset(&self, allocator: CommandAllocator, initial_pso: PipelineState) -> HRESULT {
156         unsafe { self.Reset(allocator.as_mut_ptr(), initial_pso.as_mut_ptr()) }
157     }
158 
discard_resource(&self, resource: Resource, region: DiscardRegion)159     pub fn discard_resource(&self, resource: Resource, region: DiscardRegion) {
160         debug_assert!(region.subregions.start < region.subregions.end);
161         unsafe {
162             self.DiscardResource(
163                 resource.as_mut_ptr(),
164                 &d3d12::D3D12_DISCARD_REGION {
165                     NumRects: region.rects.len() as _,
166                     pRects: region.rects.as_ptr(),
167                     FirstSubresource: region.subregions.start,
168                     NumSubresources: region.subregions.end - region.subregions.start - 1,
169                 },
170             );
171         }
172     }
173 
clear_depth_stencil_view( &self, dsv: CpuDescriptor, flags: ClearFlags, depth: f32, stencil: u8, rects: &[Rect], )174     pub fn clear_depth_stencil_view(
175         &self,
176         dsv: CpuDescriptor,
177         flags: ClearFlags,
178         depth: f32,
179         stencil: u8,
180         rects: &[Rect],
181     ) {
182         let num_rects = rects.len() as _;
183         let rects = if num_rects > 0 {
184             rects.as_ptr()
185         } else {
186             ptr::null()
187         };
188         unsafe {
189             self.ClearDepthStencilView(dsv, flags.bits(), depth, stencil, num_rects, rects);
190         }
191     }
192 
clear_render_target_view(&self, rtv: CpuDescriptor, color: [f32; 4], rects: &[Rect])193     pub fn clear_render_target_view(&self, rtv: CpuDescriptor, color: [f32; 4], rects: &[Rect]) {
194         let num_rects = rects.len() as _;
195         let rects = if num_rects > 0 {
196             rects.as_ptr()
197         } else {
198             ptr::null()
199         };
200         unsafe {
201             self.ClearRenderTargetView(rtv, &color, num_rects, rects);
202         }
203     }
204 
dispatch(&self, count: WorkGroupCount)205     pub fn dispatch(&self, count: WorkGroupCount) {
206         unsafe {
207             self.Dispatch(count[0], count[1], count[2]);
208         }
209     }
210 
draw( &self, num_vertices: VertexCount, num_instances: InstanceCount, start_vertex: VertexCount, start_instance: InstanceCount, )211     pub fn draw(
212         &self,
213         num_vertices: VertexCount,
214         num_instances: InstanceCount,
215         start_vertex: VertexCount,
216         start_instance: InstanceCount,
217     ) {
218         unsafe {
219             self.DrawInstanced(num_vertices, num_instances, start_vertex, start_instance);
220         }
221     }
222 
draw_indexed( &self, num_indices: IndexCount, num_instances: InstanceCount, start_index: IndexCount, base_vertex: VertexOffset, start_instance: InstanceCount, )223     pub fn draw_indexed(
224         &self,
225         num_indices: IndexCount,
226         num_instances: InstanceCount,
227         start_index: IndexCount,
228         base_vertex: VertexOffset,
229         start_instance: InstanceCount,
230     ) {
231         unsafe {
232             self.DrawIndexedInstanced(
233                 num_indices,
234                 num_instances,
235                 start_index,
236                 base_vertex,
237                 start_instance,
238             );
239         }
240     }
241 
set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format)242     pub fn set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format) {
243         let ibv = d3d12::D3D12_INDEX_BUFFER_VIEW {
244             BufferLocation: gpu_address,
245             SizeInBytes: size,
246             Format: format,
247         };
248         unsafe {
249             self.IASetIndexBuffer(&ibv);
250         }
251     }
252 
set_blend_factor(&self, factor: [f32; 4])253     pub fn set_blend_factor(&self, factor: [f32; 4]) {
254         unsafe {
255             self.OMSetBlendFactor(&factor);
256         }
257     }
258 
set_stencil_reference(&self, reference: u32)259     pub fn set_stencil_reference(&self, reference: u32) {
260         unsafe {
261             self.OMSetStencilRef(reference);
262         }
263     }
264 
set_pipeline_state(&self, pso: PipelineState)265     pub fn set_pipeline_state(&self, pso: PipelineState) {
266         unsafe {
267             self.SetPipelineState(pso.as_mut_ptr());
268         }
269     }
270 
execute_bundle(&self, bundle: GraphicsCommandList)271     pub fn execute_bundle(&self, bundle: GraphicsCommandList) {
272         unsafe {
273             self.ExecuteBundle(bundle.as_mut_ptr());
274         }
275     }
276 
set_descriptor_heaps(&self, heaps: &[DescriptorHeap])277     pub fn set_descriptor_heaps(&self, heaps: &[DescriptorHeap]) {
278         unsafe {
279             self.SetDescriptorHeaps(
280                 heaps.len() as _,
281                 heaps.as_ptr() as *mut &DescriptorHeap as *mut _,
282             );
283         }
284     }
285 
set_compute_root_signature(&self, signature: RootSignature)286     pub fn set_compute_root_signature(&self, signature: RootSignature) {
287         unsafe {
288             self.SetComputeRootSignature(signature.as_mut_ptr());
289         }
290     }
291 
set_graphics_root_signature(&self, signature: RootSignature)292     pub fn set_graphics_root_signature(&self, signature: RootSignature) {
293         unsafe {
294             self.SetGraphicsRootSignature(signature.as_mut_ptr());
295         }
296     }
297 
set_compute_root_descriptor_table( &self, root_index: RootIndex, base_descriptor: GpuDescriptor, )298     pub fn set_compute_root_descriptor_table(
299         &self,
300         root_index: RootIndex,
301         base_descriptor: GpuDescriptor,
302     ) {
303         unsafe {
304             self.SetComputeRootDescriptorTable(root_index, base_descriptor);
305         }
306     }
307 
set_compute_root_constant_buffer_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )308     pub fn set_compute_root_constant_buffer_view(
309         &self,
310         root_index: RootIndex,
311         buffer_location: GpuAddress,
312     ) {
313         unsafe {
314             self.SetComputeRootConstantBufferView(root_index, buffer_location);
315         }
316     }
317 
set_compute_root_shader_resource_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )318     pub fn set_compute_root_shader_resource_view(
319         &self,
320         root_index: RootIndex,
321         buffer_location: GpuAddress,
322     ) {
323         unsafe {
324             self.SetComputeRootShaderResourceView(root_index, buffer_location);
325         }
326     }
327 
set_compute_root_unordered_access_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )328     pub fn set_compute_root_unordered_access_view(
329         &self,
330         root_index: RootIndex,
331         buffer_location: GpuAddress,
332     ) {
333         unsafe {
334             self.SetComputeRootUnorderedAccessView(root_index, buffer_location);
335         }
336     }
337 
set_compute_root_constant( &self, root_index: RootIndex, value: u32, dest_offset_words: u32, )338     pub fn set_compute_root_constant(
339         &self,
340         root_index: RootIndex,
341         value: u32,
342         dest_offset_words: u32,
343     ) {
344         unsafe {
345             self.SetComputeRoot32BitConstant(root_index, value, dest_offset_words);
346         }
347     }
348 
set_graphics_root_descriptor_table( &self, root_index: RootIndex, base_descriptor: GpuDescriptor, )349     pub fn set_graphics_root_descriptor_table(
350         &self,
351         root_index: RootIndex,
352         base_descriptor: GpuDescriptor,
353     ) {
354         unsafe {
355             self.SetGraphicsRootDescriptorTable(root_index, base_descriptor);
356         }
357     }
358 
set_graphics_root_constant_buffer_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )359     pub fn set_graphics_root_constant_buffer_view(
360         &self,
361         root_index: RootIndex,
362         buffer_location: GpuAddress,
363     ) {
364         unsafe {
365             self.SetGraphicsRootConstantBufferView(root_index, buffer_location);
366         }
367     }
368 
set_graphics_root_shader_resource_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )369     pub fn set_graphics_root_shader_resource_view(
370         &self,
371         root_index: RootIndex,
372         buffer_location: GpuAddress,
373     ) {
374         unsafe {
375             self.SetGraphicsRootShaderResourceView(root_index, buffer_location);
376         }
377     }
378 
set_graphics_root_unordered_access_view( &self, root_index: RootIndex, buffer_location: GpuAddress, )379     pub fn set_graphics_root_unordered_access_view(
380         &self,
381         root_index: RootIndex,
382         buffer_location: GpuAddress,
383     ) {
384         unsafe {
385             self.SetGraphicsRootUnorderedAccessView(root_index, buffer_location);
386         }
387     }
388 
set_graphics_root_constant( &self, root_index: RootIndex, value: u32, dest_offset_words: u32, )389     pub fn set_graphics_root_constant(
390         &self,
391         root_index: RootIndex,
392         value: u32,
393         dest_offset_words: u32,
394     ) {
395         unsafe {
396             self.SetGraphicsRoot32BitConstant(root_index, value, dest_offset_words);
397         }
398     }
399 
resource_barrier(&self, barriers: &[ResourceBarrier])400     pub fn resource_barrier(&self, barriers: &[ResourceBarrier]) {
401         unsafe {
402             self.ResourceBarrier(barriers.len() as _, barriers.as_ptr() as _) // matches representation
403         }
404     }
405 }
406