mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hal/dx12: swap chain configuration
This commit is contained in:
committed by
Dzmitry Malyshau
parent
eb565a59f7
commit
0942fb1346
@@ -244,7 +244,10 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
})?;
|
||||
|
||||
Ok(crate::OpenDevice {
|
||||
device: super::Device { raw: self.device },
|
||||
device: super::Device {
|
||||
raw: self.device,
|
||||
present_queue: queue,
|
||||
},
|
||||
queue: super::Queue { raw: queue },
|
||||
})
|
||||
}
|
||||
@@ -371,7 +374,11 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
| crate::TextureUses::COPY_SRC
|
||||
| crate::TextureUses::COPY_DST,
|
||||
present_modes,
|
||||
composite_alpha_modes: vec![crate::CompositeAlphaMode::Opaque],
|
||||
composite_alpha_modes: vec![
|
||||
crate::CompositeAlphaMode::Opaque,
|
||||
crate::CompositeAlphaMode::PreMultiplied,
|
||||
crate::CompositeAlphaMode::PostMultiplied,
|
||||
],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use winapi::shared::dxgiformat;
|
||||
use winapi::shared::{dxgi1_2, dxgiformat};
|
||||
|
||||
pub(super) fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
|
||||
use wgt::TextureFormat as Tf;
|
||||
@@ -95,3 +95,22 @@ pub(super) fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI
|
||||
| Tf::Astc12x12RgbaUnormSrgb => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
|
||||
// NOTE: DXGI doesn't allow sRGB format on the swapchain, but
|
||||
// creating RTV of swapchain buffers with sRGB works
|
||||
match format {
|
||||
wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
_ => map_texture_format(format),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_acomposite_alpha_mode(mode: crate::CompositeAlphaMode) -> dxgi1_2::DXGI_ALPHA_MODE {
|
||||
use crate::CompositeAlphaMode as Cam;
|
||||
match mode {
|
||||
Cam::Opaque => dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
|
||||
Cam::PreMultiplied => dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
|
||||
Cam::PostMultiplied => dxgi1_2::DXGI_ALPHA_MODE_STRAIGHT,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ mod command;
|
||||
mod conv;
|
||||
mod device;
|
||||
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::{borrow::Cow, ptr, sync::Arc};
|
||||
use winapi::{
|
||||
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, windef, winerror},
|
||||
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, dxgitype, windef, winerror},
|
||||
um::{d3d12, synchapi, winbase, winnt},
|
||||
Interface as _,
|
||||
};
|
||||
|
||||
@@ -101,7 +102,54 @@ impl Drop for Instance {
|
||||
unsafe impl Send for Instance {}
|
||||
unsafe impl Sync for Instance {}
|
||||
|
||||
struct SwapChain {}
|
||||
#[derive(Copy, Clone)]
|
||||
struct DualHandle {
|
||||
cpu: native::CpuDescriptor,
|
||||
gpu: native::GpuDescriptor,
|
||||
/// How large the block allocated to this handle is.
|
||||
size: u64,
|
||||
}
|
||||
|
||||
type DescriptorIndex = u64;
|
||||
|
||||
struct DescriptorHeap {
|
||||
raw: native::DescriptorHeap,
|
||||
handle_size: u64,
|
||||
total_handles: u64,
|
||||
start: DualHandle,
|
||||
}
|
||||
|
||||
impl DescriptorHeap {
|
||||
fn at(&self, index: DescriptorIndex, size: u64) -> DualHandle {
|
||||
assert!(index < self.total_handles);
|
||||
DualHandle {
|
||||
cpu: self.cpu_descriptor_at(index),
|
||||
gpu: self.gpu_descriptor_at(index),
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
fn cpu_descriptor_at(&self, index: u64) -> native::CpuDescriptor {
|
||||
native::CpuDescriptor {
|
||||
ptr: self.start.cpu.ptr + (self.handle_size * index) as usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn gpu_descriptor_at(&self, index: u64) -> native::GpuDescriptor {
|
||||
native::GpuDescriptor {
|
||||
ptr: self.start.gpu.ptr + self.handle_size * index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SwapChain {
|
||||
raw: native::WeakPtr<dxgi1_4::IDXGISwapChain3>,
|
||||
// need to associate raw image pointers with the swapchain so they can be properly released
|
||||
// when the swapchain is destroyed
|
||||
resources: Vec<native::Resource>,
|
||||
waitable: winnt::HANDLE,
|
||||
acquired_count: usize,
|
||||
}
|
||||
|
||||
pub struct Surface {
|
||||
factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
|
||||
@@ -144,6 +192,7 @@ unsafe impl Sync for Adapter {}
|
||||
|
||||
pub struct Device {
|
||||
raw: native::Device,
|
||||
present_queue: native::CommandQueue,
|
||||
}
|
||||
|
||||
unsafe impl Send for Device {}
|
||||
@@ -309,16 +358,148 @@ impl crate::Instance<Api> for Instance {
|
||||
}
|
||||
}
|
||||
|
||||
impl SwapChain {
|
||||
unsafe fn release_resources(self) -> native::WeakPtr<dxgi1_4::IDXGISwapChain3> {
|
||||
for resource in self.resources {
|
||||
resource.destroy();
|
||||
}
|
||||
self.raw
|
||||
}
|
||||
|
||||
unsafe fn wait(&mut self, timeout_ms: u32) -> Result<bool, crate::SurfaceError> {
|
||||
match synchapi::WaitForSingleObject(self.waitable, timeout_ms) {
|
||||
winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => Err(crate::SurfaceError::Lost),
|
||||
winbase::WAIT_OBJECT_0 => Ok(true),
|
||||
winerror::WAIT_TIMEOUT => Ok(false),
|
||||
other => {
|
||||
log::error!("Unexpected wait status: 0x{:x}", other);
|
||||
Err(crate::SurfaceError::Lost)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Surface<Api> for Surface {
|
||||
unsafe fn configure(
|
||||
&mut self,
|
||||
device: &Device,
|
||||
config: &crate::SurfaceConfiguration,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
let mut flags = dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||
match config.present_mode {
|
||||
wgt::PresentMode::Immediate => {
|
||||
flags |= dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let non_srgb_format = conv::map_texture_format_nosrgb(config.format);
|
||||
|
||||
let swap_chain = match self.swap_chain.take() {
|
||||
Some(sc) => {
|
||||
// can't have image resources in flight used by GPU
|
||||
//device.wait_idle().unwrap();
|
||||
|
||||
let raw = sc.release_resources();
|
||||
let result = raw.ResizeBuffers(
|
||||
config.swap_chain_size,
|
||||
config.extent.width,
|
||||
config.extent.height,
|
||||
non_srgb_format,
|
||||
flags,
|
||||
);
|
||||
if let Some(err) = result.to_error() {
|
||||
log::error!("ResizeBuffers failed: {}", err);
|
||||
return Err(crate::SurfaceError::Other("window is in use"));
|
||||
}
|
||||
raw
|
||||
}
|
||||
None => {
|
||||
let mut swap_chain1 = native::WeakPtr::<dxgi1_2::IDXGISwapChain1>::null();
|
||||
|
||||
let raw_desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
|
||||
AlphaMode: conv::map_acomposite_alpha_mode(config.composite_alpha_mode),
|
||||
BufferCount: config.swap_chain_size,
|
||||
Width: config.extent.width,
|
||||
Height: config.extent.height,
|
||||
Format: non_srgb_format,
|
||||
Flags: flags,
|
||||
BufferUsage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Scaling: dxgi1_2::DXGI_SCALING_STRETCH,
|
||||
Stereo: 0,
|
||||
SwapEffect: dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
||||
};
|
||||
|
||||
let hr = self.factory.CreateSwapChainForHwnd(
|
||||
device.present_queue.as_mut_ptr() as *mut _,
|
||||
self.wnd_handle,
|
||||
&raw_desc,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
swap_chain1.mut_void() as *mut *mut _,
|
||||
);
|
||||
|
||||
if let Some(err) = hr.to_error() {
|
||||
log::error!("SwapChain creation error: {}", err);
|
||||
return Err(crate::SurfaceError::Other("swap chain creation"));
|
||||
}
|
||||
|
||||
match swap_chain1.cast::<dxgi1_4::IDXGISwapChain3>().check() {
|
||||
Ok(swap_chain3) => {
|
||||
swap_chain1.destroy();
|
||||
swap_chain3
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Unable to cast swap chain: {}", err);
|
||||
return Err(crate::SurfaceError::Other("swap chain cast to 3"));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Disable automatic Alt+Enter handling by DXGI.
|
||||
const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1;
|
||||
const DXGI_MWA_NO_ALT_ENTER: u32 = 2;
|
||||
self.factory.MakeWindowAssociation(
|
||||
self.wnd_handle,
|
||||
DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER,
|
||||
);
|
||||
|
||||
swap_chain.SetMaximumFrameLatency(config.swap_chain_size);
|
||||
let waitable = swap_chain.GetFrameLatencyWaitableObject();
|
||||
|
||||
let mut resources = vec![native::Resource::null(); config.swap_chain_size as usize];
|
||||
for (i, res) in resources.iter_mut().enumerate() {
|
||||
swap_chain.GetBuffer(i as _, &d3d12::ID3D12Resource::uuidof(), res.mut_void());
|
||||
}
|
||||
|
||||
self.swap_chain = Some(SwapChain {
|
||||
raw: swap_chain,
|
||||
resources,
|
||||
waitable,
|
||||
acquired_count: 0,
|
||||
//format: config.format,
|
||||
//size: config.extent,
|
||||
//mode: config.present_mode,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn unconfigure(&mut self, device: &Device) {}
|
||||
unsafe fn unconfigure(&mut self, device: &Device) {
|
||||
if let Some(mut sc) = self.swap_chain.take() {
|
||||
let _ = sc.wait(winbase::INFINITE);
|
||||
//TODO: this shouldn't be needed,
|
||||
// but it complains that the queue is still used otherwise
|
||||
//let _ = device.wait_idle();
|
||||
let raw = sc.release_resources();
|
||||
raw.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn acquire_texture(
|
||||
&mut self,
|
||||
|
||||
Reference in New Issue
Block a user