1 use hal::{
2     command,
3     image,
4     pso,
5     pso::{Stage, Viewport},
6 };
7 
8 use winapi::{
9     shared::{
10         dxgiformat,
11         minwindef::{FALSE, TRUE},
12         winerror,
13     },
14     um::{d3d11, d3dcommon},
15 };
16 
17 use wio::com::ComPtr;
18 
19 use std::{borrow::Borrow, mem, ptr};
20 
21 use smallvec::SmallVec;
22 use spirv_cross;
23 
24 use crate::{conv, shader, Buffer, Image, RenderPassCache};
25 
26 #[repr(C)]
27 struct BufferCopy {
28     src: u32,
29     dst: u32,
30     _padding: [u32; 2],
31 }
32 
33 #[repr(C)]
34 struct ImageCopy {
35     src: [u32; 4],
36     dst: [u32; 4],
37 }
38 
39 #[repr(C)]
40 struct BufferImageCopy {
41     buffer_offset: u32,
42     buffer_size: [u32; 2],
43     _padding: u32,
44     image_offset: [u32; 4],
45     image_extent: [u32; 4],
46     // actual size of the target image
47     image_size: [u32; 4],
48 }
49 
50 #[repr(C)]
51 struct BufferImageCopyInfo {
52     buffer: BufferCopy,
53     image: ImageCopy,
54     buffer_image: BufferImageCopy,
55 }
56 
57 #[repr(C)]
58 struct BlitInfo {
59     offset: [f32; 2],
60     extent: [f32; 2],
61     z: f32,
62     level: f32,
63 }
64 
65 #[repr(C)]
66 struct PartialClearInfo {
67     // transmute between the types, easier than juggling all different kinds of fields..
68     data: [u32; 4],
69 }
70 
71 // the threadgroup count we use in our copy shaders
72 const COPY_THREAD_GROUP_X: u32 = 8;
73 const COPY_THREAD_GROUP_Y: u32 = 8;
74 
75 // Holds everything we need for fallback implementations of features that are not in DX.
76 //
77 // TODO: maybe get rid of `Clone`? there's _a lot_ of refcounts here and it is used as a singleton
78 //       anyway :s
79 //
80 // TODO: make struct fields more modular and group them up in structs depending on if it is a
81 //       fallback version or not (eg. Option<PartialClear>), should make struct definition and
82 //       `new` function smaller
83 #[derive(Clone, Debug)]
84 pub struct Internal {
85     // partial clearing
86     vs_partial_clear: ComPtr<d3d11::ID3D11VertexShader>,
87     ps_partial_clear_float: ComPtr<d3d11::ID3D11PixelShader>,
88     ps_partial_clear_uint: ComPtr<d3d11::ID3D11PixelShader>,
89     ps_partial_clear_int: ComPtr<d3d11::ID3D11PixelShader>,
90     ps_partial_clear_depth: ComPtr<d3d11::ID3D11PixelShader>,
91     ps_partial_clear_stencil: ComPtr<d3d11::ID3D11PixelShader>,
92     partial_clear_depth_stencil_state: ComPtr<d3d11::ID3D11DepthStencilState>,
93     partial_clear_depth_state: ComPtr<d3d11::ID3D11DepthStencilState>,
94     partial_clear_stencil_state: ComPtr<d3d11::ID3D11DepthStencilState>,
95 
96     // blitting
97     vs_blit_2d: ComPtr<d3d11::ID3D11VertexShader>,
98 
99     sampler_nearest: ComPtr<d3d11::ID3D11SamplerState>,
100     sampler_linear: ComPtr<d3d11::ID3D11SamplerState>,
101 
102     ps_blit_2d_uint: ComPtr<d3d11::ID3D11PixelShader>,
103     ps_blit_2d_int: ComPtr<d3d11::ID3D11PixelShader>,
104     ps_blit_2d_float: ComPtr<d3d11::ID3D11PixelShader>,
105 
106     // Image<->Image not covered by `CopySubresourceRegion`
107     cs_copy_image2d_r8g8_image2d_r16: ComPtr<d3d11::ID3D11ComputeShader>,
108     cs_copy_image2d_r16_image2d_r8g8: ComPtr<d3d11::ID3D11ComputeShader>,
109 
110     cs_copy_image2d_r8g8b8a8_image2d_r32: ComPtr<d3d11::ID3D11ComputeShader>,
111     cs_copy_image2d_r8g8b8a8_image2d_r16g16: ComPtr<d3d11::ID3D11ComputeShader>,
112     cs_copy_image2d_r16g16_image2d_r32: ComPtr<d3d11::ID3D11ComputeShader>,
113     cs_copy_image2d_r16g16_image2d_r8g8b8a8: ComPtr<d3d11::ID3D11ComputeShader>,
114     cs_copy_image2d_r32_image2d_r16g16: ComPtr<d3d11::ID3D11ComputeShader>,
115     cs_copy_image2d_r32_image2d_r8g8b8a8: ComPtr<d3d11::ID3D11ComputeShader>,
116 
117     // Image -> Buffer
118     cs_copy_image2d_r32g32b32a32_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
119     cs_copy_image2d_r32g32_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
120     cs_copy_image2d_r16g16b16a16_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
121     cs_copy_image2d_r32_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
122     cs_copy_image2d_r16g16_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
123     cs_copy_image2d_r8g8b8a8_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
124     cs_copy_image2d_r16_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
125     cs_copy_image2d_r8g8_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
126     cs_copy_image2d_r8_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
127     cs_copy_image2d_b8g8r8a8_buffer: ComPtr<d3d11::ID3D11ComputeShader>,
128 
129     // Buffer -> Image
130     cs_copy_buffer_image2d_r32g32b32a32: ComPtr<d3d11::ID3D11ComputeShader>,
131     cs_copy_buffer_image2d_r32g32: ComPtr<d3d11::ID3D11ComputeShader>,
132     cs_copy_buffer_image2d_r16g16b16a16: ComPtr<d3d11::ID3D11ComputeShader>,
133     cs_copy_buffer_image2d_r32: ComPtr<d3d11::ID3D11ComputeShader>,
134     cs_copy_buffer_image2d_r16g16: ComPtr<d3d11::ID3D11ComputeShader>,
135     cs_copy_buffer_image2d_r8g8b8a8: ComPtr<d3d11::ID3D11ComputeShader>,
136     cs_copy_buffer_image2d_r16: ComPtr<d3d11::ID3D11ComputeShader>,
137     cs_copy_buffer_image2d_r8g8: ComPtr<d3d11::ID3D11ComputeShader>,
138     cs_copy_buffer_image2d_r8: ComPtr<d3d11::ID3D11ComputeShader>,
139 
140     // internal constant buffer that is used by internal shaders
141     internal_buffer: ComPtr<d3d11::ID3D11Buffer>,
142 
143     // public buffer that is used as intermediate storage for some operations (memory invalidation)
144     pub working_buffer: ComPtr<d3d11::ID3D11Buffer>,
145     pub working_buffer_size: u64,
146 }
147 
compile_blob(src: &[u8], entrypoint: &str, stage: Stage) -> ComPtr<d3dcommon::ID3DBlob>148 fn compile_blob(src: &[u8], entrypoint: &str, stage: Stage) -> ComPtr<d3dcommon::ID3DBlob> {
149     unsafe {
150         ComPtr::from_raw(
151             shader::compile_hlsl_shader(
152                 stage,
153                 spirv_cross::hlsl::ShaderModel::V5_0,
154                 entrypoint,
155                 src,
156             )
157             .unwrap(),
158         )
159     }
160 }
161 
compile_vs( device: &ComPtr<d3d11::ID3D11Device>, src: &[u8], entrypoint: &str, ) -> ComPtr<d3d11::ID3D11VertexShader>162 fn compile_vs(
163     device: &ComPtr<d3d11::ID3D11Device>,
164     src: &[u8],
165     entrypoint: &str,
166 ) -> ComPtr<d3d11::ID3D11VertexShader> {
167     let bytecode = compile_blob(src, entrypoint, Stage::Vertex);
168     let mut shader = ptr::null_mut();
169     let hr = unsafe {
170         device.CreateVertexShader(
171             bytecode.GetBufferPointer(),
172             bytecode.GetBufferSize(),
173             ptr::null_mut(),
174             &mut shader as *mut *mut _ as *mut *mut _,
175         )
176     };
177     assert_eq!(true, winerror::SUCCEEDED(hr));
178 
179     unsafe { ComPtr::from_raw(shader) }
180 }
181 
compile_ps( device: &ComPtr<d3d11::ID3D11Device>, src: &[u8], entrypoint: &str, ) -> ComPtr<d3d11::ID3D11PixelShader>182 fn compile_ps(
183     device: &ComPtr<d3d11::ID3D11Device>,
184     src: &[u8],
185     entrypoint: &str,
186 ) -> ComPtr<d3d11::ID3D11PixelShader> {
187     let bytecode = compile_blob(src, entrypoint, Stage::Fragment);
188     let mut shader = ptr::null_mut();
189     let hr = unsafe {
190         device.CreatePixelShader(
191             bytecode.GetBufferPointer(),
192             bytecode.GetBufferSize(),
193             ptr::null_mut(),
194             &mut shader as *mut *mut _ as *mut *mut _,
195         )
196     };
197     assert_eq!(true, winerror::SUCCEEDED(hr));
198 
199     unsafe { ComPtr::from_raw(shader) }
200 }
201 
compile_cs( device: &ComPtr<d3d11::ID3D11Device>, src: &[u8], entrypoint: &str, ) -> ComPtr<d3d11::ID3D11ComputeShader>202 fn compile_cs(
203     device: &ComPtr<d3d11::ID3D11Device>,
204     src: &[u8],
205     entrypoint: &str,
206 ) -> ComPtr<d3d11::ID3D11ComputeShader> {
207     let bytecode = compile_blob(src, entrypoint, Stage::Compute);
208     let mut shader = ptr::null_mut();
209     let hr = unsafe {
210         device.CreateComputeShader(
211             bytecode.GetBufferPointer(),
212             bytecode.GetBufferSize(),
213             ptr::null_mut(),
214             &mut shader as *mut *mut _ as *mut *mut _,
215         )
216     };
217     assert_eq!(true, winerror::SUCCEEDED(hr));
218 
219     unsafe { ComPtr::from_raw(shader) }
220 }
221 
222 impl Internal {
new(device: &ComPtr<d3d11::ID3D11Device>) -> Self223     pub fn new(device: &ComPtr<d3d11::ID3D11Device>) -> Self {
224         let internal_buffer = {
225             let desc = d3d11::D3D11_BUFFER_DESC {
226                 ByteWidth: mem::size_of::<BufferImageCopyInfo>() as _,
227                 Usage: d3d11::D3D11_USAGE_DYNAMIC,
228                 BindFlags: d3d11::D3D11_BIND_CONSTANT_BUFFER,
229                 CPUAccessFlags: d3d11::D3D11_CPU_ACCESS_WRITE,
230                 MiscFlags: 0,
231                 StructureByteStride: 0,
232             };
233 
234             let mut buffer = ptr::null_mut();
235             let hr = unsafe {
236                 device.CreateBuffer(
237                     &desc,
238                     ptr::null_mut(),
239                     &mut buffer as *mut *mut _ as *mut *mut _,
240                 )
241             };
242             assert_eq!(true, winerror::SUCCEEDED(hr));
243 
244             unsafe { ComPtr::from_raw(buffer) }
245         };
246 
247         let (depth_stencil_state, depth_state, stencil_state) = {
248             let mut depth_state = ptr::null_mut();
249             let mut stencil_state = ptr::null_mut();
250             let mut depth_stencil_state = ptr::null_mut();
251 
252             let mut desc = d3d11::D3D11_DEPTH_STENCIL_DESC {
253                 DepthEnable: TRUE,
254                 DepthWriteMask: d3d11::D3D11_DEPTH_WRITE_MASK_ALL,
255                 DepthFunc: d3d11::D3D11_COMPARISON_ALWAYS,
256                 StencilEnable: TRUE,
257                 StencilReadMask: 0,
258                 StencilWriteMask: !0,
259                 FrontFace: d3d11::D3D11_DEPTH_STENCILOP_DESC {
260                     StencilFailOp: d3d11::D3D11_STENCIL_OP_REPLACE,
261                     StencilDepthFailOp: d3d11::D3D11_STENCIL_OP_REPLACE,
262                     StencilPassOp: d3d11::D3D11_STENCIL_OP_REPLACE,
263                     StencilFunc: d3d11::D3D11_COMPARISON_ALWAYS,
264                 },
265                 BackFace: d3d11::D3D11_DEPTH_STENCILOP_DESC {
266                     StencilFailOp: d3d11::D3D11_STENCIL_OP_REPLACE,
267                     StencilDepthFailOp: d3d11::D3D11_STENCIL_OP_REPLACE,
268                     StencilPassOp: d3d11::D3D11_STENCIL_OP_REPLACE,
269                     StencilFunc: d3d11::D3D11_COMPARISON_ALWAYS,
270                 },
271             };
272 
273             let hr = unsafe {
274                 device.CreateDepthStencilState(
275                     &desc,
276                     &mut depth_stencil_state as *mut *mut _ as *mut *mut _,
277                 )
278             };
279             assert_eq!(winerror::S_OK, hr);
280 
281             desc.DepthEnable = TRUE;
282             desc.StencilEnable = FALSE;
283 
284             let hr = unsafe {
285                 device
286                     .CreateDepthStencilState(&desc, &mut depth_state as *mut *mut _ as *mut *mut _)
287             };
288             assert_eq!(winerror::S_OK, hr);
289 
290             desc.DepthEnable = FALSE;
291             desc.StencilEnable = TRUE;
292 
293             let hr = unsafe {
294                 device.CreateDepthStencilState(
295                     &desc,
296                     &mut stencil_state as *mut *mut _ as *mut *mut _,
297                 )
298             };
299             assert_eq!(winerror::S_OK, hr);
300 
301             unsafe {
302                 (
303                     ComPtr::from_raw(depth_stencil_state),
304                     ComPtr::from_raw(depth_state),
305                     ComPtr::from_raw(stencil_state),
306                 )
307             }
308         };
309 
310         let (sampler_nearest, sampler_linear) = {
311             let mut desc = d3d11::D3D11_SAMPLER_DESC {
312                 Filter: d3d11::D3D11_FILTER_MIN_MAG_MIP_POINT,
313                 AddressU: d3d11::D3D11_TEXTURE_ADDRESS_CLAMP,
314                 AddressV: d3d11::D3D11_TEXTURE_ADDRESS_CLAMP,
315                 AddressW: d3d11::D3D11_TEXTURE_ADDRESS_CLAMP,
316                 MipLODBias: 0f32,
317                 MaxAnisotropy: 0,
318                 ComparisonFunc: 0,
319                 BorderColor: [0f32; 4],
320                 MinLOD: 0f32,
321                 MaxLOD: d3d11::D3D11_FLOAT32_MAX,
322             };
323 
324             let mut nearest = ptr::null_mut();
325             let mut linear = ptr::null_mut();
326 
327             assert_eq!(winerror::S_OK, unsafe {
328                 device.CreateSamplerState(&desc, &mut nearest as *mut *mut _ as *mut *mut _)
329             });
330 
331             desc.Filter = d3d11::D3D11_FILTER_MIN_MAG_MIP_LINEAR;
332 
333             assert_eq!(winerror::S_OK, unsafe {
334                 device.CreateSamplerState(&desc, &mut linear as *mut *mut _ as *mut *mut _)
335             });
336 
337             unsafe { (ComPtr::from_raw(nearest), ComPtr::from_raw(linear)) }
338         };
339 
340         let (working_buffer, working_buffer_size) = {
341             let working_buffer_size = 1 << 16;
342 
343             let desc = d3d11::D3D11_BUFFER_DESC {
344                 ByteWidth: working_buffer_size,
345                 Usage: d3d11::D3D11_USAGE_STAGING,
346                 BindFlags: 0,
347                 CPUAccessFlags: d3d11::D3D11_CPU_ACCESS_READ | d3d11::D3D11_CPU_ACCESS_WRITE,
348                 MiscFlags: 0,
349                 StructureByteStride: 0,
350             };
351             let mut working_buffer = ptr::null_mut();
352 
353             assert_eq!(winerror::S_OK, unsafe {
354                 device.CreateBuffer(
355                     &desc,
356                     ptr::null_mut(),
357                     &mut working_buffer as *mut *mut _ as *mut *mut _,
358                 )
359             });
360 
361             (
362                 unsafe { ComPtr::from_raw(working_buffer) },
363                 working_buffer_size,
364             )
365         };
366 
367         let clear_shaders = include_bytes!("../shaders/clear.hlsl");
368         let copy_shaders = include_bytes!("../shaders/copy.hlsl");
369         let blit_shaders = include_bytes!("../shaders/blit.hlsl");
370 
371         Internal {
372             vs_partial_clear: compile_vs(device, clear_shaders, "vs_partial_clear"),
373             ps_partial_clear_float: compile_ps(device, clear_shaders, "ps_partial_clear_float"),
374             ps_partial_clear_uint: compile_ps(device, clear_shaders, "ps_partial_clear_uint"),
375             ps_partial_clear_int: compile_ps(device, clear_shaders, "ps_partial_clear_int"),
376             ps_partial_clear_depth: compile_ps(device, clear_shaders, "ps_partial_clear_depth"),
377             ps_partial_clear_stencil: compile_ps(device, clear_shaders, "ps_partial_clear_stencil"),
378             partial_clear_depth_stencil_state: depth_stencil_state,
379             partial_clear_depth_state: depth_state,
380             partial_clear_stencil_state: stencil_state,
381 
382             vs_blit_2d: compile_vs(device, blit_shaders, "vs_blit_2d"),
383 
384             sampler_nearest,
385             sampler_linear,
386 
387             ps_blit_2d_uint: compile_ps(device, blit_shaders, "ps_blit_2d_uint"),
388             ps_blit_2d_int: compile_ps(device, blit_shaders, "ps_blit_2d_int"),
389             ps_blit_2d_float: compile_ps(device, blit_shaders, "ps_blit_2d_float"),
390 
391             cs_copy_image2d_r8g8_image2d_r16: compile_cs(
392                 device,
393                 copy_shaders,
394                 "cs_copy_image2d_r8g8_image2d_r16",
395             ),
396             cs_copy_image2d_r16_image2d_r8g8: compile_cs(
397                 device,
398                 copy_shaders,
399                 "cs_copy_image2d_r16_image2d_r8g8",
400             ),
401 
402             cs_copy_image2d_r8g8b8a8_image2d_r32: compile_cs(
403                 device,
404                 copy_shaders,
405                 "cs_copy_image2d_r8g8b8a8_image2d_r32",
406             ),
407             cs_copy_image2d_r8g8b8a8_image2d_r16g16: compile_cs(
408                 device,
409                 copy_shaders,
410                 "cs_copy_image2d_r8g8b8a8_image2d_r16g16",
411             ),
412             cs_copy_image2d_r16g16_image2d_r32: compile_cs(
413                 device,
414                 copy_shaders,
415                 "cs_copy_image2d_r16g16_image2d_r32",
416             ),
417             cs_copy_image2d_r16g16_image2d_r8g8b8a8: compile_cs(
418                 device,
419                 copy_shaders,
420                 "cs_copy_image2d_r16g16_image2d_r8g8b8a8",
421             ),
422             cs_copy_image2d_r32_image2d_r16g16: compile_cs(
423                 device,
424                 copy_shaders,
425                 "cs_copy_image2d_r32_image2d_r16g16",
426             ),
427             cs_copy_image2d_r32_image2d_r8g8b8a8: compile_cs(
428                 device,
429                 copy_shaders,
430                 "cs_copy_image2d_r32_image2d_r8g8b8a8",
431             ),
432 
433             cs_copy_image2d_r32g32b32a32_buffer: compile_cs(
434                 device,
435                 copy_shaders,
436                 "cs_copy_image2d_r32g32b32a32_buffer",
437             ),
438             cs_copy_image2d_r32g32_buffer: compile_cs(
439                 device,
440                 copy_shaders,
441                 "cs_copy_image2d_r32g32_buffer",
442             ),
443             cs_copy_image2d_r16g16b16a16_buffer: compile_cs(
444                 device,
445                 copy_shaders,
446                 "cs_copy_image2d_r16g16b16a16_buffer",
447             ),
448             cs_copy_image2d_r32_buffer: compile_cs(
449                 device,
450                 copy_shaders,
451                 "cs_copy_image2d_r32_buffer",
452             ),
453             cs_copy_image2d_r16g16_buffer: compile_cs(
454                 device,
455                 copy_shaders,
456                 "cs_copy_image2d_r16g16_buffer",
457             ),
458             cs_copy_image2d_r8g8b8a8_buffer: compile_cs(
459                 device,
460                 copy_shaders,
461                 "cs_copy_image2d_r8g8b8a8_buffer",
462             ),
463             cs_copy_image2d_r16_buffer: compile_cs(
464                 device,
465                 copy_shaders,
466                 "cs_copy_image2d_r16_buffer",
467             ),
468             cs_copy_image2d_r8g8_buffer: compile_cs(
469                 device,
470                 copy_shaders,
471                 "cs_copy_image2d_r8g8_buffer",
472             ),
473             cs_copy_image2d_r8_buffer: compile_cs(
474                 device,
475                 copy_shaders,
476                 "cs_copy_image2d_r8_buffer",
477             ),
478             cs_copy_image2d_b8g8r8a8_buffer: compile_cs(
479                 device,
480                 copy_shaders,
481                 "cs_copy_image2d_b8g8r8a8_buffer",
482             ),
483 
484             cs_copy_buffer_image2d_r32g32b32a32: compile_cs(
485                 device,
486                 copy_shaders,
487                 "cs_copy_buffer_image2d_r32g32b32a32",
488             ),
489             cs_copy_buffer_image2d_r32g32: compile_cs(
490                 device,
491                 copy_shaders,
492                 "cs_copy_buffer_image2d_r32g32",
493             ),
494             cs_copy_buffer_image2d_r16g16b16a16: compile_cs(
495                 device,
496                 copy_shaders,
497                 "cs_copy_buffer_image2d_r16g16b16a16",
498             ),
499             cs_copy_buffer_image2d_r32: compile_cs(
500                 device,
501                 copy_shaders,
502                 "cs_copy_buffer_image2d_r32",
503             ),
504             cs_copy_buffer_image2d_r16g16: compile_cs(
505                 device,
506                 copy_shaders,
507                 "cs_copy_buffer_image2d_r16g16",
508             ),
509             cs_copy_buffer_image2d_r8g8b8a8: compile_cs(
510                 device,
511                 copy_shaders,
512                 "cs_copy_buffer_image2d_r8g8b8a8",
513             ),
514             cs_copy_buffer_image2d_r16: compile_cs(
515                 device,
516                 copy_shaders,
517                 "cs_copy_buffer_image2d_r16",
518             ),
519             cs_copy_buffer_image2d_r8g8: compile_cs(
520                 device,
521                 copy_shaders,
522                 "cs_copy_buffer_image2d_r8g8",
523             ),
524             cs_copy_buffer_image2d_r8: compile_cs(
525                 device,
526                 copy_shaders,
527                 "cs_copy_buffer_image2d_r8",
528             ),
529 
530             internal_buffer,
531             working_buffer,
532             working_buffer_size: working_buffer_size as _,
533         }
534     }
535 
map(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) -> *mut u8536     fn map(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) -> *mut u8 {
537         let mut mapped = unsafe { mem::zeroed::<d3d11::D3D11_MAPPED_SUBRESOURCE>() };
538         let hr = unsafe {
539             context.Map(
540                 self.internal_buffer.as_raw() as _,
541                 0,
542                 d3d11::D3D11_MAP_WRITE_DISCARD,
543                 0,
544                 &mut mapped,
545             )
546         };
547 
548         assert_eq!(winerror::S_OK, hr);
549 
550         mapped.pData as _
551     }
552 
unmap(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)553     fn unmap(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
554         unsafe {
555             context.Unmap(self.internal_buffer.as_raw() as _, 0);
556         }
557     }
558 
update_image( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, info: &command::ImageCopy, )559     fn update_image(
560         &mut self,
561         context: &ComPtr<d3d11::ID3D11DeviceContext>,
562         info: &command::ImageCopy,
563     ) {
564         unsafe {
565             ptr::copy(
566                 &BufferImageCopyInfo {
567                     image: ImageCopy {
568                         src: [
569                             info.src_offset.x as _,
570                             info.src_offset.y as _,
571                             info.src_offset.z as _,
572                             0,
573                         ],
574                         dst: [
575                             info.dst_offset.x as _,
576                             info.dst_offset.y as _,
577                             info.dst_offset.z as _,
578                             0,
579                         ],
580                     },
581                     ..mem::zeroed()
582                 },
583                 self.map(context) as *mut _,
584                 1,
585             )
586         };
587 
588         self.unmap(context);
589     }
590 
update_buffer_image( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, info: &command::BufferImageCopy, image: &Image, )591     fn update_buffer_image(
592         &mut self,
593         context: &ComPtr<d3d11::ID3D11DeviceContext>,
594         info: &command::BufferImageCopy,
595         image: &Image,
596     ) {
597         let size = image.kind.extent();
598 
599         unsafe {
600             ptr::copy(
601                 &BufferImageCopyInfo {
602                     buffer_image: BufferImageCopy {
603                         buffer_offset: info.buffer_offset as _,
604                         buffer_size: [info.buffer_width, info.buffer_height],
605                         _padding: 0,
606                         image_offset: [
607                             info.image_offset.x as _,
608                             info.image_offset.y as _,
609                             (info.image_offset.z + info.image_layers.layers.start as i32) as _,
610                             0,
611                         ],
612                         image_extent: [
613                             info.image_extent.width,
614                             info.image_extent.height,
615                             info.image_extent.depth,
616                             0,
617                         ],
618                         image_size: [size.width, size.height, size.depth, 0],
619                     },
620                     ..mem::zeroed()
621                 },
622                 self.map(context) as *mut _,
623                 1,
624             )
625         };
626 
627         self.unmap(context);
628     }
629 
update_blit( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, src: &Image, info: &command::ImageBlit, )630     fn update_blit(
631         &mut self,
632         context: &ComPtr<d3d11::ID3D11DeviceContext>,
633         src: &Image,
634         info: &command::ImageBlit,
635     ) {
636         let (sx, dx) = if info.dst_bounds.start.x > info.dst_bounds.end.x {
637             (
638                 info.src_bounds.end.x,
639                 info.src_bounds.start.x - info.src_bounds.end.x,
640             )
641         } else {
642             (
643                 info.src_bounds.start.x,
644                 info.src_bounds.end.x - info.src_bounds.start.x,
645             )
646         };
647         let (sy, dy) = if info.dst_bounds.start.y > info.dst_bounds.end.y {
648             (
649                 info.src_bounds.end.y,
650                 info.src_bounds.start.y - info.src_bounds.end.y,
651             )
652         } else {
653             (
654                 info.src_bounds.start.y,
655                 info.src_bounds.end.y - info.src_bounds.start.y,
656             )
657         };
658         let image::Extent { width, height, .. } = src.kind.level_extent(info.src_subresource.level);
659 
660         unsafe {
661             ptr::copy(
662                 &BlitInfo {
663                     offset: [sx as f32 / width as f32, sy as f32 / height as f32],
664                     extent: [dx as f32 / width as f32, dy as f32 / height as f32],
665                     z: 0f32, // TODO
666                     level: info.src_subresource.level as _,
667                 },
668                 self.map(context) as *mut _,
669                 1,
670             )
671         };
672 
673         self.unmap(context);
674     }
675 
update_clear_color( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, value: command::ClearColor, )676     fn update_clear_color(
677         &mut self,
678         context: &ComPtr<d3d11::ID3D11DeviceContext>,
679         value: command::ClearColor,
680     ) {
681         unsafe {
682             ptr::copy(
683                 &PartialClearInfo {
684                     data: mem::transmute(value),
685                 },
686                 self.map(context) as *mut _,
687                 1,
688             )
689         };
690 
691         self.unmap(context);
692     }
693 
update_clear_depth_stencil( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, depth: Option<f32>, stencil: Option<u32>, )694     fn update_clear_depth_stencil(
695         &mut self,
696         context: &ComPtr<d3d11::ID3D11DeviceContext>,
697         depth: Option<f32>,
698         stencil: Option<u32>,
699     ) {
700         unsafe {
701             ptr::copy(
702                 &PartialClearInfo {
703                     data: [
704                         mem::transmute(depth.unwrap_or(0f32)),
705                         stencil.unwrap_or(0),
706                         0,
707                         0,
708                     ],
709                 },
710                 self.map(context) as *mut _,
711                 1,
712             );
713         }
714 
715         self.unmap(context);
716     }
717 
find_image_copy_shader( &self, src: &Image, dst: &Image, ) -> Option<*mut d3d11::ID3D11ComputeShader>718     fn find_image_copy_shader(
719         &self,
720         src: &Image,
721         dst: &Image,
722     ) -> Option<*mut d3d11::ID3D11ComputeShader> {
723         use dxgiformat::*;
724 
725         let src_format = src.decomposed_format.copy_srv.unwrap();
726         let dst_format = dst.decomposed_format.copy_uav.unwrap();
727 
728         match (src_format, dst_format) {
729             (DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R16_UINT) => {
730                 Some(self.cs_copy_image2d_r8g8_image2d_r16.as_raw())
731             }
732             (DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R8G8_UINT) => {
733                 Some(self.cs_copy_image2d_r16_image2d_r8g8.as_raw())
734             }
735             (DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R32_UINT) => {
736                 Some(self.cs_copy_image2d_r8g8b8a8_image2d_r32.as_raw())
737             }
738             (DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R16G16_UINT) => {
739                 Some(self.cs_copy_image2d_r8g8b8a8_image2d_r16g16.as_raw())
740             }
741             (DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R32_UINT) => {
742                 Some(self.cs_copy_image2d_r16g16_image2d_r32.as_raw())
743             }
744             (DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R8G8B8A8_UINT) => {
745                 Some(self.cs_copy_image2d_r16g16_image2d_r8g8b8a8.as_raw())
746             }
747             (DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R16G16_UINT) => {
748                 Some(self.cs_copy_image2d_r32_image2d_r16g16.as_raw())
749             }
750             (DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R8G8B8A8_UINT) => {
751                 Some(self.cs_copy_image2d_r32_image2d_r8g8b8a8.as_raw())
752             }
753             _ => None,
754         }
755     }
756 
copy_image_2d<T>( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, src: &Image, dst: &Image, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::ImageCopy>,757     pub fn copy_image_2d<T>(
758         &mut self,
759         context: &ComPtr<d3d11::ID3D11DeviceContext>,
760         src: &Image,
761         dst: &Image,
762         regions: T,
763     ) where
764         T: IntoIterator,
765         T::Item: Borrow<command::ImageCopy>,
766     {
767         if let Some(shader) = self.find_image_copy_shader(src, dst) {
768             // Some formats cant go through default path, since they cant
769             // be cast between formats of different component types (eg.
770             // Rg16 <-> Rgba8)
771 
772             // TODO: subresources
773             let srv = src.internal.copy_srv.clone().unwrap().as_raw();
774 
775             unsafe {
776                 context.CSSetShader(shader, ptr::null_mut(), 0);
777                 context.CSSetConstantBuffers(0, 1, &self.internal_buffer.as_raw());
778                 context.CSSetShaderResources(0, 1, [srv].as_ptr());
779 
780                 for region in regions.into_iter() {
781                     let info = region.borrow();
782                     self.update_image(context, &info);
783 
784                     let uav = dst.get_uav(info.dst_subresource.level, 0).unwrap().as_raw();
785                     context.CSSetUnorderedAccessViews(0, 1, [uav].as_ptr(), ptr::null_mut());
786 
787                     context.Dispatch(info.extent.width as u32, info.extent.height as u32, 1);
788                 }
789 
790                 // unbind external resources
791                 context.CSSetShaderResources(0, 1, [ptr::null_mut(); 1].as_ptr());
792                 context.CSSetUnorderedAccessViews(
793                     0,
794                     1,
795                     [ptr::null_mut(); 1].as_ptr(),
796                     ptr::null_mut(),
797                 );
798             }
799         } else {
800             // Default copy path
801             for region in regions.into_iter() {
802                 let info = region.borrow();
803 
804                 // TODO: layer subresources
805                 unsafe {
806                     context.CopySubresourceRegion(
807                         dst.internal.raw,
808                         src.calc_subresource(info.src_subresource.level as _, 0),
809                         info.dst_offset.x as _,
810                         info.dst_offset.y as _,
811                         info.dst_offset.z as _,
812                         src.internal.raw,
813                         dst.calc_subresource(info.dst_subresource.level as _, 0),
814                         &d3d11::D3D11_BOX {
815                             left: info.src_offset.x as _,
816                             top: info.src_offset.y as _,
817                             front: info.src_offset.z as _,
818                             right: info.src_offset.x as u32 + info.extent.width as u32,
819                             bottom: info.src_offset.y as u32 + info.extent.height as u32,
820                             back: info.src_offset.z as u32 + info.extent.depth as u32,
821                         },
822                     );
823                 }
824             }
825         }
826     }
827 
find_image_to_buffer_shader( &self, format: dxgiformat::DXGI_FORMAT, ) -> Option<(*mut d3d11::ID3D11ComputeShader, u32, u32)>828     fn find_image_to_buffer_shader(
829         &self,
830         format: dxgiformat::DXGI_FORMAT,
831     ) -> Option<(*mut d3d11::ID3D11ComputeShader, u32, u32)> {
832         use dxgiformat::*;
833 
834         match format {
835             DXGI_FORMAT_R32G32B32A32_UINT => {
836                 Some((self.cs_copy_image2d_r32g32b32a32_buffer.as_raw(), 1, 1))
837             }
838             DXGI_FORMAT_R32G32_UINT => Some((self.cs_copy_image2d_r32g32_buffer.as_raw(), 1, 1)),
839             DXGI_FORMAT_R16G16B16A16_UINT => {
840                 Some((self.cs_copy_image2d_r16g16b16a16_buffer.as_raw(), 1, 1))
841             }
842             DXGI_FORMAT_R32_UINT => Some((self.cs_copy_image2d_r32_buffer.as_raw(), 1, 1)),
843             DXGI_FORMAT_R16G16_UINT => Some((self.cs_copy_image2d_r16g16_buffer.as_raw(), 1, 1)),
844             DXGI_FORMAT_R8G8B8A8_UINT => {
845                 Some((self.cs_copy_image2d_r8g8b8a8_buffer.as_raw(), 1, 1))
846             }
847             DXGI_FORMAT_R16_UINT => Some((self.cs_copy_image2d_r16_buffer.as_raw(), 2, 1)),
848             DXGI_FORMAT_R8G8_UINT => Some((self.cs_copy_image2d_r8g8_buffer.as_raw(), 2, 1)),
849             DXGI_FORMAT_R8_UINT => Some((self.cs_copy_image2d_r8_buffer.as_raw(), 4, 1)),
850             DXGI_FORMAT_B8G8R8A8_UNORM => {
851                 Some((self.cs_copy_image2d_b8g8r8a8_buffer.as_raw(), 1, 1))
852             }
853             _ => None,
854         }
855     }
856 
copy_image_2d_to_buffer<T>( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, src: &Image, dst: &Buffer, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::BufferImageCopy>,857     pub fn copy_image_2d_to_buffer<T>(
858         &mut self,
859         context: &ComPtr<d3d11::ID3D11DeviceContext>,
860         src: &Image,
861         dst: &Buffer,
862         regions: T,
863     ) where
864         T: IntoIterator,
865         T::Item: Borrow<command::BufferImageCopy>,
866     {
867         let _scope = debug_scope!(
868             context,
869             "Image (format={:?},kind={:?}) => Buffer",
870             src.format,
871             src.kind
872         );
873         let (shader, scale_x, scale_y) = self
874             .find_image_to_buffer_shader(src.decomposed_format.copy_srv.unwrap())
875             .unwrap();
876 
877         let srv = src.internal.copy_srv.clone().unwrap().as_raw();
878         let uav = dst.internal.uav.unwrap();
879         let format_desc = src.format.base_format().0.desc();
880         let bytes_per_texel = format_desc.bits as u32 / 8;
881 
882         unsafe {
883             context.CSSetShader(shader, ptr::null_mut(), 0);
884             context.CSSetConstantBuffers(0, 1, &self.internal_buffer.as_raw());
885 
886             context.CSSetShaderResources(0, 1, [srv].as_ptr());
887             context.CSSetUnorderedAccessViews(0, 1, [uav].as_ptr(), ptr::null_mut());
888 
889             for copy in regions {
890                 let copy = copy.borrow();
891                 self.update_buffer_image(context, &copy, src);
892 
893                 debug_marker!(context, "{:?}", copy);
894 
895                 context.Dispatch(
896                     ((copy.image_extent.width + (COPY_THREAD_GROUP_X - 1))
897                         / COPY_THREAD_GROUP_X
898                         / scale_x)
899                         .max(1),
900                     ((copy.image_extent.height + (COPY_THREAD_GROUP_X - 1))
901                         / COPY_THREAD_GROUP_Y
902                         / scale_y)
903                         .max(1),
904                     1,
905                 );
906 
907                 if let Some(disjoint_cb) = dst.internal.disjoint_cb {
908                     let total_size = copy.image_extent.depth
909                         * (copy.buffer_height * copy.buffer_width * bytes_per_texel);
910                     let copy_box = d3d11::D3D11_BOX {
911                         left: copy.buffer_offset as u32,
912                         top: 0,
913                         front: 0,
914                         right: copy.buffer_offset as u32 + total_size,
915                         bottom: 1,
916                         back: 1,
917                     };
918 
919                     context.CopySubresourceRegion(
920                         disjoint_cb as _,
921                         0,
922                         copy.buffer_offset as _,
923                         0,
924                         0,
925                         dst.internal.raw as _,
926                         0,
927                         &copy_box,
928                     );
929                 }
930             }
931 
932             // unbind external resources
933             context.CSSetShaderResources(0, 1, [ptr::null_mut(); 1].as_ptr());
934             context.CSSetUnorderedAccessViews(0, 1, [ptr::null_mut(); 1].as_ptr(), ptr::null_mut());
935         }
936     }
937 
find_buffer_to_image_shader( &self, format: dxgiformat::DXGI_FORMAT, ) -> Option<(*mut d3d11::ID3D11ComputeShader, u32, u32)>938     fn find_buffer_to_image_shader(
939         &self,
940         format: dxgiformat::DXGI_FORMAT,
941     ) -> Option<(*mut d3d11::ID3D11ComputeShader, u32, u32)> {
942         use dxgiformat::*;
943 
944         match format {
945             DXGI_FORMAT_R32G32B32A32_UINT => {
946                 Some((self.cs_copy_buffer_image2d_r32g32b32a32.as_raw(), 1, 1))
947             }
948             DXGI_FORMAT_R32G32_UINT => Some((self.cs_copy_buffer_image2d_r32g32.as_raw(), 1, 1)),
949             DXGI_FORMAT_R16G16B16A16_UINT => {
950                 Some((self.cs_copy_buffer_image2d_r16g16b16a16.as_raw(), 1, 1))
951             }
952             DXGI_FORMAT_R32_UINT => Some((self.cs_copy_buffer_image2d_r32.as_raw(), 1, 1)),
953             DXGI_FORMAT_R16G16_UINT => Some((self.cs_copy_buffer_image2d_r16g16.as_raw(), 1, 1)),
954             DXGI_FORMAT_R8G8B8A8_UINT => {
955                 Some((self.cs_copy_buffer_image2d_r8g8b8a8.as_raw(), 1, 1))
956             }
957             DXGI_FORMAT_R16_UINT => Some((self.cs_copy_buffer_image2d_r16.as_raw(), 2, 1)),
958             DXGI_FORMAT_R8G8_UINT => Some((self.cs_copy_buffer_image2d_r8g8.as_raw(), 2, 1)),
959             DXGI_FORMAT_R8_UINT => Some((self.cs_copy_buffer_image2d_r8.as_raw(), 4, 1)),
960             _ => None,
961         }
962     }
963 
copy_buffer_to_image_2d<T>( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, src: &Buffer, dst: &Image, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::BufferImageCopy>,964     pub fn copy_buffer_to_image_2d<T>(
965         &mut self,
966         context: &ComPtr<d3d11::ID3D11DeviceContext>,
967         src: &Buffer,
968         dst: &Image,
969         regions: T,
970     ) where
971         T: IntoIterator,
972         T::Item: Borrow<command::BufferImageCopy>,
973     {
974         let _scope = debug_scope!(
975             context,
976             "Buffer => Image (format={:?},kind={:?})",
977             dst.format,
978             dst.kind
979         );
980         // NOTE: we have two separate paths for Buffer -> Image transfers. we need to special case
981         //       uploads to compressed formats through `UpdateSubresource` since we cannot get a
982         //       UAV of any compressed format.
983 
984         let format_desc = dst.format.base_format().0.desc();
985         if format_desc.is_compressed() {
986             // we dont really care about non-4x4 block formats..
987             assert_eq!(format_desc.dim, (4, 4));
988             assert!(!src.host_ptr.is_null());
989 
990             for copy in regions {
991                 let info = copy.borrow();
992 
993                 let bytes_per_texel = format_desc.bits as u32 / 8;
994 
995                 let row_pitch = bytes_per_texel * info.image_extent.width / 4;
996                 let depth_pitch = row_pitch * info.image_extent.height / 4;
997 
998                 unsafe {
999                     context.UpdateSubresource(
1000                         dst.internal.raw,
1001                         dst.calc_subresource(
1002                             info.image_layers.level as _,
1003                             info.image_layers.layers.start as _,
1004                         ),
1005                         &d3d11::D3D11_BOX {
1006                             left: info.image_offset.x as _,
1007                             top: info.image_offset.y as _,
1008                             front: info.image_offset.z as _,
1009                             right: info.image_offset.x as u32 + info.image_extent.width,
1010                             bottom: info.image_offset.y as u32 + info.image_extent.height,
1011                             back: info.image_offset.z as u32 + info.image_extent.depth,
1012                         },
1013                         src.host_ptr
1014                             .offset(src.bound_range.start as isize + info.buffer_offset as isize)
1015                             as _,
1016                         row_pitch,
1017                         depth_pitch,
1018                     );
1019                 }
1020             }
1021         } else {
1022             let (shader, scale_x, scale_y) = self
1023                 .find_buffer_to_image_shader(dst.decomposed_format.copy_uav.unwrap())
1024                 .unwrap();
1025 
1026             let srv = src.internal.srv.unwrap();
1027 
1028             unsafe {
1029                 context.CSSetShader(shader, ptr::null_mut(), 0);
1030                 context.CSSetConstantBuffers(0, 1, &self.internal_buffer.as_raw());
1031                 context.CSSetShaderResources(0, 1, [srv].as_ptr());
1032 
1033                 for copy in regions {
1034                     let info = copy.borrow();
1035                     self.update_buffer_image(context, &info, dst);
1036 
1037                     debug_marker!(context, "{:?}", info);
1038 
1039                     // TODO: multiple layers? do we introduce a stride and do multiple dispatch
1040                     //       calls or handle this in the shader? (use z component in dispatch call
1041                     //
1042                     // NOTE: right now our copy UAV is a 2D array, and we set the layer in the
1043                     //       `update_buffer_image` call above
1044                     let uav = dst
1045                         .get_uav(
1046                             info.image_layers.level,
1047                             0, /*info.image_layers.layers.start*/
1048                         )
1049                         .unwrap()
1050                         .as_raw();
1051                     context.CSSetUnorderedAccessViews(0, 1, [uav].as_ptr(), ptr::null_mut());
1052 
1053                     context.Dispatch(
1054                         ((info.image_extent.width + (COPY_THREAD_GROUP_X - 1))
1055                             / COPY_THREAD_GROUP_X
1056                             / scale_x)
1057                             .max(1),
1058                         ((info.image_extent.height + (COPY_THREAD_GROUP_X - 1))
1059                             / COPY_THREAD_GROUP_Y
1060                             / scale_y)
1061                             .max(1),
1062                         1,
1063                     );
1064                 }
1065 
1066                 // unbind external resources
1067                 context.CSSetShaderResources(0, 1, [ptr::null_mut(); 1].as_ptr());
1068                 context.CSSetUnorderedAccessViews(
1069                     0,
1070                     1,
1071                     [ptr::null_mut(); 1].as_ptr(),
1072                     ptr::null_mut(),
1073                 );
1074             }
1075         }
1076     }
1077 
find_blit_shader(&self, src: &Image) -> Option<*mut d3d11::ID3D11PixelShader>1078     fn find_blit_shader(&self, src: &Image) -> Option<*mut d3d11::ID3D11PixelShader> {
1079         use crate::format::ChannelType as Ct;
1080 
1081         match src.format.base_format().1 {
1082             Ct::Uint => Some(self.ps_blit_2d_uint.as_raw()),
1083             Ct::Sint => Some(self.ps_blit_2d_int.as_raw()),
1084             Ct::Unorm | Ct::Snorm | Ct::Sfloat | Ct::Srgb => Some(self.ps_blit_2d_float.as_raw()),
1085             Ct::Ufloat | Ct::Uscaled | Ct::Sscaled => None,
1086         }
1087     }
1088 
blit_2d_image<T>( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, src: &Image, dst: &Image, filter: image::Filter, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::ImageBlit>,1089     pub fn blit_2d_image<T>(
1090         &mut self,
1091         context: &ComPtr<d3d11::ID3D11DeviceContext>,
1092         src: &Image,
1093         dst: &Image,
1094         filter: image::Filter,
1095         regions: T,
1096     ) where
1097         T: IntoIterator,
1098         T::Item: Borrow<command::ImageBlit>,
1099     {
1100         use std::cmp;
1101 
1102         let _scope = debug_scope!(
1103             context,
1104             "Blit: Image (format={:?},kind={:?}) => Image (format={:?},kind={:?})",
1105             src.format,
1106             src.kind,
1107             dst.format,
1108             dst.kind
1109         );
1110 
1111         let shader = self.find_blit_shader(src).unwrap();
1112 
1113         let srv = src.internal.srv.clone().unwrap().as_raw();
1114 
1115         unsafe {
1116             context.IASetPrimitiveTopology(d3dcommon::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1117             context.VSSetShader(self.vs_blit_2d.as_raw(), ptr::null_mut(), 0);
1118             context.VSSetConstantBuffers(0, 1, [self.internal_buffer.as_raw()].as_ptr());
1119             context.PSSetShader(shader, ptr::null_mut(), 0);
1120             context.PSSetShaderResources(0, 1, [srv].as_ptr());
1121             context.PSSetSamplers(
1122                 0,
1123                 1,
1124                 match filter {
1125                     image::Filter::Nearest => [self.sampler_nearest.as_raw()],
1126                     image::Filter::Linear => [self.sampler_linear.as_raw()],
1127                 }
1128                 .as_ptr(),
1129             );
1130 
1131             for region in regions {
1132                 let region = region.borrow();
1133                 self.update_blit(context, src, &region);
1134 
1135                 // TODO: more layers
1136                 let rtv = dst
1137                     .get_rtv(
1138                         region.dst_subresource.level,
1139                         region.dst_subresource.layers.start,
1140                     )
1141                     .unwrap()
1142                     .as_raw();
1143 
1144                 context.RSSetViewports(
1145                     1,
1146                     [d3d11::D3D11_VIEWPORT {
1147                         TopLeftX: cmp::min(region.dst_bounds.start.x, region.dst_bounds.end.x) as _,
1148                         TopLeftY: cmp::min(region.dst_bounds.start.y, region.dst_bounds.end.y) as _,
1149                         Width: (region.dst_bounds.end.x - region.dst_bounds.start.x).abs() as _,
1150                         Height: (region.dst_bounds.end.y - region.dst_bounds.start.y).abs() as _,
1151                         MinDepth: 0.0f32,
1152                         MaxDepth: 1.0f32,
1153                     }]
1154                     .as_ptr(),
1155                 );
1156                 context.OMSetRenderTargets(1, [rtv].as_ptr(), ptr::null_mut());
1157                 context.Draw(3, 0);
1158             }
1159 
1160             context.PSSetShaderResources(0, 1, [ptr::null_mut()].as_ptr());
1161             context.OMSetRenderTargets(1, [ptr::null_mut()].as_ptr(), ptr::null_mut());
1162         }
1163     }
1164 
clear_attachments<T, U>( &mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>, clears: T, rects: U, cache: &RenderPassCache, ) where T: IntoIterator, T::Item: Borrow<command::AttachmentClear>, U: IntoIterator, U::Item: Borrow<pso::ClearRect>,1165     pub fn clear_attachments<T, U>(
1166         &mut self,
1167         context: &ComPtr<d3d11::ID3D11DeviceContext>,
1168         clears: T,
1169         rects: U,
1170         cache: &RenderPassCache,
1171     ) where
1172         T: IntoIterator,
1173         T::Item: Borrow<command::AttachmentClear>,
1174         U: IntoIterator,
1175         U::Item: Borrow<pso::ClearRect>,
1176     {
1177         use hal::format::ChannelType as Ct;
1178         let _scope = debug_scope!(context, "ClearAttachments");
1179 
1180         let clear_rects: SmallVec<[pso::ClearRect; 8]> = rects
1181             .into_iter()
1182             .map(|rect| rect.borrow().clone())
1183             .collect();
1184 
1185         unsafe {
1186             context.IASetPrimitiveTopology(d3dcommon::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1187             context.IASetInputLayout(ptr::null_mut());
1188             context.VSSetShader(self.vs_partial_clear.as_raw(), ptr::null_mut(), 0);
1189             context.PSSetConstantBuffers(0, 1, [self.internal_buffer.as_raw()].as_ptr());
1190         }
1191 
1192         let subpass = &cache.render_pass.subpasses[cache.current_subpass as usize];
1193 
1194         for clear in clears {
1195             let clear = clear.borrow();
1196 
1197             let _scope = debug_scope!(context, "{:?}", clear);
1198 
1199             match *clear {
1200                 command::AttachmentClear::Color { index, value } => {
1201                     self.update_clear_color(context, value);
1202 
1203                     let attachment = {
1204                         let rtv_id = subpass.color_attachments[index];
1205                         &cache.framebuffer.attachments[rtv_id.0]
1206                     };
1207 
1208                     unsafe {
1209                         context.OMSetRenderTargets(
1210                             1,
1211                             [attachment.rtv_handle.clone().unwrap().as_raw()].as_ptr(),
1212                             ptr::null_mut(),
1213                         );
1214                     }
1215 
1216                     let shader = match attachment.format.base_format().1 {
1217                         Ct::Uint => self.ps_partial_clear_uint.as_raw(),
1218                         Ct::Sint => self.ps_partial_clear_int.as_raw(),
1219                         _ => self.ps_partial_clear_float.as_raw(),
1220                     };
1221                     unsafe { context.PSSetShader(shader, ptr::null_mut(), 0) };
1222 
1223                     for clear_rect in &clear_rects {
1224                         let viewport = conv::map_viewport(&Viewport {
1225                             rect: clear_rect.rect,
1226                             depth: 0f32 .. 1f32,
1227                         });
1228 
1229                         debug_marker!(context, "{:?}", clear_rect.rect);
1230 
1231                         unsafe {
1232                             context.RSSetViewports(1, [viewport].as_ptr());
1233                             context.Draw(3, 0);
1234                         }
1235                     }
1236                 }
1237                 command::AttachmentClear::DepthStencil { depth, stencil } => {
1238                     self.update_clear_depth_stencil(context, depth, stencil);
1239 
1240                     let attachment = {
1241                         let dsv_id = subpass.depth_stencil_attachment.unwrap();
1242                         &cache.framebuffer.attachments[dsv_id.0]
1243                     };
1244 
1245                     unsafe {
1246                         match (depth, stencil) {
1247                             (Some(_), Some(stencil)) => {
1248                                 context.OMSetDepthStencilState(
1249                                     self.partial_clear_depth_stencil_state.as_raw(),
1250                                     stencil,
1251                                 );
1252                                 context.PSSetShader(
1253                                     self.ps_partial_clear_depth.as_raw(),
1254                                     ptr::null_mut(),
1255                                     0,
1256                                 );
1257                             }
1258 
1259                             (Some(_), None) => {
1260                                 context.OMSetDepthStencilState(
1261                                     self.partial_clear_depth_state.as_raw(),
1262                                     0,
1263                                 );
1264                                 context.PSSetShader(
1265                                     self.ps_partial_clear_depth.as_raw(),
1266                                     ptr::null_mut(),
1267                                     0,
1268                                 );
1269                             }
1270 
1271                             (None, Some(stencil)) => {
1272                                 context.OMSetDepthStencilState(
1273                                     self.partial_clear_stencil_state.as_raw(),
1274                                     stencil,
1275                                 );
1276                                 context.PSSetShader(
1277                                     self.ps_partial_clear_stencil.as_raw(),
1278                                     ptr::null_mut(),
1279                                     0,
1280                                 );
1281                             }
1282                             (None, None) => {}
1283                         }
1284 
1285                         context.OMSetRenderTargets(
1286                             0,
1287                             ptr::null_mut(),
1288                             attachment.dsv_handle.clone().unwrap().as_raw(),
1289                         );
1290                         context.PSSetShader(
1291                             self.ps_partial_clear_depth.as_raw(),
1292                             ptr::null_mut(),
1293                             0,
1294                         );
1295                     }
1296 
1297                     for clear_rect in &clear_rects {
1298                         let viewport = conv::map_viewport(&Viewport {
1299                             rect: clear_rect.rect,
1300                             depth: 0f32 .. 1f32,
1301                         });
1302 
1303                         unsafe {
1304                             context.RSSetViewports(1, [viewport].as_ptr());
1305                             context.Draw(3, 0);
1306                         }
1307                     }
1308                 }
1309             }
1310         }
1311     }
1312 }
1313