add transparency

Junkui Zhang created

Change summary

Cargo.toml                                           |   1 
crates/gpui/src/platform/windows/directx_renderer.rs | 320 +++++++------
crates/gpui/src/platform/windows/window.rs           |   5 
3 files changed, 169 insertions(+), 157 deletions(-)

Detailed changes

Cargo.toml 🔗

@@ -677,6 +677,7 @@ features = [
     "Win32_Graphics_Direct3D",
     "Win32_Graphics_Direct3D11",
     "Win32_Graphics_Direct3D_Fxc",
+    "Win32_Graphics_DirectComposition",
     "Win32_Graphics_DirectWrite",
     "Win32_Graphics_Dwm",
     "Win32_Graphics_Dxgi",

crates/gpui/src/platform/windows/directx_renderer.rs 🔗

@@ -3,7 +3,8 @@ use std::{mem::ManuallyDrop, sync::Arc};
 use ::util::ResultExt;
 use anyhow::{Context, Result};
 // #[cfg(not(feature = "enable-renderdoc"))]
-// use windows::Win32::Graphics::DirectComposition::*;
+use windows::Win32::Graphics::DirectComposition::*;
+use windows::Win32::UI::WindowsAndMessaging::GetWindowRect;
 use windows::{
     Win32::{
         Foundation::{HMODULE, HWND},
@@ -26,7 +27,6 @@ pub(crate) struct DirectXRenderer {
     context: DirectXContext,
     globals: DirectXGlobalElements,
     pipelines: DirectXRenderPipelines,
-    hwnd: HWND,
     transparent: bool,
 }
 
@@ -46,7 +46,7 @@ struct DirectXContext {
     msaa_view: ID3D11RenderTargetView,
     viewport: [D3D11_VIEWPORT; 1],
     // #[cfg(not(feature = "enable-renderdoc"))]
-    // direct_composition: DirectComposition,
+    direct_composition: DirectComposition,
 }
 
 struct DirectXRenderPipelines {
@@ -73,11 +73,11 @@ struct DrawInstancedIndirectArgs {
 }
 
 // #[cfg(not(feature = "enable-renderdoc"))]
-// struct DirectComposition {
-//     comp_device: IDCompositionDevice,
-//     comp_target: IDCompositionTarget,
-//     comp_visual: IDCompositionVisual,
-// }
+struct DirectComposition {
+    comp_device: IDCompositionDevice,
+    comp_target: IDCompositionTarget,
+    comp_visual: IDCompositionVisual,
+}
 
 impl DirectXDevices {
     pub(crate) fn new() -> Result<Self> {
@@ -115,7 +115,6 @@ impl DirectXRenderer {
             context,
             globals,
             pipelines,
-            hwnd,
             transparent,
         })
     }
@@ -215,11 +214,6 @@ impl DirectXRenderer {
                 )
                 .unwrap();
         }
-        // let backbuffer = set_render_target_view(
-        //     &self.context.swap_chain,
-        //     &self.devices.device,
-        //     &self.devices.device_context,
-        // )?;
         let (render_target, render_target_view) =
             create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device)
                 .unwrap();
@@ -248,31 +242,6 @@ impl DirectXRenderer {
     }
 
     // #[cfg(not(feature = "enable-renderdoc"))]
-    // pub(crate) fn update_transparency(
-    //     &mut self,
-    //     background_appearance: WindowBackgroundAppearance,
-    // ) -> Result<()> {
-    //     // We only support setting `Transparent` and `Opaque` for now.
-    //     match background_appearance {
-    //         WindowBackgroundAppearance::Opaque => {
-    //             if self.transparent {
-    //                 return Err(anyhow::anyhow!(
-    //                     "Set opaque backgroud from transparent background, a restart is required. Or, you can open a new window."
-    //                 ));
-    //             }
-    //         }
-    //         WindowBackgroundAppearance::Transparent | WindowBackgroundAppearance::Blurred => {
-    //             if !self.transparent {
-    //                 return Err(anyhow::anyhow!(
-    //                     "Set transparent backgroud from opaque background, a restart is required. Or, you can open a new window."
-    //                 ));
-    //             }
-    //         }
-    //     }
-    //     Ok(())
-    // }
-
-    // #[cfg(feature = "enable-renderdoc")]
     pub(crate) fn update_transparency(
         &mut self,
         background_appearance: WindowBackgroundAppearance,
@@ -281,33 +250,84 @@ impl DirectXRenderer {
         if self.transparent == transparent {
             return Ok(());
         }
-        self.transparent = transparent;
-        // unsafe {
-        //     // recreate the swapchain
+        // self.transparent = transparent;
+        // let (width, height) = unsafe {
         //     self.devices.device_context.OMSetRenderTargets(None, None);
-        //     drop(self.context.back_buffer[0].take().unwrap());
+        //     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);
-        //     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)?;
+        //     (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<()> {
         if shadows.is_empty() {
             return Ok(());
@@ -461,24 +481,35 @@ impl DirectXRenderer {
 
 impl DirectXContext {
     pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> {
+        let (width, height) = unsafe {
+            let mut rect = std::mem::zeroed();
+            GetWindowRect(hwnd, &mut rect)?;
+            (rect.right - rect.left, rect.bottom - rect.top)
+        };
+        assert!(
+            width > 0 && height > 0,
+            "Window size must be greater than zero"
+        );
         // #[cfg(not(feature = "enable-renderdoc"))]
-        // let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, transparent)?;
+        let swap_chain = create_swap_chain(
+            &devices.dxgi_factory,
+            &devices.device,
+            transparent,
+            width as u32,
+            height as u32,
+        )?;
         // #[cfg(feature = "enable-renderdoc")]
-        let swap_chain =
-            create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?;
+        // let swap_chain =
+        //     create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?;
         // #[cfg(not(feature = "enable-renderdoc"))]
-        // let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?;
+        let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?;
         // #[cfg(not(feature = "enable-renderdoc"))]
-        // direct_composition.set_swap_chain(&swap_chain)?;
+        direct_composition.set_swap_chain(&swap_chain)?;
         let (render_target, render_target_view) =
             create_render_target_and_its_view(&swap_chain, &devices.device)?;
-        // let back_buffer = [Some(set_render_target_view(
-        //     &swap_chain,
-        //     &devices.device,
-        //     &devices.device_context,
-        // )?)];
-        let (msaa_target, msaa_view) = create_msaa_target_and_its_view(&devices.device, 1, 1)?;
-        let viewport = set_viewport(&devices.device_context, 1.0, 1.0);
+        let (msaa_target, msaa_view) =
+            create_msaa_target_and_its_view(&devices.device, width as u32, height as u32)?;
+        let viewport = set_viewport(&devices.device_context, width as f32, height as f32);
         unsafe {
             devices
                 .device_context
@@ -494,7 +525,7 @@ impl DirectXContext {
             msaa_view,
             viewport,
             // #[cfg(not(feature = "enable-renderdoc"))]
-            // direct_composition,
+            direct_composition,
         })
     }
 }
@@ -545,28 +576,28 @@ impl DirectXRenderPipelines {
 }
 
 // #[cfg(not(feature = "enable-renderdoc"))]
-// impl DirectComposition {
-//     pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result<Self> {
-//         let comp_device = get_comp_device(&dxgi_device)?;
-//         let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?;
-//         let comp_visual = unsafe { comp_device.CreateVisual() }?;
-
-//         Ok(Self {
-//             comp_device,
-//             comp_target,
-//             comp_visual,
-//         })
-//     }
-
-//     pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> {
-//         unsafe {
-//             self.comp_visual.SetContent(swap_chain)?;
-//             self.comp_target.SetRoot(&self.comp_visual)?;
-//             self.comp_device.Commit()?;
-//         }
-//         Ok(())
-//     }
-// }
+impl DirectComposition {
+    pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result<Self> {
+        let comp_device = get_comp_device(&dxgi_device)?;
+        let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?;
+        let comp_visual = unsafe { comp_device.CreateVisual() }?;
+
+        Ok(Self {
+            comp_device,
+            comp_target,
+            comp_visual,
+        })
+    }
+
+    pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> {
+        unsafe {
+            self.comp_visual.SetContent(swap_chain)?;
+            self.comp_target.SetRoot(&self.comp_visual)?;
+            self.comp_device.Commit()?;
+        }
+        Ok(())
+    }
+}
 
 impl DirectXGlobalElements {
     pub fn new(device: &ID3D11Device) -> Result<Self> {
@@ -1030,39 +1061,45 @@ fn get_device(
 }
 
 // #[cfg(not(feature = "enable-renderdoc"))]
-// fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
-//     Ok(unsafe { DCompositionCreateDevice(dxgi_device)? })
-// }
-
-// fn create_swap_chain(
-//     dxgi_factory: &IDXGIFactory6,
-//     device: &ID3D11Device,
-//     transparent: bool,
-// ) -> Result<IDXGISwapChain1> {
-//     let alpha_mode = if transparent {
-//         DXGI_ALPHA_MODE_PREMULTIPLIED
-//     } else {
-//         DXGI_ALPHA_MODE_IGNORE
-//     };
-//     let desc = DXGI_SWAP_CHAIN_DESC1 {
-//         Width: 1,
-//         Height: 1,
-//         Format: DXGI_FORMAT_B8G8R8A8_UNORM,
-//         Stereo: false.into(),
-//         SampleDesc: DXGI_SAMPLE_DESC {
-//             Count: 1,
-//             Quality: 0,
-//         },
-//         BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
-//         BufferCount: BUFFER_COUNT as u32,
-//         // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling.
-//         Scaling: DXGI_SCALING_STRETCH,
-//         SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
-//         AlphaMode: alpha_mode,
-//         Flags: 0,
-//     };
-//     Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? })
-// }
+fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
+    Ok(unsafe { DCompositionCreateDevice(dxgi_device)? })
+}
+
+fn create_swap_chain(
+    dxgi_factory: &IDXGIFactory6,
+    device: &ID3D11Device,
+    transparent: bool,
+    width: u32,
+    height: u32,
+) -> 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 {
+        Width: width,
+        Height: height,
+        Format: RENDER_TARGET_FORMAT,
+        Stereo: false.into(),
+        SampleDesc: DXGI_SAMPLE_DESC {
+            Count: 1,
+            Quality: 0,
+        },
+        BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
+        BufferCount: BUFFER_COUNT as u32,
+        // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling.
+        Scaling: DXGI_SCALING_STRETCH,
+        SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
+        AlphaMode: alpha_mode,
+        Flags: 0,
+    };
+    Ok(ManuallyDrop::new(unsafe {
+        dxgi_factory.CreateSwapChainForComposition(device, &desc, None)?
+    }))
+}
 
 // #[cfg(feature = "enable-renderdoc")]
 fn create_swap_chain_default(
@@ -1289,33 +1326,6 @@ fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: usize) -> Res
     Ok(buffer.unwrap())
 }
 
-#[inline]
-fn pre_draw(
-    device_context: &ID3D11DeviceContext,
-    global_params_buffer: &[Option<ID3D11Buffer>; 1],
-    view_port: &[D3D11_VIEWPORT; 1],
-    render_target_view: &[Option<ID3D11RenderTargetView>; 1],
-    clear_color: [f32; 4],
-    blend_state: &ID3D11BlendState,
-) -> Result<()> {
-    let global_params = global_params_buffer[0].as_ref().unwrap();
-    update_buffer(
-        device_context,
-        global_params,
-        &[GlobalParams {
-            viewport_size: [view_port[0].Width, view_port[0].Height],
-            ..Default::default()
-        }],
-    )?;
-    unsafe {
-        device_context.RSSetViewports(Some(view_port));
-        device_context.OMSetRenderTargets(Some(render_target_view), None);
-        device_context.ClearRenderTargetView(render_target_view[0].as_ref().unwrap(), &clear_color);
-        device_context.OMSetBlendState(blend_state, None, 0xFFFFFFFF);
-    }
-    Ok(())
-}
-
 #[inline]
 fn update_buffer<T>(
     device_context: &ID3D11DeviceContext,

crates/gpui/src/platform/windows/window.rs 🔗

@@ -384,7 +384,8 @@ impl WindowsWindow {
             (WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0))
         } else {
             (
-                WS_EX_APPWINDOW | WS_EX_LAYERED,
+                WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP,
+                // WS_EX_APPWINDOW | WS_EX_LAYERED,
                 WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
             )
         };
@@ -461,7 +462,7 @@ impl WindowsWindow {
         // 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)? };
+        // unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? };
 
         Ok(Self(state_ptr))
     }