1 /*!
2 # DX11 backend internals.
3
4 ## Pipeline Layout
5
6 In D3D11 there are tables of CBVs, SRVs, UAVs, and samplers.
7
8 Each descriptor type can take 1 or two of those entry points.
9
10 The descriptor pool is just and array of handles, belonging to descriptor set 1, descriptor set 2, etc.
11 Each range of descriptors in a descriptor set area of the pool is split into shader stages,
12 which in turn is split into CBS/SRV/UAV/Sampler parts. That allows binding a descriptor set as a list
13 of continuous descriptor ranges (per type, per shader stage).
14
15 !*/
16
17 //#[deny(missing_docs)]
18
19 #[macro_use]
20 extern crate bitflags;
21 #[macro_use]
22 extern crate log;
23 #[macro_use]
24 extern crate winapi;
25
26 use hal::{
27 adapter,
28 buffer,
29 command,
30 format,
31 image,
32 memory,
33 pass,
34 pso,
35 query,
36 queue,
37 window,
38 DrawCount,
39 IndexCount,
40 InstanceCount,
41 Limits,
42 VertexCount,
43 VertexOffset,
44 WorkGroupCount,
45 };
46
47 use range_alloc::RangeAllocator;
48
49 use winapi::{
50 shared::{
51 dxgi::{IDXGIAdapter, IDXGIFactory, IDXGISwapChain},
52 dxgiformat,
53 minwindef::{FALSE, HMODULE, UINT},
54 windef::{HWND, RECT},
55 winerror,
56 },
57 um::{d3d11, d3dcommon, winuser::GetClientRect},
58 Interface as _,
59 };
60
61 use wio::com::ComPtr;
62
63 use parking_lot::{Condvar, Mutex};
64
65 use std::{borrow::Borrow, cell::RefCell, fmt, mem, ops::Range, os::raw::c_void, ptr, sync::Arc};
66
67 macro_rules! debug_scope {
68 ($context:expr, $($arg:tt)+) => ({
69 #[cfg(debug_assertions)]
70 {
71 $crate::debug::DebugScope::with_name(
72 $context,
73 format_args!($($arg)+),
74 )
75 }
76 #[cfg(not(debug_assertions))]
77 {
78 ()
79 }
80 });
81 }
82
83 macro_rules! debug_marker {
84 ($context:expr, $($arg:tt)+) => ({
85 #[cfg(debug_assertions)]
86 {
87 $crate::debug::debug_marker(
88 $context,
89 format_args!($($arg)+),
90 );
91 }
92 });
93 }
94
95 mod conv;
96 #[cfg(debug_assertions)]
97 mod debug;
98 mod device;
99 mod dxgi;
100 mod internal;
101 mod shader;
102
103 type CreateFun = unsafe extern "system" fn(
104 *mut IDXGIAdapter,
105 UINT,
106 HMODULE,
107 UINT,
108 *const UINT,
109 UINT,
110 UINT,
111 *mut *mut d3d11::ID3D11Device,
112 *mut UINT,
113 *mut *mut d3d11::ID3D11DeviceContext,
114 ) -> winerror::HRESULT;
115
116 #[derive(Clone)]
117 pub(crate) struct ViewInfo {
118 resource: *mut d3d11::ID3D11Resource,
119 kind: image::Kind,
120 caps: image::ViewCapabilities,
121 view_kind: image::ViewKind,
122 format: dxgiformat::DXGI_FORMAT,
123 range: image::SubresourceRange,
124 }
125
126 impl fmt::Debug for ViewInfo {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result127 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
128 fmt.write_str("ViewInfo")
129 }
130 }
131
132 #[derive(Debug)]
133 pub struct Instance {
134 pub(crate) factory: ComPtr<IDXGIFactory>,
135 pub(crate) dxgi_version: dxgi::DxgiVersion,
136 library_d3d11: Arc<libloading::Library>,
137 library_dxgi: libloading::Library,
138 }
139
140 unsafe impl Send for Instance {}
141 unsafe impl Sync for Instance {}
142
143 impl Instance {
create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface144 pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
145 Surface {
146 factory: self.factory.clone(),
147 wnd_handle: hwnd as *mut _,
148 presentation: None,
149 }
150 }
151 }
152
get_features( _device: ComPtr<d3d11::ID3D11Device>, _feature_level: d3dcommon::D3D_FEATURE_LEVEL, ) -> hal::Features153 fn get_features(
154 _device: ComPtr<d3d11::ID3D11Device>,
155 _feature_level: d3dcommon::D3D_FEATURE_LEVEL,
156 ) -> hal::Features {
157 hal::Features::empty()
158 | hal::Features::ROBUST_BUFFER_ACCESS
159 | hal::Features::FULL_DRAW_INDEX_U32
160 | hal::Features::FORMAT_BC
161 | hal::Features::INSTANCE_RATE
162 | hal::Features::SAMPLER_MIP_LOD_BIAS
163 | hal::Features::SAMPLER_MIRROR_CLAMP_EDGE
164 | hal::Features::NDC_Y_UP
165 }
166
get_format_properties( device: ComPtr<d3d11::ID3D11Device>, ) -> [format::Properties; format::NUM_FORMATS]167 fn get_format_properties(
168 device: ComPtr<d3d11::ID3D11Device>,
169 ) -> [format::Properties; format::NUM_FORMATS] {
170 let mut format_properties = [format::Properties::default(); format::NUM_FORMATS];
171 for (i, props) in &mut format_properties.iter_mut().enumerate().skip(1) {
172 let format: format::Format = unsafe { mem::transmute(i as u32) };
173
174 let dxgi_format = match conv::map_format(format) {
175 Some(format) => format,
176 None => continue,
177 };
178
179 let mut support = d3d11::D3D11_FEATURE_DATA_FORMAT_SUPPORT {
180 InFormat: dxgi_format,
181 OutFormatSupport: 0,
182 };
183 let mut support_2 = d3d11::D3D11_FEATURE_DATA_FORMAT_SUPPORT2 {
184 InFormat: dxgi_format,
185 OutFormatSupport2: 0,
186 };
187
188 let hr = unsafe {
189 device.CheckFeatureSupport(
190 d3d11::D3D11_FEATURE_FORMAT_SUPPORT,
191 &mut support as *mut _ as *mut _,
192 mem::size_of::<d3d11::D3D11_FEATURE_DATA_FORMAT_SUPPORT>() as UINT,
193 )
194 };
195
196 if hr == winerror::S_OK {
197 let can_buffer = 0 != support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_BUFFER;
198 let can_image = 0
199 != support.OutFormatSupport
200 & (d3d11::D3D11_FORMAT_SUPPORT_TEXTURE1D
201 | d3d11::D3D11_FORMAT_SUPPORT_TEXTURE2D
202 | d3d11::D3D11_FORMAT_SUPPORT_TEXTURE3D
203 | d3d11::D3D11_FORMAT_SUPPORT_TEXTURECUBE);
204 let can_linear = can_image && !format.surface_desc().is_compressed();
205 if can_image {
206 props.optimal_tiling |=
207 format::ImageFeature::SAMPLED | format::ImageFeature::BLIT_SRC;
208 }
209 if can_linear {
210 props.linear_tiling |=
211 format::ImageFeature::SAMPLED | format::ImageFeature::BLIT_SRC;
212 }
213 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER != 0 {
214 props.buffer_features |= format::BufferFeature::VERTEX;
215 }
216 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_SHADER_SAMPLE != 0 {
217 props.optimal_tiling |= format::ImageFeature::SAMPLED_LINEAR;
218 }
219 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_RENDER_TARGET != 0 {
220 props.optimal_tiling |=
221 format::ImageFeature::COLOR_ATTACHMENT | format::ImageFeature::BLIT_DST;
222 if can_linear {
223 props.linear_tiling |=
224 format::ImageFeature::COLOR_ATTACHMENT | format::ImageFeature::BLIT_DST;
225 }
226 }
227 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_BLENDABLE != 0 {
228 props.optimal_tiling |= format::ImageFeature::COLOR_ATTACHMENT_BLEND;
229 }
230 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_DEPTH_STENCIL != 0 {
231 props.optimal_tiling |= format::ImageFeature::DEPTH_STENCIL_ATTACHMENT;
232 }
233 if support.OutFormatSupport & d3d11::D3D11_FORMAT_SUPPORT_SHADER_LOAD != 0 {
234 //TODO: check d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD ?
235 if can_buffer {
236 props.buffer_features |= format::BufferFeature::UNIFORM_TEXEL;
237 }
238 }
239
240 let hr = unsafe {
241 device.CheckFeatureSupport(
242 d3d11::D3D11_FEATURE_FORMAT_SUPPORT2,
243 &mut support_2 as *mut _ as *mut _,
244 mem::size_of::<d3d11::D3D11_FEATURE_DATA_FORMAT_SUPPORT2>() as UINT,
245 )
246 };
247 if hr == winerror::S_OK {
248 if support_2.OutFormatSupport2 & d3d11::D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD != 0 {
249 //TODO: other atomic flags?
250 if can_buffer {
251 props.buffer_features |= format::BufferFeature::STORAGE_TEXEL_ATOMIC;
252 }
253 if can_image {
254 props.optimal_tiling |= format::ImageFeature::STORAGE_ATOMIC;
255 }
256 }
257 if support_2.OutFormatSupport2 & d3d11::D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0 {
258 if can_buffer {
259 props.buffer_features |= format::BufferFeature::STORAGE_TEXEL;
260 }
261 if can_image {
262 props.optimal_tiling |= format::ImageFeature::STORAGE;
263 }
264 }
265 }
266 }
267
268 //TODO: blits, linear tiling
269 }
270
271 format_properties
272 }
273
274 impl hal::Instance<Backend> for Instance {
create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend>275 fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
276 // TODO: get the latest factory we can find
277
278 match dxgi::get_dxgi_factory() {
279 Ok((library_dxgi, factory, dxgi_version)) => {
280 info!("DXGI version: {:?}", dxgi_version);
281 let library_d3d11 = Arc::new(
282 libloading::Library::new("d3d11.dll").map_err(|_| hal::UnsupportedBackend)?,
283 );
284 Ok(Instance {
285 factory,
286 dxgi_version,
287 library_d3d11,
288 library_dxgi,
289 })
290 }
291 Err(hr) => {
292 info!("Failed on factory creation: {:?}", hr);
293 Err(hal::UnsupportedBackend)
294 }
295 }
296 }
297
enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>>298 fn enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>> {
299 let mut adapters = Vec::new();
300 let mut idx = 0;
301
302 let func: libloading::Symbol<CreateFun> =
303 match unsafe { self.library_d3d11.get(b"D3D11CreateDevice") } {
304 Ok(func) => func,
305 Err(e) => {
306 error!("Unable to get device creation function: {:?}", e);
307 return Vec::new();
308 }
309 };
310
311 while let Ok((adapter, info)) =
312 dxgi::get_adapter(idx, self.factory.as_raw(), self.dxgi_version)
313 {
314 idx += 1;
315
316 use hal::memory::Properties;
317
318 // TODO: move into function?
319 let (device, feature_level) = {
320 let feature_level = get_feature_level(&func, adapter.as_raw());
321
322 let mut device = ptr::null_mut();
323 let hr = unsafe {
324 func(
325 adapter.as_raw() as *mut _,
326 d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
327 ptr::null_mut(),
328 0,
329 [feature_level].as_ptr(),
330 1,
331 d3d11::D3D11_SDK_VERSION,
332 &mut device as *mut *mut _ as *mut *mut _,
333 ptr::null_mut(),
334 ptr::null_mut(),
335 )
336 };
337
338 if !winerror::SUCCEEDED(hr) {
339 continue;
340 }
341
342 (
343 unsafe { ComPtr::<d3d11::ID3D11Device>::from_raw(device) },
344 feature_level,
345 )
346 };
347
348 let memory_properties = adapter::MemoryProperties {
349 memory_types: vec![
350 adapter::MemoryType {
351 properties: Properties::DEVICE_LOCAL,
352 heap_index: 0,
353 },
354 adapter::MemoryType {
355 properties: Properties::CPU_VISIBLE
356 | Properties::COHERENT
357 | Properties::CPU_CACHED,
358 heap_index: 1,
359 },
360 adapter::MemoryType {
361 properties: Properties::CPU_VISIBLE | Properties::CPU_CACHED,
362 heap_index: 1,
363 },
364 ],
365 // TODO: would using *VideoMemory and *SystemMemory from
366 // DXGI_ADAPTER_DESC be too optimistic? :)
367 memory_heaps: vec![!0, !0],
368 };
369
370 let limits = hal::Limits {
371 max_image_1d_size: d3d11::D3D11_REQ_TEXTURE1D_U_DIMENSION as _,
372 max_image_2d_size: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION as _,
373 max_image_3d_size: d3d11::D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION as _,
374 max_image_cube_size: d3d11::D3D11_REQ_TEXTURECUBE_DIMENSION as _,
375 max_image_array_layers: d3d11::D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
376 max_texel_elements: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION as _, //TODO
377 max_patch_size: 0, // TODO
378 max_viewports: d3d11::D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE as _,
379 max_viewport_dimensions: [d3d11::D3D11_VIEWPORT_BOUNDS_MAX; 2],
380 max_framebuffer_extent: hal::image::Extent {
381 //TODO
382 width: 4096,
383 height: 4096,
384 depth: 1,
385 },
386 max_compute_work_group_count: [
387 d3d11::D3D11_CS_THREAD_GROUP_MAX_X,
388 d3d11::D3D11_CS_THREAD_GROUP_MAX_Y,
389 d3d11::D3D11_CS_THREAD_GROUP_MAX_Z,
390 ],
391 max_compute_work_group_size: [
392 d3d11::D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP,
393 1,
394 1,
395 ], // TODO
396 max_vertex_input_attribute_offset: 255, // TODO
397 max_vertex_input_attributes: d3d11::D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT as _,
398 max_vertex_input_binding_stride:
399 d3d11::D3D11_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES as _,
400 max_vertex_input_bindings: d3d11::D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT as _, // TODO: verify same as attributes
401 max_vertex_output_components: d3d11::D3D11_VS_OUTPUT_REGISTER_COUNT as _, // TODO
402 min_texel_buffer_offset_alignment: 1, // TODO
403 min_uniform_buffer_offset_alignment: 16, // TODO: verify
404 min_storage_buffer_offset_alignment: 1, // TODO
405 framebuffer_color_sample_counts: 1, // TODO
406 framebuffer_depth_sample_counts: 1, // TODO
407 framebuffer_stencil_sample_counts: 1, // TODO
408 max_color_attachments: d3d11::D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT as _,
409 buffer_image_granularity: 1,
410 non_coherent_atom_size: 1, // TODO
411 max_sampler_anisotropy: 16.,
412 optimal_buffer_copy_offset_alignment: 1, // TODO
413 optimal_buffer_copy_pitch_alignment: 1, // TODO
414 min_vertex_input_binding_stride_alignment: 1,
415 ..hal::Limits::default() //TODO
416 };
417
418 let features = get_features(device.clone(), feature_level);
419 let format_properties = get_format_properties(device.clone());
420 let hints = hal::Hints::BASE_VERTEX_INSTANCE_DRAWING;
421
422 let physical_device = PhysicalDevice {
423 adapter,
424 library_d3d11: Arc::clone(&self.library_d3d11),
425 features,
426 hints,
427 limits,
428 memory_properties,
429 format_properties,
430 };
431
432 info!("{:#?}", info);
433
434 adapters.push(adapter::Adapter {
435 info,
436 physical_device,
437 queue_families: vec![QueueFamily],
438 });
439 }
440
441 adapters
442 }
443
create_surface( &self, has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result<Surface, hal::window::InitError>444 unsafe fn create_surface(
445 &self,
446 has_handle: &impl raw_window_handle::HasRawWindowHandle,
447 ) -> Result<Surface, hal::window::InitError> {
448 match has_handle.raw_window_handle() {
449 raw_window_handle::RawWindowHandle::Windows(handle) => {
450 Ok(self.create_surface_from_hwnd(handle.hwnd))
451 }
452 _ => Err(hal::window::InitError::UnsupportedWindowHandle),
453 }
454 }
455
destroy_surface(&self, _surface: Surface)456 unsafe fn destroy_surface(&self, _surface: Surface) {
457 // TODO: Implement Surface cleanup
458 }
459 }
460
461 pub struct PhysicalDevice {
462 adapter: ComPtr<IDXGIAdapter>,
463 library_d3d11: Arc<libloading::Library>,
464 features: hal::Features,
465 hints: hal::Hints,
466 limits: hal::Limits,
467 memory_properties: adapter::MemoryProperties,
468 format_properties: [format::Properties; format::NUM_FORMATS],
469 }
470
471 impl fmt::Debug for PhysicalDevice {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result472 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
473 fmt.write_str("PhysicalDevice")
474 }
475 }
476
477 unsafe impl Send for PhysicalDevice {}
478 unsafe impl Sync for PhysicalDevice {}
479
480 // TODO: does the adapter we get earlier matter for feature level?
get_feature_level(func: &CreateFun, adapter: *mut IDXGIAdapter) -> d3dcommon::D3D_FEATURE_LEVEL481 fn get_feature_level(func: &CreateFun, adapter: *mut IDXGIAdapter) -> d3dcommon::D3D_FEATURE_LEVEL {
482 let requested_feature_levels = [
483 d3dcommon::D3D_FEATURE_LEVEL_11_1,
484 d3dcommon::D3D_FEATURE_LEVEL_11_0,
485 d3dcommon::D3D_FEATURE_LEVEL_10_1,
486 d3dcommon::D3D_FEATURE_LEVEL_10_0,
487 d3dcommon::D3D_FEATURE_LEVEL_9_3,
488 d3dcommon::D3D_FEATURE_LEVEL_9_2,
489 d3dcommon::D3D_FEATURE_LEVEL_9_1,
490 ];
491
492 let mut feature_level = d3dcommon::D3D_FEATURE_LEVEL_9_1;
493 let hr = unsafe {
494 func(
495 adapter,
496 d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
497 ptr::null_mut(),
498 0,
499 requested_feature_levels[..].as_ptr(),
500 requested_feature_levels.len() as _,
501 d3d11::D3D11_SDK_VERSION,
502 ptr::null_mut(),
503 &mut feature_level as *mut _,
504 ptr::null_mut(),
505 )
506 };
507
508 if !winerror::SUCCEEDED(hr) {
509 // if there is no 11.1 runtime installed, requesting
510 // `D3D_FEATURE_LEVEL_11_1` will return E_INVALIDARG so we just retry
511 // without that
512 if hr == winerror::E_INVALIDARG {
513 let hr = unsafe {
514 func(
515 adapter,
516 d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
517 ptr::null_mut(),
518 0,
519 requested_feature_levels[1 ..].as_ptr(),
520 (requested_feature_levels.len() - 1) as _,
521 d3d11::D3D11_SDK_VERSION,
522 ptr::null_mut(),
523 &mut feature_level as *mut _,
524 ptr::null_mut(),
525 )
526 };
527
528 if !winerror::SUCCEEDED(hr) {
529 // TODO: device might not support any feature levels?
530 unimplemented!();
531 }
532 }
533 }
534
535 feature_level
536 }
537
538 // TODO: PhysicalDevice
539 impl adapter::PhysicalDevice<Backend> for PhysicalDevice {
open( &self, families: &[(&QueueFamily, &[queue::QueuePriority])], requested_features: hal::Features, ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError>540 unsafe fn open(
541 &self,
542 families: &[(&QueueFamily, &[queue::QueuePriority])],
543 requested_features: hal::Features,
544 ) -> Result<adapter::Gpu<Backend>, hal::device::CreationError> {
545 let func: libloading::Symbol<CreateFun> =
546 self.library_d3d11.get(b"D3D11CreateDevice").unwrap();
547
548 let (device, cxt) = {
549 if !self.features().contains(requested_features) {
550 return Err(hal::device::CreationError::MissingFeature);
551 }
552
553 let feature_level = get_feature_level(&func, self.adapter.as_raw());
554 let mut returned_level = d3dcommon::D3D_FEATURE_LEVEL_9_1;
555
556 #[cfg(debug_assertions)]
557 let create_flags = d3d11::D3D11_CREATE_DEVICE_DEBUG;
558 #[cfg(not(debug_assertions))]
559 let create_flags = 0;
560
561 // TODO: request debug device only on debug config?
562 let mut device = ptr::null_mut();
563 let mut cxt = ptr::null_mut();
564 let hr = func(
565 self.adapter.as_raw() as *mut _,
566 d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
567 ptr::null_mut(),
568 create_flags,
569 [feature_level].as_ptr(),
570 1,
571 d3d11::D3D11_SDK_VERSION,
572 &mut device as *mut *mut _ as *mut *mut _,
573 &mut returned_level as *mut _,
574 &mut cxt as *mut *mut _ as *mut *mut _,
575 );
576
577 // NOTE: returns error if adapter argument is non-null and driver
578 // type is not unknown; or if debug device is requested but not
579 // present
580 if !winerror::SUCCEEDED(hr) {
581 return Err(hal::device::CreationError::InitializationFailed);
582 }
583
584 info!("feature level={:x}", feature_level);
585
586 (ComPtr::from_raw(device), ComPtr::from_raw(cxt))
587 };
588
589 let device = device::Device::new(
590 device,
591 cxt,
592 requested_features,
593 self.memory_properties.clone(),
594 );
595
596 // TODO: deferred context => 1 cxt/queue?
597 let queue_groups = families
598 .into_iter()
599 .map(|&(_family, prio)| {
600 assert_eq!(prio.len(), 1);
601 let mut group = queue::QueueGroup::new(queue::QueueFamilyId(0));
602
603 // TODO: multiple queues?
604 let queue = CommandQueue {
605 context: device.context.clone(),
606 };
607 group.add_queue(queue);
608 group
609 })
610 .collect();
611
612 Ok(adapter::Gpu {
613 device,
614 queue_groups,
615 })
616 }
617
format_properties(&self, fmt: Option<format::Format>) -> format::Properties618 fn format_properties(&self, fmt: Option<format::Format>) -> format::Properties {
619 let idx = fmt.map(|fmt| fmt as usize).unwrap_or(0);
620 self.format_properties[idx]
621 }
622
image_format_properties( &self, format: format::Format, dimensions: u8, tiling: image::Tiling, usage: image::Usage, view_caps: image::ViewCapabilities, ) -> Option<image::FormatProperties>623 fn image_format_properties(
624 &self,
625 format: format::Format,
626 dimensions: u8,
627 tiling: image::Tiling,
628 usage: image::Usage,
629 view_caps: image::ViewCapabilities,
630 ) -> Option<image::FormatProperties> {
631 conv::map_format(format)?; //filter out unknown formats
632
633 let supported_usage = {
634 use hal::image::Usage as U;
635 let format_props = &self.format_properties[format as usize];
636 let props = match tiling {
637 image::Tiling::Optimal => format_props.optimal_tiling,
638 image::Tiling::Linear => format_props.linear_tiling,
639 };
640 let mut flags = U::empty();
641 // Note: these checks would have been nicer if we had explicit BLIT usage
642 if props.contains(format::ImageFeature::BLIT_SRC) {
643 flags |= U::TRANSFER_SRC;
644 }
645 if props.contains(format::ImageFeature::BLIT_DST) {
646 flags |= U::TRANSFER_DST;
647 }
648 if props.contains(format::ImageFeature::SAMPLED) {
649 flags |= U::SAMPLED;
650 }
651 if props.contains(format::ImageFeature::STORAGE) {
652 flags |= U::STORAGE;
653 }
654 if props.contains(format::ImageFeature::COLOR_ATTACHMENT) {
655 flags |= U::COLOR_ATTACHMENT;
656 }
657 if props.contains(format::ImageFeature::DEPTH_STENCIL_ATTACHMENT) {
658 flags |= U::DEPTH_STENCIL_ATTACHMENT;
659 }
660 flags
661 };
662 if !supported_usage.contains(usage) {
663 return None;
664 }
665
666 let max_resource_size =
667 (d3d11::D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM as usize) << 20;
668 Some(match tiling {
669 image::Tiling::Optimal => image::FormatProperties {
670 max_extent: match dimensions {
671 1 => image::Extent {
672 width: d3d11::D3D11_REQ_TEXTURE1D_U_DIMENSION,
673 height: 1,
674 depth: 1,
675 },
676 2 => image::Extent {
677 width: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION,
678 height: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION,
679 depth: 1,
680 },
681 3 => image::Extent {
682 width: d3d11::D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
683 height: d3d11::D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
684 depth: d3d11::D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
685 },
686 _ => return None,
687 },
688 max_levels: d3d11::D3D11_REQ_MIP_LEVELS as _,
689 max_layers: match dimensions {
690 1 => d3d11::D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION as _,
691 2 => d3d11::D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as _,
692 _ => return None,
693 },
694 sample_count_mask: if dimensions == 2
695 && !view_caps.contains(image::ViewCapabilities::KIND_CUBE)
696 && (usage.contains(image::Usage::COLOR_ATTACHMENT)
697 | usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT))
698 {
699 0x3F //TODO: use D3D12_FEATURE_DATA_FORMAT_SUPPORT
700 } else {
701 0x1
702 },
703 max_resource_size,
704 },
705 image::Tiling::Linear => image::FormatProperties {
706 max_extent: match dimensions {
707 2 => image::Extent {
708 width: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION,
709 height: d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION,
710 depth: 1,
711 },
712 _ => return None,
713 },
714 max_levels: 1,
715 max_layers: 1,
716 sample_count_mask: 0x1,
717 max_resource_size,
718 },
719 })
720 }
721
memory_properties(&self) -> adapter::MemoryProperties722 fn memory_properties(&self) -> adapter::MemoryProperties {
723 self.memory_properties.clone()
724 }
725
features(&self) -> hal::Features726 fn features(&self) -> hal::Features {
727 self.features
728 }
729
hints(&self) -> hal::Hints730 fn hints(&self) -> hal::Hints {
731 self.hints
732 }
733
limits(&self) -> Limits734 fn limits(&self) -> Limits {
735 self.limits
736 }
737 }
738
739 struct Presentation {
740 swapchain: ComPtr<IDXGISwapChain>,
741 view: ComPtr<d3d11::ID3D11RenderTargetView>,
742 format: format::Format,
743 size: window::Extent2D,
744 }
745
746 pub struct Surface {
747 pub(crate) factory: ComPtr<IDXGIFactory>,
748 wnd_handle: HWND,
749 presentation: Option<Presentation>,
750 }
751
752 impl fmt::Debug for Surface {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result753 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
754 fmt.write_str("Surface")
755 }
756 }
757
758 unsafe impl Send for Surface {}
759 unsafe impl Sync for Surface {}
760
761 impl window::Surface<Backend> for Surface {
supports_queue_family(&self, _queue_family: &QueueFamily) -> bool762 fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
763 true
764 }
765
capabilities(&self, _physical_device: &PhysicalDevice) -> window::SurfaceCapabilities766 fn capabilities(&self, _physical_device: &PhysicalDevice) -> window::SurfaceCapabilities {
767 let current_extent = unsafe {
768 let mut rect: RECT = mem::zeroed();
769 assert_ne!(
770 0,
771 GetClientRect(self.wnd_handle as *mut _, &mut rect as *mut RECT)
772 );
773 Some(window::Extent2D {
774 width: (rect.right - rect.left) as u32,
775 height: (rect.bottom - rect.top) as u32,
776 })
777 };
778
779 // TODO: flip swap effects require dx11.1/windows8
780 // NOTE: some swap effects affect msaa capabilities..
781 // TODO: _DISCARD swap effects can only have one image?
782 window::SurfaceCapabilities {
783 present_modes: window::PresentMode::FIFO, //TODO
784 composite_alpha_modes: window::CompositeAlphaMode::OPAQUE, //TODO
785 image_count: 1 ..= 16, // TODO:
786 current_extent,
787 extents: window::Extent2D {
788 width: 16,
789 height: 16,
790 } ..= window::Extent2D {
791 width: 4096,
792 height: 4096,
793 },
794 max_image_layers: 1,
795 usage: image::Usage::COLOR_ATTACHMENT | image::Usage::TRANSFER_SRC,
796 }
797 }
798
supported_formats(&self, _physical_device: &PhysicalDevice) -> Option<Vec<format::Format>>799 fn supported_formats(&self, _physical_device: &PhysicalDevice) -> Option<Vec<format::Format>> {
800 Some(vec![
801 format::Format::Bgra8Srgb,
802 format::Format::Bgra8Unorm,
803 format::Format::Rgba8Srgb,
804 format::Format::Rgba8Unorm,
805 format::Format::A2b10g10r10Unorm,
806 format::Format::Rgba16Sfloat,
807 ])
808 }
809 }
810
811 impl window::PresentationSurface<Backend> for Surface {
812 type SwapchainImage = ImageView;
813
configure_swapchain( &mut self, device: &device::Device, config: window::SwapchainConfig, ) -> Result<(), window::CreationError>814 unsafe fn configure_swapchain(
815 &mut self,
816 device: &device::Device,
817 config: window::SwapchainConfig,
818 ) -> Result<(), window::CreationError> {
819 assert!(image::Usage::COLOR_ATTACHMENT.contains(config.image_usage));
820
821 let swapchain = match self.presentation.take() {
822 Some(present) => {
823 if present.format == config.format && present.size == config.extent {
824 self.presentation = Some(present);
825 return Ok(());
826 }
827 let non_srgb_format = conv::map_format_nosrgb(config.format).unwrap();
828 drop(present.view);
829 let result = present.swapchain.ResizeBuffers(
830 config.image_count,
831 config.extent.width,
832 config.extent.height,
833 non_srgb_format,
834 0,
835 );
836 if result != winerror::S_OK {
837 error!("ResizeBuffers failed with 0x{:x}", result as u32);
838 return Err(window::CreationError::WindowInUse(hal::device::WindowInUse));
839 }
840 present.swapchain
841 }
842 None => {
843 let (swapchain, _) =
844 device.create_swapchain_impl(&config, self.wnd_handle, self.factory.clone())?;
845 swapchain
846 }
847 };
848
849 let mut resource: *mut d3d11::ID3D11Resource = ptr::null_mut();
850 assert_eq!(
851 winerror::S_OK,
852 swapchain.GetBuffer(
853 0 as _,
854 &d3d11::ID3D11Resource::uuidof(),
855 &mut resource as *mut *mut _ as *mut *mut _,
856 )
857 );
858
859 let kind = image::Kind::D2(config.extent.width, config.extent.height, 1, 1);
860 let format = conv::map_format(config.format).unwrap();
861 let decomposed = conv::DecomposedDxgiFormat::from_dxgi_format(format);
862
863 let view_info = ViewInfo {
864 resource,
865 kind,
866 caps: image::ViewCapabilities::empty(),
867 view_kind: image::ViewKind::D2,
868 format: decomposed.rtv.unwrap(),
869 range: image::SubresourceRange {
870 aspects: format::Aspects::COLOR,
871 levels: 0 .. 1,
872 layers: 0 .. 1,
873 },
874 };
875 let view = device.view_image_as_render_target(&view_info).unwrap();
876
877 (*resource).Release();
878
879 self.presentation = Some(Presentation {
880 swapchain,
881 view,
882 format: config.format,
883 size: config.extent,
884 });
885 Ok(())
886 }
887
unconfigure_swapchain(&mut self, _device: &device::Device)888 unsafe fn unconfigure_swapchain(&mut self, _device: &device::Device) {
889 self.presentation = None;
890 }
891
acquire_image( &mut self, _timeout_ns: u64, ) -> Result<(ImageView, Option<window::Suboptimal>), window::AcquireError>892 unsafe fn acquire_image(
893 &mut self,
894 _timeout_ns: u64, //TODO: use the timeout
895 ) -> Result<(ImageView, Option<window::Suboptimal>), window::AcquireError> {
896 let present = self.presentation.as_ref().unwrap();
897 let image_view = ImageView {
898 format: present.format,
899 rtv_handle: Some(present.view.clone()),
900 dsv_handle: None,
901 srv_handle: None,
902 uav_handle: None,
903 };
904 Ok((image_view, None))
905 }
906 }
907
908 pub struct Swapchain {
909 dxgi_swapchain: ComPtr<IDXGISwapChain>,
910 }
911
912 impl fmt::Debug for Swapchain {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result913 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
914 fmt.write_str("Swapchain")
915 }
916 }
917
918 unsafe impl Send for Swapchain {}
919 unsafe impl Sync for Swapchain {}
920
921 impl window::Swapchain<Backend> for Swapchain {
acquire_image( &mut self, _timeout_ns: u64, _semaphore: Option<&Semaphore>, _fence: Option<&Fence>, ) -> Result<(window::SwapImageIndex, Option<window::Suboptimal>), window::AcquireError>922 unsafe fn acquire_image(
923 &mut self,
924 _timeout_ns: u64,
925 _semaphore: Option<&Semaphore>,
926 _fence: Option<&Fence>,
927 ) -> Result<(window::SwapImageIndex, Option<window::Suboptimal>), window::AcquireError> {
928 // TODO: non-`_DISCARD` swap effects have more than one buffer, `FLIP`
929 // effects are dxgi 1.3 (w10+?) in which case there is
930 // `GetCurrentBackBufferIndex()` on the swapchain
931 Ok((0, None))
932 }
933 }
934
935 #[derive(Debug, Clone, Copy)]
936 pub struct QueueFamily;
937
938 impl queue::QueueFamily for QueueFamily {
queue_type(&self) -> queue::QueueType939 fn queue_type(&self) -> queue::QueueType {
940 queue::QueueType::General
941 }
max_queues(&self) -> usize942 fn max_queues(&self) -> usize {
943 1
944 }
id(&self) -> queue::QueueFamilyId945 fn id(&self) -> queue::QueueFamilyId {
946 queue::QueueFamilyId(0)
947 }
948 }
949
950 #[derive(Clone)]
951 pub struct CommandQueue {
952 context: ComPtr<d3d11::ID3D11DeviceContext>,
953 }
954
955 impl fmt::Debug for CommandQueue {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result956 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
957 fmt.write_str("CommandQueue")
958 }
959 }
960
961 unsafe impl Send for CommandQueue {}
962 unsafe impl Sync for CommandQueue {}
963
964 impl queue::CommandQueue<Backend> for CommandQueue {
submit<'a, T, Ic, S, Iw, Is>( &mut self, submission: queue::Submission<Ic, Iw, Is>, fence: Option<&Fence>, ) where T: 'a + Borrow<CommandBuffer>, Ic: IntoIterator<Item = &'a T>, S: 'a + Borrow<Semaphore>, Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>, Is: IntoIterator<Item = &'a S>,965 unsafe fn submit<'a, T, Ic, S, Iw, Is>(
966 &mut self,
967 submission: queue::Submission<Ic, Iw, Is>,
968 fence: Option<&Fence>,
969 ) where
970 T: 'a + Borrow<CommandBuffer>,
971 Ic: IntoIterator<Item = &'a T>,
972 S: 'a + Borrow<Semaphore>,
973 Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
974 Is: IntoIterator<Item = &'a S>,
975 {
976 let _scope = debug_scope!(&self.context, "Submit(fence={:?})", fence);
977 for cmd_buf in submission.command_buffers {
978 let cmd_buf = cmd_buf.borrow();
979
980 let _scope = debug_scope!(
981 &self.context,
982 "CommandBuffer ({}/{})",
983 cmd_buf.flush_coherent_memory.len(),
984 cmd_buf.invalidate_coherent_memory.len()
985 );
986
987 {
988 let _scope = debug_scope!(&self.context, "Pre-Exec: Flush");
989 for sync in &cmd_buf.flush_coherent_memory {
990 sync.do_flush(&self.context);
991 }
992 }
993 self.context
994 .ExecuteCommandList(cmd_buf.as_raw_list().as_raw(), FALSE);
995 {
996 let _scope = debug_scope!(&self.context, "Post-Exec: Invalidate");
997 for sync in &cmd_buf.invalidate_coherent_memory {
998 sync.do_invalidate(&self.context);
999 }
1000 }
1001 }
1002
1003 if let Some(fence) = fence {
1004 *fence.mutex.lock() = true;
1005 fence.condvar.notify_all();
1006 }
1007 }
1008
present<'a, W, Is, S, Iw>( &mut self, swapchains: Is, _wait_semaphores: Iw, ) -> Result<Option<window::Suboptimal>, window::PresentError> where W: 'a + Borrow<Swapchain>, Is: IntoIterator<Item = (&'a W, window::SwapImageIndex)>, S: 'a + Borrow<Semaphore>, Iw: IntoIterator<Item = &'a S>,1009 unsafe fn present<'a, W, Is, S, Iw>(
1010 &mut self,
1011 swapchains: Is,
1012 _wait_semaphores: Iw,
1013 ) -> Result<Option<window::Suboptimal>, window::PresentError>
1014 where
1015 W: 'a + Borrow<Swapchain>,
1016 Is: IntoIterator<Item = (&'a W, window::SwapImageIndex)>,
1017 S: 'a + Borrow<Semaphore>,
1018 Iw: IntoIterator<Item = &'a S>,
1019 {
1020 for (swapchain, _idx) in swapchains {
1021 swapchain.borrow().dxgi_swapchain.Present(1, 0);
1022 }
1023
1024 Ok(None)
1025 }
1026
present_surface( &mut self, surface: &mut Surface, _image: ImageView, _wait_semaphore: Option<&Semaphore>, ) -> Result<Option<window::Suboptimal>, window::PresentError>1027 unsafe fn present_surface(
1028 &mut self,
1029 surface: &mut Surface,
1030 _image: ImageView,
1031 _wait_semaphore: Option<&Semaphore>,
1032 ) -> Result<Option<window::Suboptimal>, window::PresentError> {
1033 surface
1034 .presentation
1035 .as_ref()
1036 .unwrap()
1037 .swapchain
1038 .Present(1, 0);
1039 Ok(None)
1040 }
1041
wait_idle(&self) -> Result<(), hal::device::OutOfMemory>1042 fn wait_idle(&self) -> Result<(), hal::device::OutOfMemory> {
1043 // unimplemented!()
1044 Ok(())
1045 }
1046 }
1047
1048 #[derive(Debug)]
1049 pub struct AttachmentClear {
1050 subpass_id: Option<pass::SubpassId>,
1051 attachment_id: usize,
1052 raw: command::AttachmentClear,
1053 }
1054
1055 #[derive(Debug)]
1056 pub struct RenderPassCache {
1057 pub render_pass: RenderPass,
1058 pub framebuffer: Framebuffer,
1059 pub attachment_clear_values: Vec<AttachmentClear>,
1060 pub target_rect: pso::Rect,
1061 pub current_subpass: pass::SubpassId,
1062 }
1063
1064 impl RenderPassCache {
start_subpass( &mut self, internal: &mut internal::Internal, context: &ComPtr<d3d11::ID3D11DeviceContext>, cache: &mut CommandBufferState, )1065 pub fn start_subpass(
1066 &mut self,
1067 internal: &mut internal::Internal,
1068 context: &ComPtr<d3d11::ID3D11DeviceContext>,
1069 cache: &mut CommandBufferState,
1070 ) {
1071 let attachments = self
1072 .attachment_clear_values
1073 .iter()
1074 .filter(|clear| clear.subpass_id == Some(self.current_subpass))
1075 .map(|clear| clear.raw);
1076
1077 cache
1078 .dirty_flag
1079 .insert(DirtyStateFlag::GRAPHICS_PIPELINE | DirtyStateFlag::VIEWPORTS);
1080 internal.clear_attachments(
1081 context,
1082 attachments,
1083 &[pso::ClearRect {
1084 rect: self.target_rect,
1085 layers: 0 .. 1,
1086 }],
1087 &self,
1088 );
1089
1090 let subpass = &self.render_pass.subpasses[self.current_subpass as usize];
1091 let color_views = subpass
1092 .color_attachments
1093 .iter()
1094 .map(|&(id, _)| {
1095 self.framebuffer.attachments[id]
1096 .rtv_handle
1097 .clone()
1098 .unwrap()
1099 .as_raw()
1100 })
1101 .collect::<Vec<_>>();
1102 let ds_view = match subpass.depth_stencil_attachment {
1103 Some((id, _)) => Some(
1104 self.framebuffer.attachments[id]
1105 .dsv_handle
1106 .clone()
1107 .unwrap()
1108 .as_raw(),
1109 ),
1110 None => None,
1111 };
1112
1113 cache.set_render_targets(&color_views, ds_view);
1114 cache.bind(context);
1115 }
1116
next_subpass(&mut self)1117 pub fn next_subpass(&mut self) {
1118 self.current_subpass += 1;
1119 }
1120 }
1121
1122 bitflags! {
1123 struct DirtyStateFlag : u32 {
1124 const RENDER_TARGETS = (1 << 1);
1125 const VERTEX_BUFFERS = (1 << 2);
1126 const GRAPHICS_PIPELINE = (1 << 3);
1127 const VIEWPORTS = (1 << 4);
1128 const BLEND_STATE = (1 << 5);
1129 }
1130 }
1131
1132 pub struct CommandBufferState {
1133 dirty_flag: DirtyStateFlag,
1134
1135 render_target_len: u32,
1136 render_targets: [*mut d3d11::ID3D11RenderTargetView; 8],
1137 depth_target: Option<*mut d3d11::ID3D11DepthStencilView>,
1138 graphics_pipeline: Option<GraphicsPipeline>,
1139
1140 // a bitmask that keeps track of what vertex buffer bindings have been "bound" into
1141 // our vec
1142 bound_bindings: u32,
1143 // a bitmask that hold the required binding slots to be bound for the currently
1144 // bound pipeline
1145 required_bindings: Option<u32>,
1146 // the highest binding number in currently bound pipeline
1147 max_bindings: Option<u32>,
1148 viewports: Vec<d3d11::D3D11_VIEWPORT>,
1149 vertex_buffers: Vec<*mut d3d11::ID3D11Buffer>,
1150 vertex_offsets: Vec<u32>,
1151 vertex_strides: Vec<u32>,
1152 blend_factor: Option<[f32; 4]>,
1153 // we can only support one face (rather, both faces must have the same value)
1154 stencil_ref: Option<pso::StencilValue>,
1155 stencil_read_mask: Option<pso::StencilValue>,
1156 stencil_write_mask: Option<pso::StencilValue>,
1157 current_blend: Option<*mut d3d11::ID3D11BlendState>,
1158 }
1159
1160 impl fmt::Debug for CommandBufferState {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result1161 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1162 fmt.write_str("CommandBufferState")
1163 }
1164 }
1165
1166 impl CommandBufferState {
new() -> Self1167 fn new() -> Self {
1168 CommandBufferState {
1169 dirty_flag: DirtyStateFlag::empty(),
1170 render_target_len: 0,
1171 render_targets: [ptr::null_mut(); 8],
1172 depth_target: None,
1173 graphics_pipeline: None,
1174 bound_bindings: 0,
1175 required_bindings: None,
1176 max_bindings: None,
1177 viewports: Vec::new(),
1178 vertex_buffers: Vec::new(),
1179 vertex_offsets: Vec::new(),
1180 vertex_strides: Vec::new(),
1181 blend_factor: None,
1182 stencil_ref: None,
1183 stencil_read_mask: None,
1184 stencil_write_mask: None,
1185 current_blend: None,
1186 }
1187 }
1188
clear(&mut self)1189 fn clear(&mut self) {
1190 self.render_target_len = 0;
1191 self.depth_target = None;
1192 self.graphics_pipeline = None;
1193 self.bound_bindings = 0;
1194 self.required_bindings = None;
1195 self.max_bindings = None;
1196 self.viewports.clear();
1197 self.vertex_buffers.clear();
1198 self.vertex_offsets.clear();
1199 self.vertex_strides.clear();
1200 self.blend_factor = None;
1201 self.stencil_ref = None;
1202 self.stencil_read_mask = None;
1203 self.stencil_write_mask = None;
1204 self.current_blend = None;
1205 }
1206
set_vertex_buffer( &mut self, index: usize, offset: u32, buffer: *mut d3d11::ID3D11Buffer, )1207 pub fn set_vertex_buffer(
1208 &mut self,
1209 index: usize,
1210 offset: u32,
1211 buffer: *mut d3d11::ID3D11Buffer,
1212 ) {
1213 self.bound_bindings |= 1 << index as u32;
1214
1215 if index >= self.vertex_buffers.len() {
1216 self.vertex_buffers.push(buffer);
1217 self.vertex_offsets.push(offset);
1218 } else {
1219 self.vertex_buffers[index] = buffer;
1220 self.vertex_offsets[index] = offset;
1221 }
1222
1223 self.dirty_flag.insert(DirtyStateFlag::VERTEX_BUFFERS);
1224 }
1225
bind_vertex_buffers(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1226 pub fn bind_vertex_buffers(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1227 if let Some(binding_count) = self.max_bindings {
1228 if self.vertex_buffers.len() >= binding_count as usize
1229 && self.vertex_strides.len() >= binding_count as usize
1230 {
1231 unsafe {
1232 context.IASetVertexBuffers(
1233 0,
1234 binding_count,
1235 self.vertex_buffers.as_ptr(),
1236 self.vertex_strides.as_ptr(),
1237 self.vertex_offsets.as_ptr(),
1238 );
1239 }
1240
1241 self.dirty_flag.remove(DirtyStateFlag::VERTEX_BUFFERS);
1242 }
1243 }
1244 }
1245
set_viewports(&mut self, viewports: &[d3d11::D3D11_VIEWPORT])1246 pub fn set_viewports(&mut self, viewports: &[d3d11::D3D11_VIEWPORT]) {
1247 self.viewports.clear();
1248 self.viewports.extend(viewports);
1249
1250 self.dirty_flag.insert(DirtyStateFlag::VIEWPORTS);
1251 }
1252
bind_viewports(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1253 pub fn bind_viewports(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1254 if let Some(ref pipeline) = self.graphics_pipeline {
1255 if let Some(ref viewport) = pipeline.baked_states.viewport {
1256 unsafe {
1257 context.RSSetViewports(1, [conv::map_viewport(&viewport)].as_ptr());
1258 }
1259 } else {
1260 unsafe {
1261 context.RSSetViewports(self.viewports.len() as u32, self.viewports.as_ptr());
1262 }
1263 }
1264 } else {
1265 unsafe {
1266 context.RSSetViewports(self.viewports.len() as u32, self.viewports.as_ptr());
1267 }
1268 }
1269
1270 self.dirty_flag.remove(DirtyStateFlag::VIEWPORTS);
1271 }
1272
set_render_targets( &mut self, render_targets: &[*mut d3d11::ID3D11RenderTargetView], depth_target: Option<*mut d3d11::ID3D11DepthStencilView>, )1273 pub fn set_render_targets(
1274 &mut self,
1275 render_targets: &[*mut d3d11::ID3D11RenderTargetView],
1276 depth_target: Option<*mut d3d11::ID3D11DepthStencilView>,
1277 ) {
1278 for (idx, &rt) in render_targets.iter().enumerate() {
1279 self.render_targets[idx] = rt;
1280 }
1281
1282 self.render_target_len = render_targets.len() as u32;
1283 self.depth_target = depth_target;
1284
1285 self.dirty_flag.insert(DirtyStateFlag::RENDER_TARGETS);
1286 }
1287
bind_render_targets(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1288 pub fn bind_render_targets(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1289 unsafe {
1290 context.OMSetRenderTargets(
1291 self.render_target_len,
1292 self.render_targets.as_ptr(),
1293 if let Some(dsv) = self.depth_target {
1294 dsv
1295 } else {
1296 ptr::null_mut()
1297 },
1298 );
1299 }
1300
1301 self.dirty_flag.remove(DirtyStateFlag::RENDER_TARGETS);
1302 }
1303
set_blend_factor(&mut self, factor: [f32; 4])1304 pub fn set_blend_factor(&mut self, factor: [f32; 4]) {
1305 self.blend_factor = Some(factor);
1306
1307 self.dirty_flag.insert(DirtyStateFlag::BLEND_STATE);
1308 }
1309
bind_blend_state(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1310 pub fn bind_blend_state(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1311 if let Some(blend) = self.current_blend {
1312 let blend_color = if let Some(ref pipeline) = self.graphics_pipeline {
1313 pipeline
1314 .baked_states
1315 .blend_color
1316 .or(self.blend_factor)
1317 .unwrap_or([0f32; 4])
1318 } else {
1319 self.blend_factor.unwrap_or([0f32; 4])
1320 };
1321
1322 // TODO: MSAA
1323 unsafe {
1324 context.OMSetBlendState(blend, &blend_color, !0);
1325 }
1326
1327 self.dirty_flag.remove(DirtyStateFlag::BLEND_STATE);
1328 }
1329 }
1330
set_graphics_pipeline(&mut self, pipeline: GraphicsPipeline)1331 pub fn set_graphics_pipeline(&mut self, pipeline: GraphicsPipeline) {
1332 self.graphics_pipeline = Some(pipeline);
1333
1334 self.dirty_flag.insert(DirtyStateFlag::GRAPHICS_PIPELINE);
1335 }
1336
bind_graphics_pipeline(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1337 pub fn bind_graphics_pipeline(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1338 if let Some(ref pipeline) = self.graphics_pipeline {
1339 self.vertex_strides.clear();
1340 self.vertex_strides.extend(&pipeline.strides);
1341
1342 self.required_bindings = Some(pipeline.required_bindings);
1343 self.max_bindings = Some(pipeline.max_vertex_bindings);
1344 };
1345
1346 self.bind_vertex_buffers(context);
1347
1348 if let Some(ref pipeline) = self.graphics_pipeline {
1349 unsafe {
1350 context.IASetPrimitiveTopology(pipeline.topology);
1351 context.IASetInputLayout(pipeline.input_layout.as_raw());
1352
1353 context.VSSetShader(pipeline.vs.as_raw(), ptr::null_mut(), 0);
1354 if let Some(ref ps) = pipeline.ps {
1355 context.PSSetShader(ps.as_raw(), ptr::null_mut(), 0);
1356 }
1357 if let Some(ref gs) = pipeline.gs {
1358 context.GSSetShader(gs.as_raw(), ptr::null_mut(), 0);
1359 }
1360 if let Some(ref hs) = pipeline.hs {
1361 context.HSSetShader(hs.as_raw(), ptr::null_mut(), 0);
1362 }
1363 if let Some(ref ds) = pipeline.ds {
1364 context.DSSetShader(ds.as_raw(), ptr::null_mut(), 0);
1365 }
1366
1367 context.RSSetState(pipeline.rasterizer_state.as_raw());
1368 if let Some(ref viewport) = pipeline.baked_states.viewport {
1369 context.RSSetViewports(1, [conv::map_viewport(&viewport)].as_ptr());
1370 }
1371 if let Some(ref scissor) = pipeline.baked_states.scissor {
1372 context.RSSetScissorRects(1, [conv::map_rect(&scissor)].as_ptr());
1373 }
1374
1375 if let Some((ref state, reference)) = pipeline.depth_stencil_state {
1376 let stencil_ref = if let pso::State::Static(reference) = reference {
1377 reference
1378 } else {
1379 self.stencil_ref.unwrap_or(0)
1380 };
1381
1382 context.OMSetDepthStencilState(state.as_raw(), stencil_ref);
1383 }
1384 self.current_blend = Some(pipeline.blend_state.as_raw());
1385 }
1386 };
1387
1388 self.bind_blend_state(context);
1389
1390 self.dirty_flag.remove(DirtyStateFlag::GRAPHICS_PIPELINE);
1391 }
1392
bind(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>)1393 pub fn bind(&mut self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
1394 if self.dirty_flag.contains(DirtyStateFlag::RENDER_TARGETS) {
1395 self.bind_render_targets(context);
1396 }
1397
1398 if self.dirty_flag.contains(DirtyStateFlag::GRAPHICS_PIPELINE) {
1399 self.bind_graphics_pipeline(context);
1400 }
1401
1402 if self.dirty_flag.contains(DirtyStateFlag::VERTEX_BUFFERS) {
1403 self.bind_vertex_buffers(context);
1404 }
1405
1406 if self.dirty_flag.contains(DirtyStateFlag::VIEWPORTS) {
1407 self.bind_viewports(context);
1408 }
1409 }
1410 }
1411
1412 pub struct CommandBuffer {
1413 // TODO: better way of sharing
1414 internal: internal::Internal,
1415 context: ComPtr<d3d11::ID3D11DeviceContext>,
1416 list: RefCell<Option<ComPtr<d3d11::ID3D11CommandList>>>,
1417
1418 // since coherent memory needs to be synchronized at submission, we need to gather up all
1419 // coherent resources that are used in the command buffer and flush/invalidate them accordingly
1420 // before executing.
1421 flush_coherent_memory: Vec<MemoryFlush>,
1422 invalidate_coherent_memory: Vec<MemoryInvalidate>,
1423
1424 // holds information about the active render pass
1425 render_pass_cache: Option<RenderPassCache>,
1426
1427 cache: CommandBufferState,
1428
1429 one_time_submit: bool,
1430 }
1431
1432 impl fmt::Debug for CommandBuffer {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result1433 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1434 fmt.write_str("CommandBuffer")
1435 }
1436 }
1437
1438 unsafe impl Send for CommandBuffer {}
1439 unsafe impl Sync for CommandBuffer {}
1440
1441 impl CommandBuffer {
create_deferred(device: ComPtr<d3d11::ID3D11Device>, internal: internal::Internal) -> Self1442 fn create_deferred(device: ComPtr<d3d11::ID3D11Device>, internal: internal::Internal) -> Self {
1443 let mut context: *mut d3d11::ID3D11DeviceContext = ptr::null_mut();
1444 let hr =
1445 unsafe { device.CreateDeferredContext(0, &mut context as *mut *mut _ as *mut *mut _) };
1446 assert_eq!(hr, winerror::S_OK);
1447
1448 CommandBuffer {
1449 internal,
1450 context: unsafe { ComPtr::from_raw(context) },
1451 list: RefCell::new(None),
1452 flush_coherent_memory: Vec::new(),
1453 invalidate_coherent_memory: Vec::new(),
1454 render_pass_cache: None,
1455 cache: CommandBufferState::new(),
1456 one_time_submit: false,
1457 }
1458 }
1459
as_raw_list(&self) -> ComPtr<d3d11::ID3D11CommandList>1460 fn as_raw_list(&self) -> ComPtr<d3d11::ID3D11CommandList> {
1461 if self.one_time_submit {
1462 self.list.replace(None).unwrap()
1463 } else {
1464 self.list.borrow().clone().unwrap()
1465 }
1466 }
1467
defer_coherent_flush(&mut self, buffer: &Buffer)1468 fn defer_coherent_flush(&mut self, buffer: &Buffer) {
1469 if !self
1470 .flush_coherent_memory
1471 .iter()
1472 .any(|m| m.buffer == buffer.internal.raw)
1473 {
1474 self.flush_coherent_memory.push(MemoryFlush {
1475 host_memory: buffer.host_ptr,
1476 sync_range: SyncRange::Whole,
1477 buffer: buffer.internal.raw,
1478 });
1479 }
1480 }
1481
defer_coherent_invalidate(&mut self, buffer: &Buffer)1482 fn defer_coherent_invalidate(&mut self, buffer: &Buffer) {
1483 if !self
1484 .invalidate_coherent_memory
1485 .iter()
1486 .any(|m| m.buffer == buffer.internal.raw)
1487 {
1488 self.invalidate_coherent_memory.push(MemoryInvalidate {
1489 working_buffer: Some(self.internal.working_buffer.clone()),
1490 working_buffer_size: self.internal.working_buffer_size,
1491 host_memory: buffer.host_ptr,
1492 sync_range: buffer.bound_range.clone(),
1493 buffer: buffer.internal.raw,
1494 });
1495 }
1496 }
1497
reset(&mut self)1498 fn reset(&mut self) {
1499 self.flush_coherent_memory.clear();
1500 self.invalidate_coherent_memory.clear();
1501 self.render_pass_cache = None;
1502 self.cache.clear();
1503 }
1504 }
1505
1506 impl command::CommandBuffer<Backend> for CommandBuffer {
begin( &mut self, flags: command::CommandBufferFlags, _info: command::CommandBufferInheritanceInfo<Backend>, )1507 unsafe fn begin(
1508 &mut self,
1509 flags: command::CommandBufferFlags,
1510 _info: command::CommandBufferInheritanceInfo<Backend>,
1511 ) {
1512 self.one_time_submit = flags.contains(command::CommandBufferFlags::ONE_TIME_SUBMIT);
1513 self.reset();
1514 }
1515
finish(&mut self)1516 unsafe fn finish(&mut self) {
1517 let mut list = ptr::null_mut();
1518 let hr = self
1519 .context
1520 .FinishCommandList(FALSE, &mut list as *mut *mut _ as *mut *mut _);
1521 assert_eq!(hr, winerror::S_OK);
1522
1523 self.list.replace(Some(ComPtr::from_raw(list)));
1524 }
1525
reset(&mut self, _release_resources: bool)1526 unsafe fn reset(&mut self, _release_resources: bool) {
1527 self.reset();
1528 }
1529
begin_render_pass<T>( &mut self, render_pass: &RenderPass, framebuffer: &Framebuffer, target_rect: pso::Rect, clear_values: T, _first_subpass: command::SubpassContents, ) where T: IntoIterator, T::Item: Borrow<command::ClearValue>,1530 unsafe fn begin_render_pass<T>(
1531 &mut self,
1532 render_pass: &RenderPass,
1533 framebuffer: &Framebuffer,
1534 target_rect: pso::Rect,
1535 clear_values: T,
1536 _first_subpass: command::SubpassContents,
1537 ) where
1538 T: IntoIterator,
1539 T::Item: Borrow<command::ClearValue>,
1540 {
1541 use pass::AttachmentLoadOp as Alo;
1542
1543 let mut clear_iter = clear_values.into_iter();
1544 let mut attachment_clears = Vec::new();
1545
1546 for (idx, attachment) in render_pass.attachments.iter().enumerate() {
1547 //let attachment = render_pass.attachments[attachment_ref];
1548 let format = attachment.format.unwrap();
1549
1550 let subpass_id = render_pass
1551 .subpasses
1552 .iter()
1553 .position(|sp| sp.is_using(idx))
1554 .map(|i| i as pass::SubpassId);
1555
1556 if attachment.has_clears() {
1557 let value = *clear_iter.next().unwrap().borrow();
1558
1559 match (attachment.ops.load, attachment.stencil_ops.load) {
1560 (Alo::Clear, Alo::Clear) if format.is_depth() => {
1561 attachment_clears.push(AttachmentClear {
1562 subpass_id,
1563 attachment_id: idx,
1564 raw: command::AttachmentClear::DepthStencil {
1565 depth: Some(value.depth_stencil.depth),
1566 stencil: Some(value.depth_stencil.stencil),
1567 },
1568 });
1569 }
1570 (Alo::Clear, Alo::Clear) => {
1571 attachment_clears.push(AttachmentClear {
1572 subpass_id,
1573 attachment_id: idx,
1574 raw: command::AttachmentClear::Color {
1575 index: idx,
1576 value: value.color,
1577 },
1578 });
1579
1580 attachment_clears.push(AttachmentClear {
1581 subpass_id,
1582 attachment_id: idx,
1583 raw: command::AttachmentClear::DepthStencil {
1584 depth: None,
1585 stencil: Some(value.depth_stencil.stencil),
1586 },
1587 });
1588 }
1589 (Alo::Clear, _) if format.is_depth() => {
1590 attachment_clears.push(AttachmentClear {
1591 subpass_id,
1592 attachment_id: idx,
1593 raw: command::AttachmentClear::DepthStencil {
1594 depth: Some(value.depth_stencil.depth),
1595 stencil: None,
1596 },
1597 });
1598 }
1599 (Alo::Clear, _) => {
1600 attachment_clears.push(AttachmentClear {
1601 subpass_id,
1602 attachment_id: idx,
1603 raw: command::AttachmentClear::Color {
1604 index: idx,
1605 value: value.color,
1606 },
1607 });
1608 }
1609 (_, Alo::Clear) => {
1610 attachment_clears.push(AttachmentClear {
1611 subpass_id,
1612 attachment_id: idx,
1613 raw: command::AttachmentClear::DepthStencil {
1614 depth: None,
1615 stencil: Some(value.depth_stencil.stencil),
1616 },
1617 });
1618 }
1619 _ => {}
1620 }
1621 }
1622 }
1623
1624 self.render_pass_cache = Some(RenderPassCache {
1625 render_pass: render_pass.clone(),
1626 framebuffer: framebuffer.clone(),
1627 attachment_clear_values: attachment_clears,
1628 target_rect,
1629 current_subpass: 0,
1630 });
1631
1632 if let Some(ref mut current_render_pass) = self.render_pass_cache {
1633 current_render_pass.start_subpass(&mut self.internal, &self.context, &mut self.cache);
1634 }
1635 }
1636
next_subpass(&mut self, _contents: command::SubpassContents)1637 unsafe fn next_subpass(&mut self, _contents: command::SubpassContents) {
1638 if let Some(ref mut current_render_pass) = self.render_pass_cache {
1639 // TODO: resolve msaa
1640 current_render_pass.next_subpass();
1641 current_render_pass.start_subpass(&mut self.internal, &self.context, &mut self.cache);
1642 }
1643 }
1644
end_render_pass(&mut self)1645 unsafe fn end_render_pass(&mut self) {
1646 self.context
1647 .OMSetRenderTargets(8, [ptr::null_mut(); 8].as_ptr(), ptr::null_mut());
1648
1649 self.render_pass_cache = None;
1650 }
1651
pipeline_barrier<'a, T>( &mut self, _stages: Range<pso::PipelineStage>, _dependencies: memory::Dependencies, _barriers: T, ) where T: IntoIterator, T::Item: Borrow<memory::Barrier<'a, Backend>>,1652 unsafe fn pipeline_barrier<'a, T>(
1653 &mut self,
1654 _stages: Range<pso::PipelineStage>,
1655 _dependencies: memory::Dependencies,
1656 _barriers: T,
1657 ) where
1658 T: IntoIterator,
1659 T::Item: Borrow<memory::Barrier<'a, Backend>>,
1660 {
1661 // TODO: should we track and assert on resource states?
1662 // unimplemented!()
1663 }
1664
clear_image<T>( &mut self, image: &Image, _: image::Layout, value: command::ClearValue, subresource_ranges: T, ) where T: IntoIterator, T::Item: Borrow<image::SubresourceRange>,1665 unsafe fn clear_image<T>(
1666 &mut self,
1667 image: &Image,
1668 _: image::Layout,
1669 value: command::ClearValue,
1670 subresource_ranges: T,
1671 ) where
1672 T: IntoIterator,
1673 T::Item: Borrow<image::SubresourceRange>,
1674 {
1675 for range in subresource_ranges {
1676 let range = range.borrow();
1677
1678 // TODO: clear Int/Uint depending on format
1679 if range.aspects.contains(format::Aspects::COLOR) {
1680 for layer in range.layers.clone() {
1681 for level in range.levels.clone() {
1682 self.context.ClearRenderTargetView(
1683 image.get_rtv(level, layer).unwrap().as_raw(),
1684 &value.color.float32,
1685 );
1686 }
1687 }
1688 }
1689
1690 let mut depth_stencil_flags = 0;
1691 if range.aspects.contains(format::Aspects::DEPTH) {
1692 depth_stencil_flags |= d3d11::D3D11_CLEAR_DEPTH;
1693 }
1694
1695 if range.aspects.contains(format::Aspects::STENCIL) {
1696 depth_stencil_flags |= d3d11::D3D11_CLEAR_STENCIL;
1697 }
1698
1699 if depth_stencil_flags != 0 {
1700 for layer in range.layers.clone() {
1701 for level in range.levels.clone() {
1702 self.context.ClearDepthStencilView(
1703 image.get_dsv(level, layer).unwrap().as_raw(),
1704 depth_stencil_flags,
1705 value.depth_stencil.depth,
1706 value.depth_stencil.stencil as _,
1707 );
1708 }
1709 }
1710 }
1711 }
1712 }
1713
clear_attachments<T, U>(&mut self, clears: T, rects: U) where T: IntoIterator, T::Item: Borrow<command::AttachmentClear>, U: IntoIterator, U::Item: Borrow<pso::ClearRect>,1714 unsafe fn clear_attachments<T, U>(&mut self, clears: T, rects: U)
1715 where
1716 T: IntoIterator,
1717 T::Item: Borrow<command::AttachmentClear>,
1718 U: IntoIterator,
1719 U::Item: Borrow<pso::ClearRect>,
1720 {
1721 if let Some(ref pass) = self.render_pass_cache {
1722 self.cache.dirty_flag.insert(
1723 DirtyStateFlag::GRAPHICS_PIPELINE
1724 | DirtyStateFlag::VIEWPORTS
1725 | DirtyStateFlag::RENDER_TARGETS,
1726 );
1727 self.internal
1728 .clear_attachments(&self.context, clears, rects, pass);
1729 self.cache.bind(&self.context);
1730 } else {
1731 panic!("`clear_attachments` can only be called inside a renderpass")
1732 }
1733 }
1734
resolve_image<T>( &mut self, _src: &Image, _src_layout: image::Layout, _dst: &Image, _dst_layout: image::Layout, _regions: T, ) where T: IntoIterator, T::Item: Borrow<command::ImageResolve>,1735 unsafe fn resolve_image<T>(
1736 &mut self,
1737 _src: &Image,
1738 _src_layout: image::Layout,
1739 _dst: &Image,
1740 _dst_layout: image::Layout,
1741 _regions: T,
1742 ) where
1743 T: IntoIterator,
1744 T::Item: Borrow<command::ImageResolve>,
1745 {
1746 unimplemented!()
1747 }
1748
blit_image<T>( &mut self, src: &Image, _src_layout: image::Layout, dst: &Image, _dst_layout: image::Layout, filter: image::Filter, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::ImageBlit>,1749 unsafe fn blit_image<T>(
1750 &mut self,
1751 src: &Image,
1752 _src_layout: image::Layout,
1753 dst: &Image,
1754 _dst_layout: image::Layout,
1755 filter: image::Filter,
1756 regions: T,
1757 ) where
1758 T: IntoIterator,
1759 T::Item: Borrow<command::ImageBlit>,
1760 {
1761 self.cache
1762 .dirty_flag
1763 .insert(DirtyStateFlag::GRAPHICS_PIPELINE);
1764
1765 self.internal
1766 .blit_2d_image(&self.context, src, dst, filter, regions);
1767
1768 self.cache.bind(&self.context);
1769 }
1770
bind_index_buffer(&mut self, ibv: buffer::IndexBufferView<Backend>)1771 unsafe fn bind_index_buffer(&mut self, ibv: buffer::IndexBufferView<Backend>) {
1772 self.context.IASetIndexBuffer(
1773 ibv.buffer.internal.raw,
1774 conv::map_index_type(ibv.index_type),
1775 ibv.range.offset as u32,
1776 );
1777 }
1778
bind_vertex_buffers<I, T>(&mut self, first_binding: pso::BufferIndex, buffers: I) where I: IntoIterator<Item = (T, buffer::SubRange)>, T: Borrow<Buffer>,1779 unsafe fn bind_vertex_buffers<I, T>(&mut self, first_binding: pso::BufferIndex, buffers: I)
1780 where
1781 I: IntoIterator<Item = (T, buffer::SubRange)>,
1782 T: Borrow<Buffer>,
1783 {
1784 for (i, (buf, sub)) in buffers.into_iter().enumerate() {
1785 let idx = i + first_binding as usize;
1786 let buf = buf.borrow();
1787
1788 if buf.properties.contains(memory::Properties::COHERENT) {
1789 self.defer_coherent_flush(buf);
1790 }
1791
1792 self.cache
1793 .set_vertex_buffer(idx, sub.offset as u32, buf.internal.raw);
1794 }
1795
1796 self.cache.bind_vertex_buffers(&self.context);
1797 }
1798
set_viewports<T>(&mut self, _first_viewport: u32, viewports: T) where T: IntoIterator, T::Item: Borrow<pso::Viewport>,1799 unsafe fn set_viewports<T>(&mut self, _first_viewport: u32, viewports: T)
1800 where
1801 T: IntoIterator,
1802 T::Item: Borrow<pso::Viewport>,
1803 {
1804 let viewports = viewports
1805 .into_iter()
1806 .map(|v| {
1807 let v = v.borrow();
1808 conv::map_viewport(v)
1809 })
1810 .collect::<Vec<_>>();
1811
1812 // TODO: DX only lets us set all VPs at once, so cache in slice?
1813 self.cache.set_viewports(&viewports);
1814 self.cache.bind_viewports(&self.context);
1815 }
1816
set_scissors<T>(&mut self, _first_scissor: u32, scissors: T) where T: IntoIterator, T::Item: Borrow<pso::Rect>,1817 unsafe fn set_scissors<T>(&mut self, _first_scissor: u32, scissors: T)
1818 where
1819 T: IntoIterator,
1820 T::Item: Borrow<pso::Rect>,
1821 {
1822 let scissors = scissors
1823 .into_iter()
1824 .map(|s| {
1825 let s = s.borrow();
1826 conv::map_rect(s)
1827 })
1828 .collect::<Vec<_>>();
1829
1830 // TODO: same as for viewports
1831 self.context
1832 .RSSetScissorRects(scissors.len() as _, scissors.as_ptr());
1833 }
1834
set_blend_constants(&mut self, color: pso::ColorValue)1835 unsafe fn set_blend_constants(&mut self, color: pso::ColorValue) {
1836 self.cache.set_blend_factor(color);
1837 self.cache.bind_blend_state(&self.context);
1838 }
1839
set_stencil_reference(&mut self, _faces: pso::Face, value: pso::StencilValue)1840 unsafe fn set_stencil_reference(&mut self, _faces: pso::Face, value: pso::StencilValue) {
1841 self.cache.stencil_ref = Some(value);
1842 }
1843
set_stencil_read_mask(&mut self, _faces: pso::Face, value: pso::StencilValue)1844 unsafe fn set_stencil_read_mask(&mut self, _faces: pso::Face, value: pso::StencilValue) {
1845 self.cache.stencil_read_mask = Some(value);
1846 }
1847
set_stencil_write_mask(&mut self, _faces: pso::Face, value: pso::StencilValue)1848 unsafe fn set_stencil_write_mask(&mut self, _faces: pso::Face, value: pso::StencilValue) {
1849 self.cache.stencil_write_mask = Some(value);
1850 }
1851
set_depth_bounds(&mut self, _bounds: Range<f32>)1852 unsafe fn set_depth_bounds(&mut self, _bounds: Range<f32>) {
1853 unimplemented!()
1854 }
1855
set_line_width(&mut self, width: f32)1856 unsafe fn set_line_width(&mut self, width: f32) {
1857 validate_line_width(width);
1858 }
1859
set_depth_bias(&mut self, _depth_bias: pso::DepthBias)1860 unsafe fn set_depth_bias(&mut self, _depth_bias: pso::DepthBias) {
1861 // TODO:
1862 // unimplemented!()
1863 }
1864
bind_graphics_pipeline(&mut self, pipeline: &GraphicsPipeline)1865 unsafe fn bind_graphics_pipeline(&mut self, pipeline: &GraphicsPipeline) {
1866 self.cache.set_graphics_pipeline(pipeline.clone());
1867 self.cache.bind_graphics_pipeline(&self.context);
1868 }
1869
bind_graphics_descriptor_sets<'a, I, J>( &mut self, layout: &PipelineLayout, first_set: usize, sets: I, _offsets: J, ) where I: IntoIterator, I::Item: Borrow<DescriptorSet>, J: IntoIterator, J::Item: Borrow<command::DescriptorSetOffset>,1870 unsafe fn bind_graphics_descriptor_sets<'a, I, J>(
1871 &mut self,
1872 layout: &PipelineLayout,
1873 first_set: usize,
1874 sets: I,
1875 _offsets: J,
1876 ) where
1877 I: IntoIterator,
1878 I::Item: Borrow<DescriptorSet>,
1879 J: IntoIterator,
1880 J::Item: Borrow<command::DescriptorSetOffset>,
1881 {
1882 let _scope = debug_scope!(&self.context, "BindGraphicsDescriptorSets");
1883
1884 // TODO: find a better solution to invalidating old bindings..
1885 self.context.CSSetUnorderedAccessViews(
1886 0,
1887 16,
1888 [ptr::null_mut(); 16].as_ptr(),
1889 ptr::null_mut(),
1890 );
1891
1892 //let offsets: Vec<command::DescriptorSetOffset> = offsets.into_iter().map(|o| *o.borrow()).collect();
1893
1894 for (set, info) in sets.into_iter().zip(&layout.sets[first_set ..]) {
1895 let set = set.borrow();
1896
1897 {
1898 let coherent_buffers = set.coherent_buffers.lock();
1899 for sync in coherent_buffers.flush_coherent_buffers.borrow().iter() {
1900 // TODO: merge sync range if a flush already exists
1901 if !self
1902 .flush_coherent_memory
1903 .iter()
1904 .any(|m| m.buffer == sync.device_buffer)
1905 {
1906 self.flush_coherent_memory.push(MemoryFlush {
1907 host_memory: sync.host_ptr,
1908 sync_range: sync.range.clone(),
1909 buffer: sync.device_buffer,
1910 });
1911 }
1912 }
1913
1914 for sync in coherent_buffers.invalidate_coherent_buffers.borrow().iter() {
1915 if !self
1916 .invalidate_coherent_memory
1917 .iter()
1918 .any(|m| m.buffer == sync.device_buffer)
1919 {
1920 self.invalidate_coherent_memory.push(MemoryInvalidate {
1921 working_buffer: Some(self.internal.working_buffer.clone()),
1922 working_buffer_size: self.internal.working_buffer_size,
1923 host_memory: sync.host_ptr,
1924 sync_range: sync.range.clone(),
1925 buffer: sync.device_buffer,
1926 });
1927 }
1928 }
1929 }
1930
1931 // TODO: offsets
1932
1933 if let Some(rd) = info.registers.vs.c.as_some() {
1934 self.context.VSSetConstantBuffers(
1935 rd.res_index as u32,
1936 rd.count as u32,
1937 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1938 );
1939 }
1940 if let Some(rd) = info.registers.vs.t.as_some() {
1941 self.context.VSSetShaderResources(
1942 rd.res_index as u32,
1943 rd.count as u32,
1944 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1945 );
1946 }
1947 if let Some(rd) = info.registers.vs.s.as_some() {
1948 self.context.VSSetSamplers(
1949 rd.res_index as u32,
1950 rd.count as u32,
1951 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1952 );
1953 }
1954
1955 if let Some(rd) = info.registers.ps.c.as_some() {
1956 self.context.PSSetConstantBuffers(
1957 rd.res_index as u32,
1958 rd.count as u32,
1959 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1960 );
1961 }
1962 if let Some(rd) = info.registers.ps.t.as_some() {
1963 self.context.PSSetShaderResources(
1964 rd.res_index as u32,
1965 rd.count as u32,
1966 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1967 );
1968 }
1969 if let Some(rd) = info.registers.ps.s.as_some() {
1970 self.context.PSSetSamplers(
1971 rd.res_index as u32,
1972 rd.count as u32,
1973 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
1974 );
1975 }
1976 }
1977 }
1978
bind_compute_pipeline(&mut self, pipeline: &ComputePipeline)1979 unsafe fn bind_compute_pipeline(&mut self, pipeline: &ComputePipeline) {
1980 self.context
1981 .CSSetShader(pipeline.cs.as_raw(), ptr::null_mut(), 0);
1982 }
1983
bind_compute_descriptor_sets<I, J>( &mut self, layout: &PipelineLayout, first_set: usize, sets: I, _offsets: J, ) where I: IntoIterator, I::Item: Borrow<DescriptorSet>, J: IntoIterator, J::Item: Borrow<command::DescriptorSetOffset>,1984 unsafe fn bind_compute_descriptor_sets<I, J>(
1985 &mut self,
1986 layout: &PipelineLayout,
1987 first_set: usize,
1988 sets: I,
1989 _offsets: J,
1990 ) where
1991 I: IntoIterator,
1992 I::Item: Borrow<DescriptorSet>,
1993 J: IntoIterator,
1994 J::Item: Borrow<command::DescriptorSetOffset>,
1995 {
1996 let _scope = debug_scope!(&self.context, "BindComputeDescriptorSets");
1997
1998 self.context.CSSetUnorderedAccessViews(
1999 0,
2000 16,
2001 [ptr::null_mut(); 16].as_ptr(),
2002 ptr::null_mut(),
2003 );
2004 for (set, info) in sets.into_iter().zip(&layout.sets[first_set ..]) {
2005 let set = set.borrow();
2006
2007 {
2008 let coherent_buffers = set.coherent_buffers.lock();
2009 for sync in coherent_buffers.flush_coherent_buffers.borrow().iter() {
2010 if !self
2011 .flush_coherent_memory
2012 .iter()
2013 .any(|m| m.buffer == sync.device_buffer)
2014 {
2015 self.flush_coherent_memory.push(MemoryFlush {
2016 host_memory: sync.host_ptr,
2017 sync_range: sync.range.clone(),
2018 buffer: sync.device_buffer,
2019 });
2020 }
2021 }
2022
2023 for sync in coherent_buffers.invalidate_coherent_buffers.borrow().iter() {
2024 if !self
2025 .invalidate_coherent_memory
2026 .iter()
2027 .any(|m| m.buffer == sync.device_buffer)
2028 {
2029 self.invalidate_coherent_memory.push(MemoryInvalidate {
2030 working_buffer: Some(self.internal.working_buffer.clone()),
2031 working_buffer_size: self.internal.working_buffer_size,
2032 host_memory: sync.host_ptr,
2033 sync_range: sync.range.clone(),
2034 buffer: sync.device_buffer,
2035 });
2036 }
2037 }
2038 }
2039
2040 // TODO: offsets
2041
2042 if let Some(rd) = info.registers.cs.c.as_some() {
2043 self.context.CSSetConstantBuffers(
2044 rd.res_index as u32,
2045 rd.count as u32,
2046 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
2047 );
2048 }
2049 if let Some(rd) = info.registers.cs.t.as_some() {
2050 self.context.CSSetShaderResources(
2051 rd.res_index as u32,
2052 rd.count as u32,
2053 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
2054 );
2055 }
2056 if let Some(rd) = info.registers.cs.u.as_some() {
2057 self.context.CSSetUnorderedAccessViews(
2058 rd.res_index as u32,
2059 rd.count as u32,
2060 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
2061 ptr::null_mut(),
2062 );
2063 }
2064 if let Some(rd) = info.registers.cs.s.as_some() {
2065 self.context.CSSetSamplers(
2066 rd.res_index as u32,
2067 rd.count as u32,
2068 set.handles.offset(rd.pool_offset as isize) as *const *mut _ as *const *mut _,
2069 );
2070 }
2071 }
2072 }
2073
dispatch(&mut self, count: WorkGroupCount)2074 unsafe fn dispatch(&mut self, count: WorkGroupCount) {
2075 self.context.Dispatch(count[0], count[1], count[2]);
2076 }
2077
dispatch_indirect(&mut self, _buffer: &Buffer, _offset: buffer::Offset)2078 unsafe fn dispatch_indirect(&mut self, _buffer: &Buffer, _offset: buffer::Offset) {
2079 unimplemented!()
2080 }
2081
fill_buffer(&mut self, _buffer: &Buffer, _sub: buffer::SubRange, _data: u32)2082 unsafe fn fill_buffer(&mut self, _buffer: &Buffer, _sub: buffer::SubRange, _data: u32) {
2083 unimplemented!()
2084 }
2085
update_buffer(&mut self, _buffer: &Buffer, _offset: buffer::Offset, _data: &[u8])2086 unsafe fn update_buffer(&mut self, _buffer: &Buffer, _offset: buffer::Offset, _data: &[u8]) {
2087 unimplemented!()
2088 }
2089
copy_buffer<T>(&mut self, src: &Buffer, dst: &Buffer, regions: T) where T: IntoIterator, T::Item: Borrow<command::BufferCopy>,2090 unsafe fn copy_buffer<T>(&mut self, src: &Buffer, dst: &Buffer, regions: T)
2091 where
2092 T: IntoIterator,
2093 T::Item: Borrow<command::BufferCopy>,
2094 {
2095 if src.properties.contains(memory::Properties::COHERENT) {
2096 self.defer_coherent_flush(src);
2097 }
2098
2099 for region in regions.into_iter() {
2100 let info = region.borrow();
2101 let dst_box = d3d11::D3D11_BOX {
2102 left: info.src as _,
2103 top: 0,
2104 front: 0,
2105 right: (info.src + info.size) as _,
2106 bottom: 1,
2107 back: 1,
2108 };
2109
2110 self.context.CopySubresourceRegion(
2111 dst.internal.raw as _,
2112 0,
2113 info.dst as _,
2114 0,
2115 0,
2116 src.internal.raw as _,
2117 0,
2118 &dst_box,
2119 );
2120
2121 if let Some(disjoint_cb) = dst.internal.disjoint_cb {
2122 self.context.CopySubresourceRegion(
2123 disjoint_cb as _,
2124 0,
2125 info.dst as _,
2126 0,
2127 0,
2128 src.internal.raw as _,
2129 0,
2130 &dst_box,
2131 );
2132 }
2133 }
2134 }
2135
copy_image<T>( &mut self, src: &Image, _: image::Layout, dst: &Image, _: image::Layout, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::ImageCopy>,2136 unsafe fn copy_image<T>(
2137 &mut self,
2138 src: &Image,
2139 _: image::Layout,
2140 dst: &Image,
2141 _: image::Layout,
2142 regions: T,
2143 ) where
2144 T: IntoIterator,
2145 T::Item: Borrow<command::ImageCopy>,
2146 {
2147 self.internal
2148 .copy_image_2d(&self.context, src, dst, regions);
2149 }
2150
copy_buffer_to_image<T>( &mut self, buffer: &Buffer, image: &Image, _: image::Layout, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::BufferImageCopy>,2151 unsafe fn copy_buffer_to_image<T>(
2152 &mut self,
2153 buffer: &Buffer,
2154 image: &Image,
2155 _: image::Layout,
2156 regions: T,
2157 ) where
2158 T: IntoIterator,
2159 T::Item: Borrow<command::BufferImageCopy>,
2160 {
2161 if buffer.properties.contains(memory::Properties::COHERENT) {
2162 self.defer_coherent_flush(buffer);
2163 }
2164
2165 self.internal
2166 .copy_buffer_to_image_2d(&self.context, buffer, image, regions);
2167 }
2168
copy_image_to_buffer<T>( &mut self, image: &Image, _: image::Layout, buffer: &Buffer, regions: T, ) where T: IntoIterator, T::Item: Borrow<command::BufferImageCopy>,2169 unsafe fn copy_image_to_buffer<T>(
2170 &mut self,
2171 image: &Image,
2172 _: image::Layout,
2173 buffer: &Buffer,
2174 regions: T,
2175 ) where
2176 T: IntoIterator,
2177 T::Item: Borrow<command::BufferImageCopy>,
2178 {
2179 if buffer.properties.contains(memory::Properties::COHERENT) {
2180 self.defer_coherent_invalidate(buffer);
2181 }
2182
2183 self.internal
2184 .copy_image_2d_to_buffer(&self.context, image, buffer, regions);
2185 }
2186
draw(&mut self, vertices: Range<VertexCount>, instances: Range<InstanceCount>)2187 unsafe fn draw(&mut self, vertices: Range<VertexCount>, instances: Range<InstanceCount>) {
2188 self.context.DrawInstanced(
2189 vertices.end - vertices.start,
2190 instances.end - instances.start,
2191 vertices.start,
2192 instances.start,
2193 );
2194 }
2195
draw_indexed( &mut self, indices: Range<IndexCount>, base_vertex: VertexOffset, instances: Range<InstanceCount>, )2196 unsafe fn draw_indexed(
2197 &mut self,
2198 indices: Range<IndexCount>,
2199 base_vertex: VertexOffset,
2200 instances: Range<InstanceCount>,
2201 ) {
2202 self.context.DrawIndexedInstanced(
2203 indices.end - indices.start,
2204 instances.end - instances.start,
2205 indices.start,
2206 base_vertex,
2207 instances.start,
2208 );
2209 }
2210
draw_indirect( &mut self, _buffer: &Buffer, _offset: buffer::Offset, _draw_count: DrawCount, _stride: u32, )2211 unsafe fn draw_indirect(
2212 &mut self,
2213 _buffer: &Buffer,
2214 _offset: buffer::Offset,
2215 _draw_count: DrawCount,
2216 _stride: u32,
2217 ) {
2218 unimplemented!()
2219 }
2220
draw_indexed_indirect( &mut self, _buffer: &Buffer, _offset: buffer::Offset, _draw_count: DrawCount, _stride: u32, )2221 unsafe fn draw_indexed_indirect(
2222 &mut self,
2223 _buffer: &Buffer,
2224 _offset: buffer::Offset,
2225 _draw_count: DrawCount,
2226 _stride: u32,
2227 ) {
2228 unimplemented!()
2229 }
2230
set_event(&mut self, _: &(), _: pso::PipelineStage)2231 unsafe fn set_event(&mut self, _: &(), _: pso::PipelineStage) {
2232 unimplemented!()
2233 }
2234
reset_event(&mut self, _: &(), _: pso::PipelineStage)2235 unsafe fn reset_event(&mut self, _: &(), _: pso::PipelineStage) {
2236 unimplemented!()
2237 }
2238
wait_events<'a, I, J>(&mut self, _: I, _: Range<pso::PipelineStage>, _: J) where I: IntoIterator, I::Item: Borrow<()>, J: IntoIterator, J::Item: Borrow<memory::Barrier<'a, Backend>>,2239 unsafe fn wait_events<'a, I, J>(&mut self, _: I, _: Range<pso::PipelineStage>, _: J)
2240 where
2241 I: IntoIterator,
2242 I::Item: Borrow<()>,
2243 J: IntoIterator,
2244 J::Item: Borrow<memory::Barrier<'a, Backend>>,
2245 {
2246 unimplemented!()
2247 }
2248
begin_query(&mut self, _query: query::Query<Backend>, _flags: query::ControlFlags)2249 unsafe fn begin_query(&mut self, _query: query::Query<Backend>, _flags: query::ControlFlags) {
2250 unimplemented!()
2251 }
2252
end_query(&mut self, _query: query::Query<Backend>)2253 unsafe fn end_query(&mut self, _query: query::Query<Backend>) {
2254 unimplemented!()
2255 }
2256
reset_query_pool(&mut self, _pool: &QueryPool, _queries: Range<query::Id>)2257 unsafe fn reset_query_pool(&mut self, _pool: &QueryPool, _queries: Range<query::Id>) {
2258 unimplemented!()
2259 }
2260
copy_query_pool_results( &mut self, _pool: &QueryPool, _queries: Range<query::Id>, _buffer: &Buffer, _offset: buffer::Offset, _stride: buffer::Offset, _flags: query::ResultFlags, )2261 unsafe fn copy_query_pool_results(
2262 &mut self,
2263 _pool: &QueryPool,
2264 _queries: Range<query::Id>,
2265 _buffer: &Buffer,
2266 _offset: buffer::Offset,
2267 _stride: buffer::Offset,
2268 _flags: query::ResultFlags,
2269 ) {
2270 unimplemented!()
2271 }
2272
write_timestamp(&mut self, _: pso::PipelineStage, _query: query::Query<Backend>)2273 unsafe fn write_timestamp(&mut self, _: pso::PipelineStage, _query: query::Query<Backend>) {
2274 unimplemented!()
2275 }
2276
push_graphics_constants( &mut self, _layout: &PipelineLayout, _stages: pso::ShaderStageFlags, _offset: u32, _constants: &[u32], )2277 unsafe fn push_graphics_constants(
2278 &mut self,
2279 _layout: &PipelineLayout,
2280 _stages: pso::ShaderStageFlags,
2281 _offset: u32,
2282 _constants: &[u32],
2283 ) {
2284 // unimplemented!()
2285 }
2286
push_compute_constants( &mut self, _layout: &PipelineLayout, _offset: u32, _constants: &[u32], )2287 unsafe fn push_compute_constants(
2288 &mut self,
2289 _layout: &PipelineLayout,
2290 _offset: u32,
2291 _constants: &[u32],
2292 ) {
2293 unimplemented!()
2294 }
2295
execute_commands<'a, T, I>(&mut self, _buffers: I) where T: 'a + Borrow<CommandBuffer>, I: IntoIterator<Item = &'a T>,2296 unsafe fn execute_commands<'a, T, I>(&mut self, _buffers: I)
2297 where
2298 T: 'a + Borrow<CommandBuffer>,
2299 I: IntoIterator<Item = &'a T>,
2300 {
2301 unimplemented!()
2302 }
2303
insert_debug_marker(&mut self, _name: &str, _color: u32)2304 unsafe fn insert_debug_marker(&mut self, _name: &str, _color: u32) {
2305 //TODO
2306 }
begin_debug_marker(&mut self, _name: &str, _color: u32)2307 unsafe fn begin_debug_marker(&mut self, _name: &str, _color: u32) {
2308 //TODO
2309 }
end_debug_marker(&mut self)2310 unsafe fn end_debug_marker(&mut self) {
2311 //TODO
2312 }
2313 }
2314
2315 #[derive(Clone, Debug)]
2316 enum SyncRange {
2317 Whole,
2318 Partial(Range<u64>),
2319 }
2320
2321 #[derive(Debug)]
2322 pub struct MemoryFlush {
2323 host_memory: *mut u8,
2324 sync_range: SyncRange,
2325 buffer: *mut d3d11::ID3D11Buffer,
2326 }
2327
2328 pub struct MemoryInvalidate {
2329 working_buffer: Option<ComPtr<d3d11::ID3D11Buffer>>,
2330 working_buffer_size: u64,
2331 host_memory: *mut u8,
2332 sync_range: Range<u64>,
2333 buffer: *mut d3d11::ID3D11Buffer,
2334 }
2335
2336 impl fmt::Debug for MemoryInvalidate {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2337 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2338 fmt.write_str("MemoryInvalidate")
2339 }
2340 }
2341
intersection(a: &Range<u64>, b: &Range<u64>) -> Option<Range<u64>>2342 fn intersection(a: &Range<u64>, b: &Range<u64>) -> Option<Range<u64>> {
2343 let min = if a.start < b.start { a } else { b };
2344 let max = if min == a { b } else { a };
2345
2346 if min.end < max.start {
2347 None
2348 } else {
2349 let end = if min.end < max.end { min.end } else { max.end };
2350 Some(max.start .. end)
2351 }
2352 }
2353
2354 impl MemoryFlush {
do_flush(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>)2355 fn do_flush(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
2356 let src = self.host_memory;
2357
2358 debug_marker!(context, "Flush({:?})", self.sync_range);
2359 let region = match self.sync_range {
2360 SyncRange::Partial(ref range) if range.start < range.end => Some(d3d11::D3D11_BOX {
2361 left: range.start as u32,
2362 top: 0,
2363 front: 0,
2364 right: range.end as u32,
2365 bottom: 1,
2366 back: 1,
2367 }),
2368 _ => None,
2369 };
2370
2371 unsafe {
2372 context.UpdateSubresource(
2373 self.buffer as _,
2374 0,
2375 if let Some(region) = region {
2376 ®ion
2377 } else {
2378 ptr::null_mut()
2379 },
2380 src as _,
2381 0,
2382 0,
2383 );
2384 }
2385 }
2386 }
2387
2388 impl MemoryInvalidate {
download( &self, context: &ComPtr<d3d11::ID3D11DeviceContext>, buffer: *mut d3d11::ID3D11Buffer, range: Range<u64>, )2389 fn download(
2390 &self,
2391 context: &ComPtr<d3d11::ID3D11DeviceContext>,
2392 buffer: *mut d3d11::ID3D11Buffer,
2393 range: Range<u64>,
2394 ) {
2395 unsafe {
2396 context.CopySubresourceRegion(
2397 self.working_buffer.clone().unwrap().as_raw() as _,
2398 0,
2399 0,
2400 0,
2401 0,
2402 buffer as _,
2403 0,
2404 &d3d11::D3D11_BOX {
2405 left: range.start as _,
2406 top: 0,
2407 front: 0,
2408 right: range.end as _,
2409 bottom: 1,
2410 back: 1,
2411 },
2412 );
2413
2414 // copy over to our vec
2415 let dst = self.host_memory.offset(range.start as isize);
2416 let src = self.map(&context);
2417 ptr::copy(src, dst, (range.end - range.start) as usize);
2418 self.unmap(&context);
2419 }
2420 }
2421
do_invalidate(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>)2422 fn do_invalidate(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
2423 let stride = self.working_buffer_size;
2424 let range = &self.sync_range;
2425 let len = range.end - range.start;
2426 let chunks = len / stride;
2427 let remainder = len % stride;
2428
2429 // we split up the copies into chunks the size of our working buffer
2430 for i in 0 .. chunks {
2431 let offset = range.start + i * stride;
2432 let range = offset .. (offset + stride);
2433
2434 self.download(context, self.buffer, range);
2435 }
2436
2437 if remainder != 0 {
2438 self.download(context, self.buffer, (chunks * stride) .. range.end);
2439 }
2440 }
2441
map(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>) -> *mut u82442 fn map(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>) -> *mut u8 {
2443 assert_eq!(self.working_buffer.is_some(), true);
2444
2445 unsafe {
2446 let mut map = mem::zeroed();
2447 let hr = context.Map(
2448 self.working_buffer.clone().unwrap().as_raw() as _,
2449 0,
2450 d3d11::D3D11_MAP_READ,
2451 0,
2452 &mut map,
2453 );
2454
2455 assert_eq!(hr, winerror::S_OK);
2456
2457 map.pData as _
2458 }
2459 }
2460
unmap(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>)2461 fn unmap(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>) {
2462 unsafe {
2463 context.Unmap(self.working_buffer.clone().unwrap().as_raw() as _, 0);
2464 }
2465 }
2466 }
2467
2468 // Since we dont have any heaps to work with directly, everytime we bind a
2469 // buffer/image to memory we allocate a dx11 resource and assign it a range.
2470 //
2471 // `HOST_VISIBLE` memory gets a `Vec<u8>` which covers the entire memory
2472 // range. This forces us to only expose non-coherent memory, as this
2473 // abstraction acts as a "cache" since the "staging buffer" vec is disjoint
2474 // from all the dx11 resources we store in the struct.
2475 pub struct Memory {
2476 properties: memory::Properties,
2477 size: u64,
2478
2479 mapped_ptr: *mut u8,
2480
2481 // staging buffer covering the whole memory region, if it's HOST_VISIBLE
2482 host_visible: Option<RefCell<Vec<u8>>>,
2483
2484 // list of all buffers bound to this memory
2485 local_buffers: RefCell<Vec<(Range<u64>, InternalBuffer)>>,
2486
2487 // list of all images bound to this memory
2488 _local_images: RefCell<Vec<(Range<u64>, InternalImage)>>,
2489 }
2490
2491 impl fmt::Debug for Memory {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2492 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2493 fmt.write_str("Memory")
2494 }
2495 }
2496
2497 unsafe impl Send for Memory {}
2498 unsafe impl Sync for Memory {}
2499
2500 impl Memory {
resolve(&self, segment: &memory::Segment) -> Range<u64>2501 pub fn resolve(&self, segment: &memory::Segment) -> Range<u64> {
2502 segment.offset .. segment.size.map_or(self.size, |s| segment.offset + s)
2503 }
2504
bind_buffer(&self, range: Range<u64>, buffer: InternalBuffer)2505 pub fn bind_buffer(&self, range: Range<u64>, buffer: InternalBuffer) {
2506 self.local_buffers.borrow_mut().push((range, buffer));
2507 }
2508
flush(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>, range: Range<u64>)2509 pub fn flush(&self, context: &ComPtr<d3d11::ID3D11DeviceContext>, range: Range<u64>) {
2510 use buffer::Usage;
2511
2512 for &(ref buffer_range, ref buffer) in self.local_buffers.borrow().iter() {
2513 if let Some(range) = intersection(&range, &buffer_range) {
2514 let ptr = self.mapped_ptr;
2515
2516 // we need to handle 3 cases for updating buffers:
2517 //
2518 // 1. if our buffer was created as a `UNIFORM` buffer *and* other usage flags, we
2519 // also have a disjoint buffer which only has `D3D11_BIND_CONSTANT_BUFFER` due
2520 // to DX11 limitation. we then need to update both the original buffer and the
2521 // disjoint one with the *whole* range (TODO: allow for partial updates)
2522 //
2523 // 2. if our buffer was created with *only* `UNIFORM` usage we need to upload
2524 // the whole range (TODO: allow for partial updates)
2525 //
2526 // 3. the general case, without any `UNIFORM` usage has no restrictions on
2527 // partial updates, so we upload the specified range
2528 //
2529 if buffer.usage.contains(Usage::UNIFORM) && buffer.usage != Usage::UNIFORM {
2530 MemoryFlush {
2531 host_memory: unsafe { ptr.offset(buffer_range.start as _) },
2532 sync_range: SyncRange::Whole,
2533 buffer: buffer.raw,
2534 }
2535 .do_flush(&context);
2536
2537 if let Some(disjoint) = buffer.disjoint_cb {
2538 MemoryFlush {
2539 host_memory: unsafe { ptr.offset(buffer_range.start as _) },
2540 sync_range: SyncRange::Whole,
2541 buffer: disjoint,
2542 }
2543 .do_flush(&context);
2544 }
2545 } else if buffer.usage == Usage::UNIFORM {
2546 MemoryFlush {
2547 host_memory: unsafe { ptr.offset(buffer_range.start as _) },
2548 sync_range: SyncRange::Whole,
2549 buffer: buffer.raw,
2550 }
2551 .do_flush(&context);
2552 } else {
2553 let local_start = range.start - buffer_range.start;
2554 let local_len = range.end - range.start;
2555
2556 MemoryFlush {
2557 host_memory: unsafe { ptr.offset(range.start as _) },
2558 sync_range: SyncRange::Partial(local_start .. (local_start + local_len)),
2559 buffer: buffer.raw,
2560 }
2561 .do_flush(&context);
2562 }
2563 }
2564 }
2565 }
2566
invalidate( &self, context: &ComPtr<d3d11::ID3D11DeviceContext>, range: Range<u64>, working_buffer: ComPtr<d3d11::ID3D11Buffer>, working_buffer_size: u64, )2567 pub fn invalidate(
2568 &self,
2569 context: &ComPtr<d3d11::ID3D11DeviceContext>,
2570 range: Range<u64>,
2571 working_buffer: ComPtr<d3d11::ID3D11Buffer>,
2572 working_buffer_size: u64,
2573 ) {
2574 for &(ref buffer_range, ref buffer) in self.local_buffers.borrow().iter() {
2575 if let Some(range) = intersection(&range, &buffer_range) {
2576 MemoryInvalidate {
2577 working_buffer: Some(working_buffer.clone()),
2578 working_buffer_size,
2579 host_memory: self.mapped_ptr,
2580 sync_range: range.clone(),
2581 buffer: buffer.raw,
2582 }
2583 .do_invalidate(&context);
2584 }
2585 }
2586 }
2587 }
2588
2589 #[derive(Debug)]
2590 pub struct CommandPool {
2591 device: ComPtr<d3d11::ID3D11Device>,
2592 internal: internal::Internal,
2593 }
2594
2595 unsafe impl Send for CommandPool {}
2596 unsafe impl Sync for CommandPool {}
2597
2598 impl hal::pool::CommandPool<Backend> for CommandPool {
reset(&mut self, _release_resources: bool)2599 unsafe fn reset(&mut self, _release_resources: bool) {
2600 //unimplemented!()
2601 }
2602
allocate_one(&mut self, _level: command::Level) -> CommandBuffer2603 unsafe fn allocate_one(&mut self, _level: command::Level) -> CommandBuffer {
2604 CommandBuffer::create_deferred(self.device.clone(), self.internal.clone())
2605 }
2606
free<I>(&mut self, _cbufs: I) where I: IntoIterator<Item = CommandBuffer>,2607 unsafe fn free<I>(&mut self, _cbufs: I)
2608 where
2609 I: IntoIterator<Item = CommandBuffer>,
2610 {
2611 // TODO:
2612 // unimplemented!()
2613 }
2614 }
2615
2616 /// Similarily to dx12 backend, we can handle either precompiled dxbc or spirv
2617 pub enum ShaderModule {
2618 Dxbc(Vec<u8>),
2619 Spirv(Vec<u32>),
2620 }
2621
2622 // TODO: temporary
2623 impl fmt::Debug for ShaderModule {
fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result2624 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
2625 write!(f, "{}", "ShaderModule { ... }")
2626 }
2627 }
2628
2629 unsafe impl Send for ShaderModule {}
2630 unsafe impl Sync for ShaderModule {}
2631
2632 #[derive(Clone, Debug)]
2633 pub struct SubpassDesc {
2634 pub color_attachments: Vec<pass::AttachmentRef>,
2635 pub depth_stencil_attachment: Option<pass::AttachmentRef>,
2636 pub input_attachments: Vec<pass::AttachmentRef>,
2637 pub resolve_attachments: Vec<pass::AttachmentRef>,
2638 }
2639
2640 impl SubpassDesc {
is_using(&self, at_id: pass::AttachmentId) -> bool2641 pub(crate) fn is_using(&self, at_id: pass::AttachmentId) -> bool {
2642 self.color_attachments
2643 .iter()
2644 .chain(self.depth_stencil_attachment.iter())
2645 .chain(self.input_attachments.iter())
2646 .chain(self.resolve_attachments.iter())
2647 .any(|&(id, _)| id == at_id)
2648 }
2649 }
2650
2651 #[derive(Clone, Debug)]
2652 pub struct RenderPass {
2653 pub attachments: Vec<pass::Attachment>,
2654 pub subpasses: Vec<SubpassDesc>,
2655 }
2656
2657 #[derive(Clone, Debug)]
2658 pub struct Framebuffer {
2659 attachments: Vec<ImageView>,
2660 layers: image::Layer,
2661 }
2662
2663 #[derive(Clone, Debug)]
2664 pub struct InternalBuffer {
2665 raw: *mut d3d11::ID3D11Buffer,
2666 // TODO: need to sync between `raw` and `disjoint_cb`, same way as we do with
2667 // `MemoryFlush/Invalidate`
2668 disjoint_cb: Option<*mut d3d11::ID3D11Buffer>, // if unbound this buffer might be null.
2669 srv: Option<*mut d3d11::ID3D11ShaderResourceView>,
2670 uav: Option<*mut d3d11::ID3D11UnorderedAccessView>,
2671 usage: buffer::Usage,
2672 }
2673
2674 pub struct Buffer {
2675 internal: InternalBuffer,
2676 properties: memory::Properties, // empty if unbound
2677 host_ptr: *mut u8, // null if unbound
2678 bound_range: Range<u64>, // 0 if unbound
2679 requirements: memory::Requirements,
2680 bind: d3d11::D3D11_BIND_FLAG,
2681 }
2682
2683 impl fmt::Debug for Buffer {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2684 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2685 fmt.write_str("Buffer")
2686 }
2687 }
2688
2689 unsafe impl Send for Buffer {}
2690 unsafe impl Sync for Buffer {}
2691
2692 #[derive(Debug)]
2693 pub struct BufferView;
2694
2695 pub struct Image {
2696 kind: image::Kind,
2697 usage: image::Usage,
2698 format: format::Format,
2699 view_caps: image::ViewCapabilities,
2700 decomposed_format: conv::DecomposedDxgiFormat,
2701 mip_levels: image::Level,
2702 internal: InternalImage,
2703 bind: d3d11::D3D11_BIND_FLAG,
2704 requirements: memory::Requirements,
2705 }
2706
2707 impl fmt::Debug for Image {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2708 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2709 fmt.write_str("Image")
2710 }
2711 }
2712
2713 pub struct InternalImage {
2714 raw: *mut d3d11::ID3D11Resource,
2715 copy_srv: Option<ComPtr<d3d11::ID3D11ShaderResourceView>>,
2716 srv: Option<ComPtr<d3d11::ID3D11ShaderResourceView>>,
2717
2718 /// Contains UAVs for all subresources
2719 unordered_access_views: Vec<ComPtr<d3d11::ID3D11UnorderedAccessView>>,
2720
2721 /// Contains DSVs for all subresources
2722 depth_stencil_views: Vec<ComPtr<d3d11::ID3D11DepthStencilView>>,
2723
2724 /// Contains RTVs for all subresources
2725 render_target_views: Vec<ComPtr<d3d11::ID3D11RenderTargetView>>,
2726 }
2727
2728 impl fmt::Debug for InternalImage {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2729 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2730 fmt.write_str("InternalImage")
2731 }
2732 }
2733
2734 unsafe impl Send for Image {}
2735 unsafe impl Sync for Image {}
2736
2737 impl Image {
calc_subresource(&self, mip_level: UINT, layer: UINT) -> UINT2738 pub fn calc_subresource(&self, mip_level: UINT, layer: UINT) -> UINT {
2739 mip_level + (layer * self.mip_levels as UINT)
2740 }
2741
get_uav( &self, mip_level: image::Level, _layer: image::Layer, ) -> Option<&ComPtr<d3d11::ID3D11UnorderedAccessView>>2742 pub fn get_uav(
2743 &self,
2744 mip_level: image::Level,
2745 _layer: image::Layer,
2746 ) -> Option<&ComPtr<d3d11::ID3D11UnorderedAccessView>> {
2747 self.internal
2748 .unordered_access_views
2749 .get(self.calc_subresource(mip_level as _, 0) as usize)
2750 }
2751
get_dsv( &self, mip_level: image::Level, layer: image::Layer, ) -> Option<&ComPtr<d3d11::ID3D11DepthStencilView>>2752 pub fn get_dsv(
2753 &self,
2754 mip_level: image::Level,
2755 layer: image::Layer,
2756 ) -> Option<&ComPtr<d3d11::ID3D11DepthStencilView>> {
2757 self.internal
2758 .depth_stencil_views
2759 .get(self.calc_subresource(mip_level as _, layer as _) as usize)
2760 }
2761
get_rtv( &self, mip_level: image::Level, layer: image::Layer, ) -> Option<&ComPtr<d3d11::ID3D11RenderTargetView>>2762 pub fn get_rtv(
2763 &self,
2764 mip_level: image::Level,
2765 layer: image::Layer,
2766 ) -> Option<&ComPtr<d3d11::ID3D11RenderTargetView>> {
2767 self.internal
2768 .render_target_views
2769 .get(self.calc_subresource(mip_level as _, layer as _) as usize)
2770 }
2771 }
2772
2773 #[derive(Clone)]
2774 pub struct ImageView {
2775 format: format::Format,
2776 rtv_handle: Option<ComPtr<d3d11::ID3D11RenderTargetView>>,
2777 srv_handle: Option<ComPtr<d3d11::ID3D11ShaderResourceView>>,
2778 dsv_handle: Option<ComPtr<d3d11::ID3D11DepthStencilView>>,
2779 uav_handle: Option<ComPtr<d3d11::ID3D11UnorderedAccessView>>,
2780 }
2781
2782 impl fmt::Debug for ImageView {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2783 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2784 fmt.write_str("ImageView")
2785 }
2786 }
2787
2788 unsafe impl Send for ImageView {}
2789 unsafe impl Sync for ImageView {}
2790
2791 pub struct Sampler {
2792 sampler_handle: ComPtr<d3d11::ID3D11SamplerState>,
2793 }
2794
2795 impl fmt::Debug for Sampler {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2796 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2797 fmt.write_str("Sampler")
2798 }
2799 }
2800
2801 unsafe impl Send for Sampler {}
2802 unsafe impl Sync for Sampler {}
2803
2804 pub struct ComputePipeline {
2805 cs: ComPtr<d3d11::ID3D11ComputeShader>,
2806 }
2807
2808 impl fmt::Debug for ComputePipeline {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2809 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2810 fmt.write_str("ComputePipeline")
2811 }
2812 }
2813
2814 unsafe impl Send for ComputePipeline {}
2815 unsafe impl Sync for ComputePipeline {}
2816
2817 /// NOTE: some objects are hashed internally and reused when created with the
2818 /// same params[0], need to investigate which interfaces this applies
2819 /// to.
2820 ///
2821 /// [0]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476500(v=vs.85).aspx
2822 #[derive(Clone)]
2823 pub struct GraphicsPipeline {
2824 vs: ComPtr<d3d11::ID3D11VertexShader>,
2825 gs: Option<ComPtr<d3d11::ID3D11GeometryShader>>,
2826 hs: Option<ComPtr<d3d11::ID3D11HullShader>>,
2827 ds: Option<ComPtr<d3d11::ID3D11DomainShader>>,
2828 ps: Option<ComPtr<d3d11::ID3D11PixelShader>>,
2829 topology: d3d11::D3D11_PRIMITIVE_TOPOLOGY,
2830 input_layout: ComPtr<d3d11::ID3D11InputLayout>,
2831 rasterizer_state: ComPtr<d3d11::ID3D11RasterizerState>,
2832 blend_state: ComPtr<d3d11::ID3D11BlendState>,
2833 depth_stencil_state: Option<(
2834 ComPtr<d3d11::ID3D11DepthStencilState>,
2835 pso::State<pso::StencilValue>,
2836 )>,
2837 baked_states: pso::BakedStates,
2838 required_bindings: u32,
2839 max_vertex_bindings: u32,
2840 strides: Vec<u32>,
2841 }
2842
2843 impl fmt::Debug for GraphicsPipeline {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result2844 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2845 fmt.write_str("GraphicsPipeline")
2846 }
2847 }
2848
2849 unsafe impl Send for GraphicsPipeline {}
2850 unsafe impl Sync for GraphicsPipeline {}
2851
2852 type ResourceIndex = u8;
2853 type DescriptorIndex = u16;
2854
2855 #[derive(Clone, Debug, Default)]
2856 struct RegisterData<T> {
2857 // CBV
2858 c: T,
2859 // SRV
2860 t: T,
2861 // UAV
2862 u: T,
2863 // Sampler
2864 s: T,
2865 }
2866
2867 impl<T> RegisterData<T> {
map<U, F: Fn(&T) -> U>(&self, fun: F) -> RegisterData<U>2868 fn map<U, F: Fn(&T) -> U>(&self, fun: F) -> RegisterData<U> {
2869 RegisterData {
2870 c: fun(&self.c),
2871 t: fun(&self.t),
2872 u: fun(&self.u),
2873 s: fun(&self.s),
2874 }
2875 }
2876 }
2877
2878 impl RegisterData<DescriptorIndex> {
add_content_many(&mut self, content: DescriptorContent, many: DescriptorIndex)2879 fn add_content_many(&mut self, content: DescriptorContent, many: DescriptorIndex) {
2880 if content.contains(DescriptorContent::CBV) {
2881 self.c += many;
2882 }
2883 if content.contains(DescriptorContent::SRV) {
2884 self.t += many;
2885 }
2886 if content.contains(DescriptorContent::UAV) {
2887 self.u += many;
2888 }
2889 if content.contains(DescriptorContent::SAMPLER) {
2890 self.s += many;
2891 }
2892 }
2893
add_content(&mut self, content: DescriptorContent)2894 fn add_content(&mut self, content: DescriptorContent) {
2895 self.add_content_many(content, 1)
2896 }
2897
sum(&self) -> DescriptorIndex2898 fn sum(&self) -> DescriptorIndex {
2899 self.c + self.t + self.u + self.s
2900 }
2901 }
2902
2903 #[derive(Clone, Debug, Default)]
2904 struct MultiStageData<T> {
2905 vs: T,
2906 ps: T,
2907 cs: T,
2908 }
2909
2910 impl<T> MultiStageData<T> {
select(self, stage: pso::Stage) -> T2911 fn select(self, stage: pso::Stage) -> T {
2912 match stage {
2913 pso::Stage::Vertex => self.vs,
2914 pso::Stage::Fragment => self.ps,
2915 pso::Stage::Compute => self.cs,
2916 _ => panic!("Unsupported stage {:?}", stage),
2917 }
2918 }
2919 }
2920
2921 impl<T> MultiStageData<RegisterData<T>> {
map_register<U, F: Fn(&T) -> U>(&self, fun: F) -> MultiStageData<RegisterData<U>>2922 fn map_register<U, F: Fn(&T) -> U>(&self, fun: F) -> MultiStageData<RegisterData<U>> {
2923 MultiStageData {
2924 vs: self.vs.map(&fun),
2925 ps: self.ps.map(&fun),
2926 cs: self.cs.map(&fun),
2927 }
2928 }
2929
map_other<U, F: Fn(&RegisterData<T>) -> U>(&self, fun: F) -> MultiStageData<U>2930 fn map_other<U, F: Fn(&RegisterData<T>) -> U>(&self, fun: F) -> MultiStageData<U> {
2931 MultiStageData {
2932 vs: fun(&self.vs),
2933 ps: fun(&self.ps),
2934 cs: fun(&self.cs),
2935 }
2936 }
2937 }
2938
2939 impl MultiStageData<RegisterData<DescriptorIndex>> {
add_content(&mut self, content: DescriptorContent, stages: pso::ShaderStageFlags)2940 fn add_content(&mut self, content: DescriptorContent, stages: pso::ShaderStageFlags) {
2941 if stages.contains(pso::ShaderStageFlags::VERTEX) {
2942 self.vs.add_content(content);
2943 }
2944 if stages.contains(pso::ShaderStageFlags::FRAGMENT) {
2945 self.ps.add_content(content);
2946 }
2947 if stages.contains(pso::ShaderStageFlags::COMPUTE) {
2948 self.cs.add_content(content);
2949 }
2950 }
2951
sum(&self) -> DescriptorIndex2952 fn sum(&self) -> DescriptorIndex {
2953 self.vs.sum() + self.ps.sum() + self.cs.sum()
2954 }
2955 }
2956
2957 #[derive(Clone, Debug, Default)]
2958 struct RegisterPoolMapping {
2959 offset: DescriptorIndex,
2960 count: ResourceIndex,
2961 }
2962
2963 #[derive(Clone, Debug, Default)]
2964 struct RegisterInfo {
2965 res_index: ResourceIndex,
2966 pool_offset: DescriptorIndex,
2967 count: ResourceIndex,
2968 }
2969
2970 impl RegisterInfo {
as_some(&self) -> Option<&Self>2971 fn as_some(&self) -> Option<&Self> {
2972 if self.count == 0 {
2973 None
2974 } else {
2975 Some(self)
2976 }
2977 }
2978 }
2979
2980 #[derive(Clone, Debug, Default)]
2981 struct RegisterAccumulator {
2982 res_index: ResourceIndex,
2983 }
2984
2985 impl RegisterAccumulator {
to_mapping(&self, cur_offset: &mut DescriptorIndex) -> RegisterPoolMapping2986 fn to_mapping(&self, cur_offset: &mut DescriptorIndex) -> RegisterPoolMapping {
2987 let offset = *cur_offset;
2988 *cur_offset += self.res_index as DescriptorIndex;
2989
2990 RegisterPoolMapping {
2991 offset,
2992 count: self.res_index,
2993 }
2994 }
2995
advance(&mut self, mapping: &RegisterPoolMapping) -> RegisterInfo2996 fn advance(&mut self, mapping: &RegisterPoolMapping) -> RegisterInfo {
2997 let res_index = self.res_index;
2998 self.res_index += mapping.count;
2999 RegisterInfo {
3000 res_index,
3001 pool_offset: mapping.offset,
3002 count: mapping.count,
3003 }
3004 }
3005 }
3006
3007 impl RegisterData<RegisterAccumulator> {
to_mapping(&self, pool_offset: &mut DescriptorIndex) -> RegisterData<RegisterPoolMapping>3008 fn to_mapping(&self, pool_offset: &mut DescriptorIndex) -> RegisterData<RegisterPoolMapping> {
3009 RegisterData {
3010 c: self.c.to_mapping(pool_offset),
3011 t: self.t.to_mapping(pool_offset),
3012 u: self.u.to_mapping(pool_offset),
3013 s: self.s.to_mapping(pool_offset),
3014 }
3015 }
3016
advance( &mut self, mapping: &RegisterData<RegisterPoolMapping>, ) -> RegisterData<RegisterInfo>3017 fn advance(
3018 &mut self,
3019 mapping: &RegisterData<RegisterPoolMapping>,
3020 ) -> RegisterData<RegisterInfo> {
3021 RegisterData {
3022 c: self.c.advance(&mapping.c),
3023 t: self.t.advance(&mapping.t),
3024 u: self.u.advance(&mapping.u),
3025 s: self.s.advance(&mapping.s),
3026 }
3027 }
3028 }
3029
3030 impl MultiStageData<RegisterData<RegisterAccumulator>> {
to_mapping(&self) -> MultiStageData<RegisterData<RegisterPoolMapping>>3031 fn to_mapping(&self) -> MultiStageData<RegisterData<RegisterPoolMapping>> {
3032 let mut pool_offset = 0;
3033 MultiStageData {
3034 vs: self.vs.to_mapping(&mut pool_offset),
3035 ps: self.ps.to_mapping(&mut pool_offset),
3036 cs: self.cs.to_mapping(&mut pool_offset),
3037 }
3038 }
3039
advance( &mut self, mapping: &MultiStageData<RegisterData<RegisterPoolMapping>>, ) -> MultiStageData<RegisterData<RegisterInfo>>3040 fn advance(
3041 &mut self,
3042 mapping: &MultiStageData<RegisterData<RegisterPoolMapping>>,
3043 ) -> MultiStageData<RegisterData<RegisterInfo>> {
3044 MultiStageData {
3045 vs: self.vs.advance(&mapping.vs),
3046 ps: self.ps.advance(&mapping.ps),
3047 cs: self.cs.advance(&mapping.cs),
3048 }
3049 }
3050 }
3051
3052 #[derive(Clone, Debug)]
3053 struct DescriptorSetInfo {
3054 bindings: Arc<Vec<pso::DescriptorSetLayoutBinding>>,
3055 registers: MultiStageData<RegisterData<RegisterInfo>>,
3056 }
3057
3058 impl DescriptorSetInfo {
find_register( &self, stage: pso::Stage, binding_index: pso::DescriptorBinding, ) -> (DescriptorContent, RegisterData<ResourceIndex>)3059 fn find_register(
3060 &self,
3061 stage: pso::Stage,
3062 binding_index: pso::DescriptorBinding,
3063 ) -> (DescriptorContent, RegisterData<ResourceIndex>) {
3064 let mut res_offsets = self
3065 .registers
3066 .map_register(|info| info.res_index as DescriptorIndex)
3067 .select(stage);
3068 for binding in self.bindings.iter() {
3069 let content = DescriptorContent::from(binding.ty);
3070 if binding.binding == binding_index {
3071 return (content, res_offsets.map(|offset| *offset as ResourceIndex));
3072 }
3073 res_offsets.add_content(content);
3074 }
3075 panic!("Unable to find binding {:?}", binding_index);
3076 }
3077 }
3078
3079 /// The pipeline layout holds optimized (less api calls) ranges of objects for all descriptor sets
3080 /// belonging to the pipeline object.
3081 #[derive(Debug)]
3082 pub struct PipelineLayout {
3083 sets: Vec<DescriptorSetInfo>,
3084 }
3085
3086 /// The descriptor set layout contains mappings from a given binding to the offset in our
3087 /// descriptor pool storage and what type of descriptor it is (combined image sampler takes up two
3088 /// handles).
3089 #[derive(Debug)]
3090 pub struct DescriptorSetLayout {
3091 bindings: Arc<Vec<pso::DescriptorSetLayoutBinding>>,
3092 pool_mapping: MultiStageData<RegisterData<RegisterPoolMapping>>,
3093 }
3094
3095 #[derive(Debug)]
3096 struct CoherentBufferFlushRange {
3097 device_buffer: *mut d3d11::ID3D11Buffer,
3098 host_ptr: *mut u8,
3099 range: SyncRange,
3100 }
3101
3102 #[derive(Debug)]
3103 struct CoherentBufferInvalidateRange {
3104 device_buffer: *mut d3d11::ID3D11Buffer,
3105 host_ptr: *mut u8,
3106 range: Range<u64>,
3107 }
3108
3109 #[derive(Debug)]
3110 struct CoherentBuffers {
3111 // descriptor set writes containing coherent resources go into these vecs and are added to the
3112 // command buffers own Vec on binding the set.
3113 flush_coherent_buffers: RefCell<Vec<CoherentBufferFlushRange>>,
3114 invalidate_coherent_buffers: RefCell<Vec<CoherentBufferInvalidateRange>>,
3115 }
3116
3117 impl CoherentBuffers {
_add_flush(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer)3118 fn _add_flush(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer) {
3119 let new = buffer.internal.raw;
3120
3121 if old != new {
3122 let mut buffers = self.flush_coherent_buffers.borrow_mut();
3123
3124 let pos = buffers.iter().position(|sync| old == sync.device_buffer);
3125
3126 let sync_range = CoherentBufferFlushRange {
3127 device_buffer: new,
3128 host_ptr: buffer.host_ptr,
3129 range: SyncRange::Whole,
3130 };
3131
3132 if let Some(pos) = pos {
3133 buffers[pos] = sync_range;
3134 } else {
3135 buffers.push(sync_range);
3136 }
3137
3138 if let Some(disjoint) = buffer.internal.disjoint_cb {
3139 let pos = buffers
3140 .iter()
3141 .position(|sync| disjoint == sync.device_buffer);
3142
3143 let sync_range = CoherentBufferFlushRange {
3144 device_buffer: disjoint,
3145 host_ptr: buffer.host_ptr,
3146 range: SyncRange::Whole,
3147 };
3148
3149 if let Some(pos) = pos {
3150 buffers[pos] = sync_range;
3151 } else {
3152 buffers.push(sync_range);
3153 }
3154 }
3155 }
3156 }
3157
_add_invalidate(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer)3158 fn _add_invalidate(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer) {
3159 let new = buffer.internal.raw;
3160
3161 if old != new {
3162 let mut buffers = self.invalidate_coherent_buffers.borrow_mut();
3163
3164 let pos = buffers.iter().position(|sync| old == sync.device_buffer);
3165
3166 let sync_range = CoherentBufferInvalidateRange {
3167 device_buffer: new,
3168 host_ptr: buffer.host_ptr,
3169 range: buffer.bound_range.clone(),
3170 };
3171
3172 if let Some(pos) = pos {
3173 buffers[pos] = sync_range;
3174 } else {
3175 buffers.push(sync_range);
3176 }
3177 }
3178 }
3179 }
3180
3181 /// Newtype around a common interface that all bindable resources inherit from.
3182 #[derive(Debug, Copy, Clone)]
3183 #[repr(C)]
3184 struct Descriptor(*mut d3d11::ID3D11DeviceChild);
3185
3186 bitflags! {
3187 /// A set of D3D11 descriptor types that need to be associated
3188 /// with a single gfx-hal `DescriptorType`.
3189 #[derive(Default)]
3190 pub struct DescriptorContent: u8 {
3191 const CBV = 0x1;
3192 const SRV = 0x2;
3193 const UAV = 0x4;
3194 const SAMPLER = 0x8;
3195 /// Indicates if the descriptor is a dynamic uniform/storage buffer.
3196 /// Important as dynamic buffers are implemented as root descriptors.
3197 const DYNAMIC = 0x10;
3198 }
3199 }
3200
3201 impl From<pso::DescriptorType> for DescriptorContent {
from(ty: pso::DescriptorType) -> Self3202 fn from(ty: pso::DescriptorType) -> Self {
3203 use hal::pso::{
3204 BufferDescriptorFormat as Bdf,
3205 BufferDescriptorType as Bdt,
3206 DescriptorType as Dt,
3207 ImageDescriptorType as Idt,
3208 };
3209 match ty {
3210 Dt::Sampler => DescriptorContent::SAMPLER,
3211 Dt::Image {
3212 ty: Idt::Sampled { with_sampler: true },
3213 } => DescriptorContent::SRV | DescriptorContent::SAMPLER,
3214 Dt::Image {
3215 ty: Idt::Sampled {
3216 with_sampler: false,
3217 },
3218 }
3219 | Dt::Image {
3220 ty: Idt::Storage { read_only: true },
3221 }
3222 | Dt::InputAttachment => DescriptorContent::SRV,
3223 Dt::Image {
3224 ty: Idt::Storage { read_only: false },
3225 } => DescriptorContent::SRV | DescriptorContent::UAV,
3226 Dt::Buffer {
3227 ty: Bdt::Uniform,
3228 format:
3229 Bdf::Structured {
3230 dynamic_offset: true,
3231 },
3232 } => DescriptorContent::CBV | DescriptorContent::DYNAMIC,
3233 Dt::Buffer {
3234 ty: Bdt::Uniform, ..
3235 } => DescriptorContent::CBV,
3236 Dt::Buffer {
3237 ty: Bdt::Storage { read_only: true },
3238 format:
3239 Bdf::Structured {
3240 dynamic_offset: true,
3241 },
3242 } => DescriptorContent::SRV | DescriptorContent::DYNAMIC,
3243 Dt::Buffer {
3244 ty: Bdt::Storage { read_only: false },
3245 format:
3246 Bdf::Structured {
3247 dynamic_offset: true,
3248 },
3249 } => DescriptorContent::SRV | DescriptorContent::UAV | DescriptorContent::DYNAMIC,
3250 Dt::Buffer {
3251 ty: Bdt::Storage { read_only: true },
3252 ..
3253 } => DescriptorContent::SRV,
3254 Dt::Buffer {
3255 ty: Bdt::Storage { read_only: false },
3256 ..
3257 } => DescriptorContent::SRV | DescriptorContent::UAV,
3258 }
3259 }
3260 }
3261
3262 pub struct DescriptorSet {
3263 offset: DescriptorIndex,
3264 len: DescriptorIndex,
3265 handles: *mut Descriptor,
3266 coherent_buffers: Mutex<CoherentBuffers>,
3267 layout: DescriptorSetLayout,
3268 }
3269
3270 impl fmt::Debug for DescriptorSet {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result3271 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
3272 fmt.write_str("DescriptorSet")
3273 }
3274 }
3275
3276 unsafe impl Send for DescriptorSet {}
3277 unsafe impl Sync for DescriptorSet {}
3278
3279 impl DescriptorSet {
_add_flush(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer)3280 fn _add_flush(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer) {
3281 let new = buffer.internal.raw;
3282
3283 if old != new {
3284 self.coherent_buffers.lock()._add_flush(old, buffer);
3285 }
3286 }
3287
_add_invalidate(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer)3288 fn _add_invalidate(&self, old: *mut d3d11::ID3D11Buffer, buffer: &Buffer) {
3289 let new = buffer.internal.raw;
3290
3291 if old != new {
3292 self.coherent_buffers.lock()._add_invalidate(old, buffer);
3293 }
3294 }
3295
assign(&self, offset: DescriptorIndex, value: *mut d3d11::ID3D11DeviceChild)3296 unsafe fn assign(&self, offset: DescriptorIndex, value: *mut d3d11::ID3D11DeviceChild) {
3297 *self.handles.offset(offset as isize) = Descriptor(value);
3298 }
3299
assign_stages( &self, offsets: &MultiStageData<DescriptorIndex>, stages: pso::ShaderStageFlags, value: *mut d3d11::ID3D11DeviceChild, )3300 unsafe fn assign_stages(
3301 &self,
3302 offsets: &MultiStageData<DescriptorIndex>,
3303 stages: pso::ShaderStageFlags,
3304 value: *mut d3d11::ID3D11DeviceChild,
3305 ) {
3306 if stages.contains(pso::ShaderStageFlags::VERTEX) {
3307 self.assign(offsets.vs, value);
3308 }
3309 if stages.contains(pso::ShaderStageFlags::FRAGMENT) {
3310 self.assign(offsets.ps, value);
3311 }
3312 if stages.contains(pso::ShaderStageFlags::COMPUTE) {
3313 self.assign(offsets.cs, value);
3314 }
3315 }
3316 }
3317
3318 #[derive(Debug)]
3319 pub struct DescriptorPool {
3320 handles: Vec<Descriptor>,
3321 allocator: RangeAllocator<DescriptorIndex>,
3322 }
3323
3324 unsafe impl Send for DescriptorPool {}
3325 unsafe impl Sync for DescriptorPool {}
3326
3327 impl DescriptorPool {
with_capacity(size: DescriptorIndex) -> Self3328 fn with_capacity(size: DescriptorIndex) -> Self {
3329 DescriptorPool {
3330 handles: vec![Descriptor(ptr::null_mut()); size as usize],
3331 allocator: RangeAllocator::new(0 .. size),
3332 }
3333 }
3334 }
3335
3336 impl pso::DescriptorPool<Backend> for DescriptorPool {
allocate_set( &mut self, layout: &DescriptorSetLayout, ) -> Result<DescriptorSet, pso::AllocationError>3337 unsafe fn allocate_set(
3338 &mut self,
3339 layout: &DescriptorSetLayout,
3340 ) -> Result<DescriptorSet, pso::AllocationError> {
3341 let len = layout
3342 .pool_mapping
3343 .map_register(|mapping| mapping.count as DescriptorIndex)
3344 .sum()
3345 .max(1);
3346
3347 self.allocator
3348 .allocate_range(len)
3349 .map(|range| {
3350 for handle in &mut self.handles[range.start as usize .. range.end as usize] {
3351 *handle = Descriptor(ptr::null_mut());
3352 }
3353
3354 DescriptorSet {
3355 offset: range.start,
3356 len,
3357 handles: self.handles.as_mut_ptr().offset(range.start as _),
3358 coherent_buffers: Mutex::new(CoherentBuffers {
3359 flush_coherent_buffers: RefCell::new(Vec::new()),
3360 invalidate_coherent_buffers: RefCell::new(Vec::new()),
3361 }),
3362 layout: DescriptorSetLayout {
3363 bindings: Arc::clone(&layout.bindings),
3364 pool_mapping: layout.pool_mapping.clone(),
3365 },
3366 }
3367 })
3368 .map_err(|_| pso::AllocationError::OutOfPoolMemory)
3369 }
3370
free_sets<I>(&mut self, descriptor_sets: I) where I: IntoIterator<Item = DescriptorSet>,3371 unsafe fn free_sets<I>(&mut self, descriptor_sets: I)
3372 where
3373 I: IntoIterator<Item = DescriptorSet>,
3374 {
3375 for set in descriptor_sets {
3376 self.allocator
3377 .free_range(set.offset .. (set.offset + set.len))
3378 }
3379 }
3380
reset(&mut self)3381 unsafe fn reset(&mut self) {
3382 self.allocator.reset();
3383 }
3384 }
3385
3386 #[derive(Debug)]
3387 pub struct RawFence {
3388 mutex: Mutex<bool>,
3389 condvar: Condvar,
3390 }
3391
3392 pub type Fence = Arc<RawFence>;
3393
3394 #[derive(Debug)]
3395 pub struct Semaphore;
3396 #[derive(Debug)]
3397 pub struct QueryPool;
3398
3399 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
3400 pub enum Backend {}
3401 impl hal::Backend for Backend {
3402 type Instance = Instance;
3403 type PhysicalDevice = PhysicalDevice;
3404 type Device = device::Device;
3405
3406 type Surface = Surface;
3407 type Swapchain = Swapchain;
3408
3409 type QueueFamily = QueueFamily;
3410 type CommandQueue = CommandQueue;
3411 type CommandBuffer = CommandBuffer;
3412
3413 type Memory = Memory;
3414 type CommandPool = CommandPool;
3415
3416 type ShaderModule = ShaderModule;
3417 type RenderPass = RenderPass;
3418 type Framebuffer = Framebuffer;
3419
3420 type Buffer = Buffer;
3421 type BufferView = BufferView;
3422 type Image = Image;
3423
3424 type ImageView = ImageView;
3425 type Sampler = Sampler;
3426
3427 type ComputePipeline = ComputePipeline;
3428 type GraphicsPipeline = GraphicsPipeline;
3429 type PipelineLayout = PipelineLayout;
3430 type PipelineCache = ();
3431 type DescriptorSetLayout = DescriptorSetLayout;
3432 type DescriptorPool = DescriptorPool;
3433 type DescriptorSet = DescriptorSet;
3434
3435 type Fence = Fence;
3436 type Semaphore = Semaphore;
3437 type Event = ();
3438 type QueryPool = QueryPool;
3439 }
3440
validate_line_width(width: f32)3441 fn validate_line_width(width: f32) {
3442 // Note from the Vulkan spec:
3443 // > If the wide lines feature is not enabled, lineWidth must be 1.0
3444 // Simply assert and no-op because DX11 never exposes `Features::LINE_WIDTH`
3445 assert_eq!(width, 1.0);
3446 }
3447