Skip to content

Commit

Permalink
fix: Use composition to fix window transparency when using D3D (neovi…
Browse files Browse the repository at this point in the history
…de#2529)

* Use composition to support transparency with d3d

* Don't enable the D3D debug layer by default
  • Loading branch information
fredizzimo authored and zbyna committed May 17, 2024
1 parent 60fe195 commit 895a6a9
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tracy-context-switch-tracing = ["tracy-client-sys?/context-switch-tracing"]
tracy-sampling = ["tracy-client-sys?/sampling"]
tracy-code-transfer = ["tracy-client-sys?/code-transfer"]
tracy-callstack-inlines = ["tracy-client-sys?/callstack-inlines"]
d3d_debug = [] # Enable the D3D debug layer

[patch.crates-io]
winit = { path = "../winit" }
Expand Down Expand Up @@ -92,6 +93,7 @@ skia-safe = { version = "0.73.0", features = ["gl", "d3d", "textlayout"] }
windows = { version = "0.56.0", features = [
"Win32_Graphics_Direct3D",
"Win32_Graphics_Direct3D12",
"Win32_Graphics_DirectComposition",
"Win32_Graphics_Dwm",
"Win32_Graphics_Dxgi",
"Win32_Graphics_Dxgi_Common",
Expand Down
80 changes: 57 additions & 23 deletions src/renderer/d3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@ use windows::core::{Interface, Result, PCWSTR};
use windows::Win32::Foundation::{CloseHandle, HANDLE, HWND};
use windows::Win32::Graphics::Direct3D::D3D_FEATURE_LEVEL_11_0;
use windows::Win32::Graphics::Direct3D12::{
D3D12CreateDevice, D3D12GetDebugInterface, ID3D12CommandQueue, ID3D12Debug, ID3D12Device,
ID3D12Fence, ID3D12Resource, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC,
D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, D3D12_RESOURCE_STATE_PRESENT,
D3D12CreateDevice, ID3D12CommandQueue, ID3D12Device, ID3D12Fence, ID3D12Resource,
D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE,
D3D12_FENCE_FLAG_NONE, D3D12_RESOURCE_STATE_PRESENT,
};
#[cfg(feature = "d3d_debug")]
use windows::Win32::Graphics::Direct3D12::{D3D12GetDebugInterface, ID3D12Debug};
use windows::Win32::Graphics::DirectComposition::{
DCompositionCreateDevice2, IDCompositionDevice, IDCompositionTarget, IDCompositionVisual,
};
use windows::Win32::Graphics::Dxgi::Common::{
DXGI_ALPHA_MODE_UNSPECIFIED, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC,
DXGI_ALPHA_MODE_PREMULTIPLIED, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN,
DXGI_SAMPLE_DESC,
};
use windows::Win32::Graphics::Dxgi::{
CreateDXGIFactory2, IDXGIAdapter1, IDXGIFactory4, IDXGISwapChain1, IDXGISwapChain3,
DXGI_ADAPTER_FLAG, DXGI_ADAPTER_FLAG_SOFTWARE, DXGI_CREATE_FACTORY_DEBUG, DXGI_SCALING_NONE,
DXGI_ADAPTER_FLAG, DXGI_ADAPTER_FLAG_SOFTWARE, DXGI_CREATE_FACTORY_DEBUG, DXGI_SCALING_STRETCH,
DXGI_SWAP_CHAIN_DESC1, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT,
DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_USAGE_RENDER_TARGET_OUTPUT,
DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_USAGE_RENDER_TARGET_OUTPUT,
};
use windows::Win32::System::Threading::{CreateEventW, WaitForSingleObjectEx, INFINITE};
use winit::{
Expand Down Expand Up @@ -83,17 +89,20 @@ pub struct D3DSkiaRenderer {
#[cfg(feature = "gpu_profiling")]
pub device: ID3D12Device,
_adapter: IDXGIAdapter1,
_composition_device: IDCompositionDevice,
_target: IDCompositionTarget,
_visual: IDCompositionVisual,
window: Window,
}

impl D3DSkiaRenderer {
pub fn new(window: Window) -> Self {
let mut debug_controller: Option<ID3D12Debug> = None;
#[cfg(feature = "d3d_debug")]
unsafe {
let mut debug_controller: Option<ID3D12Debug> = None;
D3D12GetDebugInterface(&mut debug_controller)
.expect("Failed to create Direct3D debug controller");
}
unsafe {

debug_controller
.expect("Failed to enable debug layer")
.EnableDebugLayer();
Expand All @@ -102,6 +111,7 @@ impl D3DSkiaRenderer {
let dxgi_factory: IDXGIFactory4 = unsafe {
CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG).expect("Failed to create DXGI factory")
};

let adapter = get_hardware_adapter(&dxgi_factory)
.expect("Failed to find any suitable Direct3D 12 adapters");

Expand All @@ -124,10 +134,12 @@ impl D3DSkiaRenderer {
.expect("Failed to create the Direct3D command queue")
};

let size = window.inner_size();

// Describe and create the swap chain.
let swap_chain_desc = DXGI_SWAP_CHAIN_DESC1 {
Width: 0,
Height: 0,
Width: size.width,
Height: size.height,
Format: DXGI_FORMAT_R8G8B8A8_UNORM,
Stereo: false.into(),
SampleDesc: DXGI_SAMPLE_DESC {
Expand All @@ -136,9 +148,9 @@ impl D3DSkiaRenderer {
},
BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: 2,
Scaling: DXGI_SCALING_NONE,
SwapEffect: DXGI_SWAP_EFFECT_FLIP_DISCARD,
AlphaMode: DXGI_ALPHA_MODE_UNSPECIFIED,
Scaling: DXGI_SCALING_STRETCH,
SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
AlphaMode: DXGI_ALPHA_MODE_PREMULTIPLIED,
Flags: DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT.0 as u32,
};

Expand All @@ -147,20 +159,14 @@ impl D3DSkiaRenderer {
.expect("Failed to fetch window handle")
.as_raw()
{
handle.hwnd
HWND(handle.hwnd.get())
} else {
panic!("Not a Win32 window");
};

let swap_chain = unsafe {
dxgi_factory
.CreateSwapChainForHwnd(
&command_queue,
HWND(hwnd.get()),
&swap_chain_desc,
None,
None,
)
.CreateSwapChainForComposition(&command_queue, &swap_chain_desc, None)
.expect("Failed to create the Direct3D swap chain")
};

Expand All @@ -172,6 +178,31 @@ impl D3DSkiaRenderer {
.SetMaximumFrameLatency(1)
.expect("Failed to set maximum frame latency");
}
let composition_device: IDCompositionDevice = unsafe {
DCompositionCreateDevice2(None).expect("Could not create composition device")
};
let target = unsafe {
composition_device
.CreateTargetForHwnd(hwnd, true)
.expect("Could not create composition target")
};
let visual = unsafe {
composition_device
.CreateVisual()
.expect("Could not create composition visual")
};

unsafe {
visual
.SetContent(&swap_chain)
.expect("Failed to set composition content");
target
.SetRoot(&visual)
.expect("Failed to set composition root");
composition_device
.Commit()
.expect("Failed to commit composition");
}

let swap_chain_waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() };
if swap_chain_waitable.is_invalid() {
Expand Down Expand Up @@ -219,6 +250,9 @@ impl D3DSkiaRenderer {
fence_event,
frame_swapped: true,
frame_index,
_composition_device: composition_device,
_target: target,
_visual: visual,
window,
};
ret.setup_surfaces();
Expand Down Expand Up @@ -381,7 +415,7 @@ impl SkiaRenderer for D3DSkiaRenderer {
0,
size.width,
size.height,
self.swap_chain_desc.Format,
DXGI_FORMAT_UNKNOWN,
self.swap_chain_desc.Flags,
)
.expect("Failed to resize buffers");
Expand Down
10 changes: 10 additions & 0 deletions src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ use winit::platform::macos::WindowBuilderExtMacOS;
#[cfg(target_os = "linux")]
use winit::platform::{wayland::WindowBuilderExtWayland, x11::WindowBuilderExtX11};

#[cfg(target_os = "windows")]
use winit::platform::windows::WindowBuilderExtWindows;

#[cfg(target_os = "macos")]
use winit::platform::macos::EventLoopBuilderExtMacOS;

Expand Down Expand Up @@ -161,6 +164,13 @@ pub fn create_window(
.with_transparent(true)
.with_visible(false);

#[cfg(target_os = "windows")]
let winit_window_builder = if !cmd_line_settings.opengl {
WindowBuilderExtWindows::with_no_redirection_bitmap(winit_window_builder, true)
} else {
winit_window_builder
};

let frame_decoration = cmd_line_settings.frame;

#[cfg(target_os = "macos")]
Expand Down

0 comments on commit 895a6a9

Please sign in to comment.