-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add support for builtin DComp swapchains #7550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
e6d7e5f
c328699
3f91a00
b8131bf
1f70a9a
60a747c
8b012f3
91d98af
bae60c3
194a685
32ce523
157c1c6
cd41a6e
73579d3
cae67ca
830bf2b
f40d9b5
2302705
504dfa1
62758fe
25f68fa
7b5d124
eab2de6
a9ddf45
55659a1
92afbbc
783e730
1a9ff41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use windows::Win32::{Foundation::HWND, Graphics::DirectComposition}; | ||
|
||
#[derive(Default)] | ||
pub struct DCompState { | ||
inner: Option<InnerState>, | ||
} | ||
|
||
impl DCompState { | ||
/// This will create a DirectComposition device and a target for the window handle if not already initialized. | ||
/// If the device is already initialized, it will return the existing state. | ||
pub unsafe fn get_or_init( | ||
&mut self, | ||
hwnd: &HWND, | ||
) -> Result<&mut InnerState, crate::SurfaceError> { | ||
if self.inner.is_none() { | ||
self.inner = Some(unsafe { InnerState::init(hwnd) }?); | ||
} | ||
Ok(self.inner.as_mut().unwrap()) | ||
} | ||
} | ||
|
||
pub struct InnerState { | ||
pub visual: DirectComposition::IDCompositionVisual, | ||
pub device: DirectComposition::IDCompositionDevice, | ||
// Must be kept alive but is otherwise unused after initialization. | ||
pub _target: DirectComposition::IDCompositionTarget, | ||
} | ||
|
||
impl InnerState { | ||
/// Creates a DirectComposition device and a target for the given window handle. | ||
pub unsafe fn init(hwnd: &HWND) -> Result<Self, crate::SurfaceError> { | ||
let dcomp_device: DirectComposition::IDCompositionDevice = { | ||
profiling::scope!("DirectComposition::DCompositionCreateDevice"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wondering, is it normal to wrap every external API call - especially these that are well off the hot path - in a profiling scope? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps just a single profile scope for the whole init scope? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah lets do a single scope - generally the decision for what to scope depends on how long it takes, so if there's a single item that takes a long time, scope that, but for processes that only really take a while in aggregate, we can use a single scope. |
||
unsafe { DirectComposition::DCompositionCreateDevice2(None) }.map_err(|err| { | ||
log::error!("DirectComposition::DCompositionCreateDevice failed: {err}"); | ||
crate::SurfaceError::Other("DirectComposition::DCompositionCreateDevice") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's surprising that |
||
})? | ||
}; | ||
|
||
let target = { | ||
profiling::scope!("IDCompositionDevice::CreateTargetForHwnd"); | ||
unsafe { dcomp_device.CreateTargetForHwnd(*hwnd, false) }.map_err(|err| { | ||
log::error!("IDCompositionDevice::CreateTargetForHwnd failed: {err}"); | ||
crate::SurfaceError::Other("IDCompositionDevice::CreateTargetForHwnd") | ||
})? | ||
}; | ||
|
||
let visual = { | ||
profiling::scope!("IDCompositionDevice::CreateVisual"); | ||
unsafe { dcomp_device.CreateVisual() }.map_err(|err| { | ||
log::error!("IDCompositionDevice::CreateVisual failed: {err}"); | ||
crate::SurfaceError::Other("IDCompositionDevice::CreateVisual") | ||
})? | ||
}; | ||
|
||
{ | ||
profiling::scope!("IDCompositionTarget::SetRoot"); | ||
unsafe { target.SetRoot(&visual) }.map_err(|err| { | ||
log::error!("IDCompositionTarget::SetRoot failed: {err}"); | ||
crate::SurfaceError::Other("IDCompositionTarget::SetRoot") | ||
})?; | ||
} | ||
|
||
Ok(InnerState { | ||
visual, | ||
device: dcomp_device, | ||
_target: target, | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -359,6 +359,8 @@ impl GlBackendOptions { | |
pub struct Dx12BackendOptions { | ||
/// Which DX12 shader compiler to use. | ||
pub shader_compiler: Dx12Compiler, | ||
/// Presentation system to use. | ||
pub presentation_system: Dx12SwapchainKind, | ||
/// Whether to wait for the latency waitable object before acquiring the next swapchain image. | ||
pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject, | ||
} | ||
|
@@ -370,10 +372,12 @@ impl Dx12BackendOptions { | |
#[must_use] | ||
pub fn from_env_or_default() -> Self { | ||
let compiler = Dx12Compiler::from_env().unwrap_or_default(); | ||
let presentation_system = Dx12SwapchainKind::from_env().unwrap_or_default(); | ||
let latency_waitable_object = | ||
Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default(); | ||
Self { | ||
shader_compiler: compiler, | ||
presentation_system, | ||
latency_waitable_object, | ||
} | ||
} | ||
|
@@ -384,10 +388,11 @@ impl Dx12BackendOptions { | |
#[must_use] | ||
pub fn with_env(self) -> Self { | ||
let shader_compiler = self.shader_compiler.with_env(); | ||
let presentation_system = self.presentation_system.with_env(); | ||
let latency_waitable_object = self.latency_waitable_object.with_env(); | ||
|
||
Self { | ||
shader_compiler, | ||
presentation_system, | ||
latency_waitable_object, | ||
} | ||
} | ||
|
@@ -439,6 +444,51 @@ impl NoopBackendOptions { | |
} | ||
} | ||
|
||
#[derive(Clone, Debug, Default, Copy, PartialEq, Eq)] | ||
/// Selects which kind of swapchain to use on DX12. | ||
pub enum Dx12SwapchainKind { | ||
/// Use a DXGI swapchain made directly from the window's HWND. | ||
/// | ||
/// This supports fullscreen optimization, making borderless windows just as efficient as exclusive fullscreen. It does not support transparent windows. | ||
#[default] | ||
Dxgi, | ||
/// Use a DXGI swapchain made from a DirectComposition visual made from the window. | ||
/// | ||
/// This supports transparent windows, but does not support fullscreen optimization. | ||
DirectComposition, | ||
} | ||
|
||
impl Dx12SwapchainKind { | ||
/// Choose which presentation system to use from the environment variable `WGPU_DX12_PRESENTATION_SYSTEM`. | ||
/// | ||
/// Valid values, case insensitive: | ||
/// - `Dxgi` | ||
/// - `DirectComposition` | ||
#[must_use] | ||
pub fn from_env() -> Option<Self> { | ||
let value = crate::env::var("WGPU_DX12_PRESENTATION_SYSTEM") | ||
.as_deref()? | ||
.to_lowercase(); | ||
match value.as_str() { | ||
"dcomp" => Some(Self::DirectComposition), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also update the argument name? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh ya was gonna ask we wanted to update that. though i could see leaving it so its short in the cli There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think having both would be reasonable as well. |
||
"dxgi" => Some(Self::Dxgi), | ||
_ => None, | ||
} | ||
} | ||
|
||
/// Takes the given presentation system, modifies it based on the `WGPU_DX12_PRESENTATION_SYSTEM` environment variable, and returns the result. | ||
/// | ||
/// See [`from_env`](Self::from_env) for more information. | ||
#[must_use] | ||
pub fn with_env(self) -> Self { | ||
if let Some(presentation_system) = Self::from_env() { | ||
presentation_system | ||
} else { | ||
self | ||
} | ||
} | ||
} | ||
|
||
/// DXC shader model. | ||
#[derive(Clone, Debug)] | ||
#[allow(missing_docs)] | ||
|
Uh oh!
There was an error while loading. Please reload this page.