Skip to content

Commit a543b43

Browse files
committed
dxgi: share surface_capabilities + typeless-format helpers across DX12/Vulkan
1 parent bb82939 commit a543b43

4 files changed

Lines changed: 120 additions & 99 deletions

File tree

wgpu-hal/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ vulkan = [
117117
"windows/Win32_Graphics_DirectComposition",
118118
"windows/Win32_Security",
119119
"windows/Win32_System_Threading",
120+
"windows/Win32_UI_WindowsAndMessaging",
120121
]
121122
gles = [
122123
"dep:arrayvec",

wgpu-hal/src/auxil/dxgi/conv.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,28 @@ pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> Dxgi::Common::DX
117117
}
118118
}
119119

120+
/// The typeless DXGI format family for `format`, for the color formats wgpu may view as both their
121+
/// sRGB and non-sRGB form. Returns `None` for formats with no such castable typeless family.
122+
///
123+
/// Shared by the DX12 resource-creation path ([`map_texture_format_for_resource`]) and the Windows
124+
/// Vulkan DXGI interop swapchain, which creates its shared interop textures typeless so the imported
125+
/// Vulkan image can be viewed through either form.
126+
pub fn map_texture_format_typeless(
127+
format: wgt::TextureFormat,
128+
) -> Option<Dxgi::Common::DXGI_FORMAT> {
129+
use wgt::TextureFormat as Tf;
130+
use Dxgi::Common::*;
131+
Some(match format {
132+
Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_TYPELESS,
133+
Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_TYPELESS,
134+
Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_TYPELESS,
135+
Tf::Bc2RgbaUnorm | Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_TYPELESS,
136+
Tf::Bc3RgbaUnorm | Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_TYPELESS,
137+
Tf::Bc7RgbaUnorm | Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_TYPELESS,
138+
_ => return None,
139+
})
140+
}
141+
120142
// SRV and UAV can't use the depth or typeless formats
121143
// see https://microsoft.github.io/DirectX-Specs/d3d/PlanarDepthStencilDDISpec.html#view-creation
122144
#[cfg(dx12)]
@@ -204,15 +226,7 @@ pub fn map_texture_format_for_resource(
204226

205227
// We might view this resource as srgb or non-srgb
206228
} else if has_view_formats {
207-
match format {
208-
Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_TYPELESS,
209-
Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_TYPELESS,
210-
Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_TYPELESS,
211-
Tf::Bc2RgbaUnorm | Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_TYPELESS,
212-
Tf::Bc3RgbaUnorm | Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_TYPELESS,
213-
Tf::Bc7RgbaUnorm | Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_TYPELESS,
214-
format => map_texture_format(format),
215-
}
229+
map_texture_format_typeless(format).unwrap_or_else(|| map_texture_format(format))
216230

217231
// We might view this resource as SRV/UAV but also as DSV
218232
} else if format.is_depth_stencil_format()

wgpu-hal/src/auxil/dxgi/swapchain.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! Windows Vulkan backend's DXGI interop swapchain.
33
44
use parking_lot::Mutex;
5-
use windows::Win32::{Foundation, Graphics::Dxgi, System::Threading};
5+
use windows::Win32::{Foundation, Graphics::Dxgi, System::Threading, UI::WindowsAndMessaging};
66

77
use crate::auxil::dxgi::{dcomp, factory::DxgiFactory};
88

