gpui: Enable per-pixel, GPU composited transparency on Windows (#26645)
Move the SetLayeredWindowAttributes call to immediately after window construction, and initialize it with per-pixel transparency settings, no color key and no global blending. The render pipeline will perform alpha blending during compositing. Cleaned up the DWM acrylic API calls some, to explicitly set to the three appropriate modes depending on opaque, transparent or blurred settings. The API internally hides versioning concerns from the caller. Set the window class background color to black, this prevents a flashbang on slow startup, e.g. debug builds on a heavily loaded system. The outcome is that the window no longer receives paint demands for underlying window updates, while also having per-pixel transparency - opaque theme elements are now correctly opaque. The transparency settings are now portable across windows and macOS having mostly similar outcomes (modulo palette differences). Small fonts may still appear to be alpha blended - this seems to be in the glyph atlas, their pixels are not actually opaque. Larger fonts (or higher DPIs) don't suffer this and are as opaque as expected. Layering the window atop one that is rendering at 120fps, the editor window can drop to its 8fps idle state, while still being composited with 120fps alpha blend in the background, in both blur and transparent modes. Updates #20400 Release Notes: - Improved transparency on Windows to be more efficient, support fully opaque elements and more closely match other platforms.
This commit is contained in:
parent
384868e597
commit
94b75f3ad9
1 changed files with 30 additions and 36 deletions
|
@ -390,10 +390,10 @@ impl WindowsWindow {
|
|||
.unwrap_or(""),
|
||||
);
|
||||
let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp {
|
||||
(WS_EX_TOOLWINDOW, WINDOW_STYLE(0x0))
|
||||
(WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0))
|
||||
} else {
|
||||
(
|
||||
WS_EX_APPWINDOW,
|
||||
WS_EX_APPWINDOW | WS_EX_LAYERED,
|
||||
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||
)
|
||||
};
|
||||
|
@ -459,6 +459,14 @@ impl WindowsWindow {
|
|||
state: WindowOpenState::Windowed,
|
||||
});
|
||||
}
|
||||
// The render pipeline will perform compositing on the GPU when the
|
||||
// swapchain is configured correctly (see downstream of
|
||||
// update_transparency).
|
||||
// The following configuration is a one-time setup to ensure that the
|
||||
// window is going to be composited with per-pixel alpha, but the render
|
||||
// pipeline is responsible for effectively calling UpdateLayeredWindow
|
||||
// at the appropriate time.
|
||||
unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? };
|
||||
|
||||
Ok(Self(state_ptr))
|
||||
}
|
||||
|
@ -703,41 +711,20 @@ impl PlatformWindow for WindowsWindow {
|
|||
window_state
|
||||
.renderer
|
||||
.update_transparency(background_appearance != WindowBackgroundAppearance::Opaque);
|
||||
let mut version = unsafe { std::mem::zeroed() };
|
||||
let status = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) };
|
||||
if status.is_ok() {
|
||||
if background_appearance == WindowBackgroundAppearance::Blurred {
|
||||
if version.dwBuildNumber >= 17763 {
|
||||
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 10)), 4);
|
||||
}
|
||||
} else {
|
||||
if version.dwBuildNumber >= 17763 {
|
||||
|
||||
match background_appearance {
|
||||
WindowBackgroundAppearance::Opaque => {
|
||||
// ACCENT_DISABLED
|
||||
set_window_composition_attribute(window_state.hwnd, None, 0);
|
||||
}
|
||||
WindowBackgroundAppearance::Transparent => {
|
||||
// Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background
|
||||
set_window_composition_attribute(window_state.hwnd, None, 2);
|
||||
}
|
||||
//Transparent effect might cause some flickering and performance issues due `WS_EX_COMPOSITED` is enabled
|
||||
//if `WS_EX_COMPOSITED` is removed the window instance won't initiate
|
||||
if background_appearance == WindowBackgroundAppearance::Transparent {
|
||||
unsafe {
|
||||
let current_style = GetWindowLongW(window_state.hwnd, GWL_EXSTYLE);
|
||||
SetWindowLongW(
|
||||
window_state.hwnd,
|
||||
GWL_EXSTYLE,
|
||||
current_style | WS_EX_LAYERED.0 as i32 | WS_EX_COMPOSITED.0 as i32,
|
||||
);
|
||||
SetLayeredWindowAttributes(window_state.hwnd, COLORREF(0), 225, LWA_ALPHA)
|
||||
.inspect_err(|e| log::error!("Unable to set window to transparent: {e}"))
|
||||
.ok();
|
||||
};
|
||||
} else {
|
||||
unsafe {
|
||||
let current_style = GetWindowLongW(window_state.hwnd, GWL_EXSTYLE);
|
||||
SetWindowLongW(
|
||||
window_state.hwnd,
|
||||
GWL_EXSTYLE,
|
||||
current_style & !WS_EX_LAYERED.0 as i32 & !WS_EX_COMPOSITED.0 as i32,
|
||||
);
|
||||
}
|
||||
WindowBackgroundAppearance::Blurred => {
|
||||
// Enable acrylic blur
|
||||
// ACCENT_ENABLE_ACRYLICBLURBEHIND
|
||||
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1084,6 +1071,7 @@ fn register_wnd_class(icon_handle: HICON) -> PCWSTR {
|
|||
lpszClassName: PCWSTR(CLASS_NAME.as_ptr()),
|
||||
style: CS_HREDRAW | CS_VREDRAW,
|
||||
hInstance: get_module_handle().into(),
|
||||
hbrBackground: unsafe { CreateSolidBrush(COLORREF(0x00000000)) },
|
||||
..Default::default()
|
||||
};
|
||||
unsafe { RegisterClassW(&wc) };
|
||||
|
@ -1241,6 +1229,12 @@ fn retrieve_window_placement(
|
|||
}
|
||||
|
||||
fn set_window_composition_attribute(hwnd: HWND, color: Option<Color>, state: u32) {
|
||||
let mut version = unsafe { std::mem::zeroed() };
|
||||
let status = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) };
|
||||
if !status.is_ok() || version.dwBuildNumber < 17763 {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
type SetWindowCompositionAttributeType =
|
||||
unsafe extern "system" fn(HWND, *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue