finetune transpanrency

This commit is contained in:
Junkui Zhang 2025-07-17 14:36:41 +08:00
parent 7ab2d0d800
commit c6e020f60f
2 changed files with 15 additions and 146 deletions

View file

@ -27,7 +27,6 @@ pub(crate) struct DirectXRenderer {
context: DirectXContext, context: DirectXContext,
globals: DirectXGlobalElements, globals: DirectXGlobalElements,
pipelines: DirectXRenderPipelines, pipelines: DirectXRenderPipelines,
transparent: bool,
} }
#[derive(Clone)] #[derive(Clone)]
@ -46,7 +45,7 @@ struct DirectXContext {
msaa_view: ID3D11RenderTargetView, msaa_view: ID3D11RenderTargetView,
viewport: [D3D11_VIEWPORT; 1], viewport: [D3D11_VIEWPORT; 1],
// #[cfg(not(feature = "enable-renderdoc"))] // #[cfg(not(feature = "enable-renderdoc"))]
direct_composition: DirectComposition, _direct_composition: DirectComposition,
} }
struct DirectXRenderPipelines { struct DirectXRenderPipelines {
@ -101,12 +100,12 @@ impl DirectXDevices {
} }
impl DirectXRenderer { impl DirectXRenderer {
pub(crate) fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> { pub(crate) fn new(devices: &DirectXDevices, hwnd: HWND) -> Result<Self> {
let atlas = Arc::new(DirectXAtlas::new( let atlas = Arc::new(DirectXAtlas::new(
devices.device.clone(), devices.device.clone(),
devices.device_context.clone(), devices.device_context.clone(),
)); ));
let context = DirectXContext::new(devices, hwnd, transparent)?; let context = DirectXContext::new(devices, hwnd)?;
let globals = DirectXGlobalElements::new(&devices.device)?; let globals = DirectXGlobalElements::new(&devices.device)?;
let pipelines = DirectXRenderPipelines::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?;
Ok(DirectXRenderer { Ok(DirectXRenderer {
@ -115,7 +114,6 @@ impl DirectXRenderer {
context, context,
globals, globals,
pipelines, pipelines,
transparent,
}) })
} }
@ -241,93 +239,6 @@ impl DirectXRenderer {
Ok(()) Ok(())
} }
// #[cfg(not(feature = "enable-renderdoc"))]
pub(crate) fn update_transparency(
&mut self,
background_appearance: WindowBackgroundAppearance,
) -> Result<()> {
let transparent = background_appearance != WindowBackgroundAppearance::Opaque;
if self.transparent == transparent {
return Ok(());
}
// self.transparent = transparent;
// let (width, height) = unsafe {
// self.devices.device_context.OMSetRenderTargets(None, None);
// ManuallyDrop::drop(&mut self.context.render_target);
// drop(self.context.render_target_view[0].take().unwrap());
// let desc = self.context.swap_chain.GetDesc1().unwrap();
// ManuallyDrop::drop(&mut self.context.swap_chain);
// (desc.Width, desc.Height)
// };
// self.context.swap_chain = create_swap_chain(
// &self.devices.dxgi_factory,
// &self.devices.device,
// transparent,
// width,
// height,
// )
// .unwrap();
// self.context
// .direct_composition
// .set_swap_chain(&self.context.swap_chain)
// .context("Failed to set swap chain for DirectComposition")?;
// let (render_target, render_target_view) =
// create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device)
// .unwrap();
// self.context.render_target = render_target;
// self.context.render_target_view = render_target_view;
// unsafe {
// self.devices
// .device_context
// .OMSetRenderTargets(Some(&self.context.render_target_view), None);
// }
// let (msaa_target, msaa_view) =
// create_msaa_target_and_its_view(&self.devices.device, width, height)?;
// self.context.msaa_target = msaa_target;
// self.context.msaa_view = msaa_view;
// self.context.viewport = set_viewport(&self.devices.device_context, width as _, height as _);
// set_rasterizer_state(&self.devices.device, &self.devices.device_context)?;
Ok(())
}
// #[cfg(feature = "enable-renderdoc")]
// pub(crate) fn update_transparency(
// &mut self,
// background_appearance: WindowBackgroundAppearance,
// ) -> Result<()> {
// let transparent = background_appearance != WindowBackgroundAppearance::Opaque;
// if self.transparent == transparent {
// return Ok(());
// }
// self.transparent = transparent;
// unsafe {
// // recreate the swapchain
// self.devices.device_context.OMSetRenderTargets(None, None);
// drop(self.context.back_buffer[0].take().unwrap());
// ManuallyDrop::drop(&mut self.context.swap_chain);
// self.context.swap_chain = create_swap_chain_default(
// &self.devices.dxgi_factory,
// &self.devices.device,
// self.hwnd,
// transparent,
// )?;
// self.context.back_buffer = [Some(set_render_target_view(
// &self.context.swap_chain,
// &self.devices.device,
// &self.devices.device_context,
// )?)];
// self.context.viewport = set_viewport(
// &self.devices.device_context,
// self.context.viewport[0].Width,
// self.context.viewport[0].Height,
// );
// set_rasterizer_state(&self.devices.device, &self.devices.device_context)?;
// }
// Ok(())
// }
fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> { fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> {
if shadows.is_empty() { if shadows.is_empty() {
return Ok(()); return Ok(());
@ -480,7 +391,7 @@ impl DirectXRenderer {
} }
impl DirectXContext { impl DirectXContext {
pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> { pub fn new(devices: &DirectXDevices, hwnd: HWND) -> Result<Self> {
let (width, height) = unsafe { let (width, height) = unsafe {
let mut rect = std::mem::zeroed(); let mut rect = std::mem::zeroed();
GetWindowRect(hwnd, &mut rect)?; GetWindowRect(hwnd, &mut rect)?;
@ -494,7 +405,6 @@ impl DirectXContext {
let swap_chain = create_swap_chain( let swap_chain = create_swap_chain(
&devices.dxgi_factory, &devices.dxgi_factory,
&devices.device, &devices.device,
transparent,
width as u32, width as u32,
height as u32, height as u32,
)?; )?;
@ -525,7 +435,7 @@ impl DirectXContext {
msaa_view, msaa_view,
viewport, viewport,
// #[cfg(not(feature = "enable-renderdoc"))] // #[cfg(not(feature = "enable-renderdoc"))]
direct_composition, _direct_composition: direct_composition,
}) })
} }
} }
@ -1068,17 +978,9 @@ fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
fn create_swap_chain( fn create_swap_chain(
dxgi_factory: &IDXGIFactory6, dxgi_factory: &IDXGIFactory6,
device: &ID3D11Device, device: &ID3D11Device,
transparent: bool,
width: u32, width: u32,
height: u32, height: u32,
) -> Result<ManuallyDrop<IDXGISwapChain1>> { ) -> Result<ManuallyDrop<IDXGISwapChain1>> {
println!("Creating swap chain for DirectComposition: {}", transparent);
let transparent = true;
let alpha_mode = if transparent {
DXGI_ALPHA_MODE_PREMULTIPLIED
} else {
DXGI_ALPHA_MODE_IGNORE
};
let desc = DXGI_SWAP_CHAIN_DESC1 { let desc = DXGI_SWAP_CHAIN_DESC1 {
Width: width, Width: width,
Height: height, Height: height,
@ -1093,7 +995,7 @@ fn create_swap_chain(
// Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling. // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling.
Scaling: DXGI_SCALING_STRETCH, Scaling: DXGI_SCALING_STRETCH,
SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
AlphaMode: alpha_mode, AlphaMode: DXGI_ALPHA_MODE_PREMULTIPLIED,
Flags: 0, Flags: 0,
}; };
Ok(ManuallyDrop::new(unsafe { Ok(ManuallyDrop::new(unsafe {
@ -1149,24 +1051,6 @@ fn create_render_target_and_its_view(
)) ))
} }
#[inline]
fn set_render_target_view(
swap_chain: &IDXGISwapChain1,
device: &ID3D11Device,
device_context: &ID3D11DeviceContext,
) -> Result<ID3D11RenderTargetView> {
// In dx11, ID3D11RenderTargetView is supposed to always point to the new back buffer.
// https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after
let back_buffer = unsafe {
let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?;
let mut buffer: Option<ID3D11RenderTargetView> = None;
device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?;
buffer.unwrap()
};
unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) };
Ok(back_buffer)
}
#[inline] #[inline]
fn create_msaa_target_and_its_view( fn create_msaa_target_and_its_view(
device: &ID3D11Device, device: &ID3D11Device,

View file

@ -80,7 +80,6 @@ pub(crate) struct WindowsWindowStatePtr {
impl WindowsWindowState { impl WindowsWindowState {
fn new( fn new(
hwnd: HWND, hwnd: HWND,
transparent: bool,
cs: &CREATESTRUCTW, cs: &CREATESTRUCTW,
current_cursor: Option<HCURSOR>, current_cursor: Option<HCURSOR>,
display: WindowsDisplay, display: WindowsDisplay,
@ -104,7 +103,7 @@ impl WindowsWindowState {
let border_offset = WindowBorderOffset::default(); let border_offset = WindowBorderOffset::default();
let restore_from_minimized = None; let restore_from_minimized = None;
// let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?; // let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
let renderer = DirectXRenderer::new(gpu_context, hwnd, transparent)?; let renderer = DirectXRenderer::new(gpu_context, hwnd)?;
let callbacks = Callbacks::default(); let callbacks = Callbacks::default();
let input_handler = None; let input_handler = None;
let pending_surrogate = None; let pending_surrogate = None;
@ -207,7 +206,6 @@ impl WindowsWindowStatePtr {
fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> { fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
let state = RefCell::new(WindowsWindowState::new( let state = RefCell::new(WindowsWindowState::new(
hwnd, hwnd,
context.transparent,
cs, cs,
context.current_cursor, context.current_cursor,
context.display, context.display,
@ -335,7 +333,6 @@ struct WindowCreateContext<'a> {
handle: AnyWindowHandle, handle: AnyWindowHandle,
hide_title_bar: bool, hide_title_bar: bool,
display: WindowsDisplay, display: WindowsDisplay,
transparent: bool,
is_movable: bool, is_movable: bool,
min_size: Option<Size<Pixels>>, min_size: Option<Size<Pixels>>,
executor: ForegroundExecutor, executor: ForegroundExecutor,
@ -381,11 +378,13 @@ impl WindowsWindow {
.unwrap_or(""), .unwrap_or(""),
); );
let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp { let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp {
(WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0)) (
WS_EX_TOOLWINDOW | WS_EX_NOREDIRECTIONBITMAP,
WINDOW_STYLE(0x0),
)
} else { } else {
( (
WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP, WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP,
// WS_EX_APPWINDOW | WS_EX_LAYERED,
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
) )
}; };
@ -403,7 +402,6 @@ impl WindowsWindow {
handle, handle,
hide_title_bar, hide_title_bar,
display, display,
transparent: false,
is_movable: params.is_movable, is_movable: params.is_movable,
min_size: params.window_min_size, min_size: params.window_min_size,
executor, executor,
@ -455,14 +453,6 @@ impl WindowsWindow {
state: WindowOpenState::Windowed, 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)) Ok(Self(state_ptr))
} }
@ -707,26 +697,21 @@ impl PlatformWindow for WindowsWindow {
} }
fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
let mut window_state = self.0.state.borrow_mut(); let hwnd = self.0.hwnd;
window_state
.renderer
.update_transparency(background_appearance)
.context("Updating window transparency")
.log_err();
match background_appearance { match background_appearance {
WindowBackgroundAppearance::Opaque => { WindowBackgroundAppearance::Opaque => {
// ACCENT_DISABLED // ACCENT_DISABLED
set_window_composition_attribute(window_state.hwnd, None, 0); set_window_composition_attribute(hwnd, None, 0);
} }
WindowBackgroundAppearance::Transparent => { WindowBackgroundAppearance::Transparent => {
// Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background
set_window_composition_attribute(window_state.hwnd, None, 2); set_window_composition_attribute(hwnd, None, 2);
} }
WindowBackgroundAppearance::Blurred => { WindowBackgroundAppearance::Blurred => {
// Enable acrylic blur // Enable acrylic blur
// ACCENT_ENABLE_ACRYLICBLURBEHIND // ACCENT_ENABLE_ACRYLICBLURBEHIND
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); set_window_composition_attribute(hwnd, Some((0, 0, 0, 0)), 4);
} }
} }
} }