@@ -151,3 +151,93 @@ pub(crate) fn map_surface_color_space(
151151
}
152152
}
153153
}
154+
155+
/// The presentation capabilities of a DXGI flip-model surface; identical for both backends, since
156+
/// they drive the same kind of swapchain.
157+
pub(crate) fn surface_capabilities(
158+
target: &SurfaceTarget,
159+
supports_allow_tearing: bool,
160+
) -> crate::SurfaceCapabilities {
161+
let mut present_modes = vec![wgt::PresentMode::Mailbox, wgt::PresentMode::Fifo];
162+
if supports_allow_tearing {
163+
present_modes.push(wgt::PresentMode::Immediate);
164+
}
165+
166+
// `Surface::configure` applies the requested color space with
167+
// `IDXGISwapChain3::SetColorSpace1`. fp16 buffers keep DXGI's scRGB interpretation
168+
// (`DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709`) and `Rgb10a2Unorm` additionally supports
169+
// BT.2100 PQ (HDR10).
170+
//
171+
// These color spaces are advertised unconditionally, not gated on whether the output is
172+
// currently in HDR mode: Windows always composites in scRGB and tone-maps PQ down to an SDR
173+
// output, so the color space is configurable regardless, and `CheckColorSpaceSupport`
174+
// returning false does not mean it won't present. Whether HDR is actually *visible* is a
175+
// separate, live question (the display-HDR query, #9739), not a configuration gate. Display-P3
176+
// and HLG are never reported: DXGI has no RGB HLG swapchain color space, and P3 isn't a DXGI
177+
// swapchain color space.
178+
let formats = [
179+
wgt::TextureFormat::Bgra8UnormSrgb,
180+
wgt::TextureFormat::Bgra8Unorm,
181+
wgt::TextureFormat::Rgba8UnormSrgb,
182+
wgt::TextureFormat::Rgba8Unorm,
183+
wgt::TextureFormat::Rgb10a2Unorm,
184+
wgt::TextureFormat::Rgba16Float,
185+
]
186+
.map(|format| wgt::SurfaceFormatCapabilities {
187+
format,
188+
color_spaces: match format {
189+
wgt::TextureFormat::Rgba16Float => wgt::SurfaceColorSpaces::EXTENDED_SRGB_LINEAR,
190+
wgt::TextureFormat::Rgb10a2Unorm => {
191+
wgt::SurfaceColorSpaces::SRGB | wgt::SurfaceColorSpaces::BT2100_PQ
192+
}
193+
_ => wgt::SurfaceColorSpaces::SRGB,
194+
},
195+
})
196+
.to_vec();
197+
198+
let composite_alpha_modes = match target {
199+
SurfaceTarget::WndHandle(_) => vec![wgt::CompositeAlphaMode::Opaque],
200+
_ => vec![
201+
wgt::CompositeAlphaMode::Auto,
202+
wgt::CompositeAlphaMode::Inherit,
203+
wgt::CompositeAlphaMode::Opaque,
204+
wgt::CompositeAlphaMode::PostMultiplied,
205+
wgt::CompositeAlphaMode::PreMultiplied,
206+
],
207+
};
208+
209+
crate::SurfaceCapabilities {
210+
formats,
211+
// See https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgidevice1-setmaximumframelatency
212+
maximum_frame_latency: 1..=16,
213+
current_extent: surface_extent(target),
214+
usage: wgt::TextureUses::COLOR_TARGET
215+
| wgt::TextureUses::COPY_SRC
216+
| wgt::TextureUses::COPY_DST,
217+
present_modes,
218+
composite_alpha_modes,
219+
}
220+
}
221+
222+
/// The current client-area extent of `target`'s backing window, or `None` for targets without one
223+
/// (the DX12 external-surface variants) or when the query fails.
224+
fn surface_extent(target: &SurfaceTarget) -> Option<wgt::Extent3d> {
225+
let handle = match target {
226+
SurfaceTarget::WndHandle(handle) | SurfaceTarget::VisualFromWndHandle { handle, .. } => {
227+
*handle
228+
}
229+
#[allow(unreachable_patterns)]
230+
_ => return None,
231+
};
232+
let mut rect = Default::default();
233+
if unsafe { WindowsAndMessaging::GetClientRect(handle, &mut rect) }.is_ok() {
234+
Some(wgt::Extent3d {
235+
width: (rect.right - rect.left) as u32,
236+
height: (rect.bottom - rect.top) as u32,
237+
depth_or_array_layers: 1,
238+
})
239+
} else {
240+
log::warn!("Unable to get the window client rect");
241+
None
242+
}
243+
}

wgpu-hal/src/dx12/adapter.rs

Lines changed: 5 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ use windows::{
1313
},
1414
Foundation::{GetLastError, ERROR_NO_MORE_ITEMS},
1515
Graphics::{Direct3D, Direct3D12, Dxgi},
16-
UI::WindowsAndMessaging,
1716
},
1817
};
1918

2019
use super::D3D12Lib;
2120
use crate::{
2221
auxil::{
2322
self,
24-
dxgi::{dcomp::DCompLib, factory::DxgiAdapter, result::HResult, swapchain::SurfaceTarget},
23+
dxgi::{dcomp::DCompLib, factory::DxgiAdapter, result::HResult},
2524
},
2625
dx12::{device_creation::DeviceFactory, shader_compilation, FeatureLevel, ShaderModel},
2726
};
@@ -1285,93 +1284,10 @@ impl crate::Adapter for super::Adapter {
12851284
&self,
12861285
surface: &super::Surface,
12871286
) -> Option<crate::SurfaceCapabilities> {
1288-
let current_extent = {
1289-
match surface.target {
1290-
SurfaceTarget::WndHandle(wnd_handle)
1291-
| SurfaceTarget::VisualFromWndHandle {
1292-
handle: wnd_handle, ..
1293-
} => {
1294-
let mut rect = Default::default();
1295-
if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok()
1296-
{
1297-
Some(wgt::Extent3d {
1298-
width: (rect.right - rect.left) as u32,
1299-
height: (rect.bottom - rect.top) as u32,
1300-
depth_or_array_layers: 1,
1301-
})
1302-
} else {
1303-
log::warn!("Unable to get the window client rect");
1304-
None
1305-
}
1306-
}
1307-
SurfaceTarget::Visual(_)
1308-
| SurfaceTarget::SurfaceHandle(_)
1309-
| SurfaceTarget::SwapChainPanel(_) => None,
1310-
}
1311-
};
1312-
1313-
let mut present_modes = vec![wgt::PresentMode::Mailbox, wgt::PresentMode::Fifo];
1314-
if surface.supports_allow_tearing {
1315-
present_modes.push(wgt::PresentMode::Immediate);
1316-
}
1317-
1318-
Some(crate::SurfaceCapabilities {
1319-
// `Surface::configure` applies the requested color space with
1320-
// `IDXGISwapChain3::SetColorSpace1`. fp16 buffers keep DXGI's
1321-
// scRGB interpretation (`DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709`)
1322-
// and `Rgb10a2Unorm` additionally supports BT.2100 PQ (HDR10).
1323-
//
1324-
// These color spaces are advertised unconditionally, not gated on
1325-
// whether the output is currently in HDR mode: Windows always
1326-
// composites in scRGB and tone-maps PQ down to an SDR output, so the
1327-
// color space is configurable regardless, and `CheckColorSpaceSupport`
1328-
// returning false does not mean it won't present. Whether HDR is
1329-
// actually *visible* is a separate, live question (the upcoming
1330-
// display-HDR query, #9739), not a configuration gate. Display-P3 and
1331-
// HLG are never reported: DXGI has no RGB HLG swapchain color space,
1332-
// and P3 isn't a DXGI swapchain color space.
1333-
formats: [
1334-
wgt::TextureFormat::Bgra8UnormSrgb,
1335-
wgt::TextureFormat::Bgra8Unorm,
1336-
wgt::TextureFormat::Rgba8UnormSrgb,
1337-
wgt::TextureFormat::Rgba8Unorm,
1338-
wgt::TextureFormat::Rgb10a2Unorm,
1339-
wgt::TextureFormat::Rgba16Float,
1340-
]
1341-
.map(|format| wgt::SurfaceFormatCapabilities {
1342-
format,
1343-
color_spaces: match format {
1344-
wgt::TextureFormat::Rgba16Float => {
1345-
wgt::SurfaceColorSpaces::EXTENDED_SRGB_LINEAR
1346-
}
1347-
wgt::TextureFormat::Rgb10a2Unorm => {
1348-
wgt::SurfaceColorSpaces::SRGB | wgt::SurfaceColorSpaces::BT2100_PQ
1349-
}
1350-
_ => wgt::SurfaceColorSpaces::SRGB,
1351-
},
1352-
})
1353-
.to_vec(),
1354-
// See https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgidevice1-setmaximumframelatency
1355-
maximum_frame_latency: 1..=16,
1356-
current_extent,
1357-
usage: wgt::TextureUses::COLOR_TARGET
1358-
| wgt::TextureUses::COPY_SRC
1359-
| wgt::TextureUses::COPY_DST,
1360-
present_modes,
1361-
composite_alpha_modes: match surface.target {
1362-
SurfaceTarget::WndHandle(_) => vec![wgt::CompositeAlphaMode::Opaque],
1363-
SurfaceTarget::Visual(_)
1364-
| SurfaceTarget::VisualFromWndHandle { .. }
1365-
| SurfaceTarget::SurfaceHandle(_)
1366-
| SurfaceTarget::SwapChainPanel(_) => vec![
1367-
wgt::CompositeAlphaMode::Auto,
1368-
wgt::CompositeAlphaMode::Inherit,
1369-
wgt::CompositeAlphaMode::Opaque,
1370-
wgt::CompositeAlphaMode::PostMultiplied,
1371-
wgt::CompositeAlphaMode::PreMultiplied,
1372-
],
1373-
},
1374-
})
1287+
Some(auxil::dxgi::swapchain::surface_capabilities(
1288+
&surface.target,
1289+
surface.supports_allow_tearing,
1290+
))
13751291
}
13761292

13771293
unsafe fn surface_display_hdr_info(

0 commit comments

Comments
 (0)