Skip to content
This repository has been archived by the owner on Jul 27, 2023. It is now read-only.

Commit

Permalink
Use optional functions for flip mode
Browse files Browse the repository at this point in the history
Some of the functions needed for flip mode are unavailable in Windows
7, so load them optionally.
  • Loading branch information
raphlinus committed Apr 16, 2018
1 parent a7210b2 commit c851d8c
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 77 deletions.
7 changes: 6 additions & 1 deletion xi-win-shell/src/dcomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use direct2d::error::D2D1Error;
use direct2d::math::Matrix3x2F;
use direct2d::render_target::RenderTargetBacking;

use util::OPTIONAL_FUNCTIONS;

unsafe fn wrap<T, U, F>(hr: HRESULT, ptr: *mut T, f: F) -> Result<U, HRESULT>
where F: Fn(ComPtr<T>) -> U, T: Interface
{
Expand Down Expand Up @@ -96,10 +98,13 @@ impl D3D11Device {
}

impl D2D1Device {
/// Create a wrapped DCompositionDevice object. Note: returns Err(0) on systems
/// not supporting DirectComposition, available 8.1 and above.
pub fn create_composition_device(&mut self) -> Result<DCompositionDevice, HRESULT> {
unsafe {
let create = OPTIONAL_FUNCTIONS.DCompositionCreateDevice2.ok_or(0)?;
let mut dcomp_device: *mut IDCompositionDevice = null_mut();
let hr = DCompositionCreateDevice2(self.0.as_raw() as *mut IUnknown,
let hr = create(self.0.as_raw() as *mut IUnknown,
&IDCompositionDevice::uuidof(),
&mut dcomp_device as *mut _ as *mut _);
wrap(hr, dcomp_device, DCompositionDevice)
Expand Down
33 changes: 32 additions & 1 deletion xi-win-shell/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ use std::os::windows::ffi::OsStrExt;
use std::slice;
use std::mem;

use winapi::ctypes::c_void;
use winapi::shared::guiddef::REFIID;
use winapi::shared::minwindef::*;
use winapi::shared::ntdef::*;
use winapi::shared::windef::*;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::libloaderapi::*;
use winapi::um::shellscalingapi::*;
use winapi::um::unknwnbase::IUnknown;

use direct2d::render_target::DrawTextOption;

Expand All @@ -39,6 +42,8 @@ pub enum Error {
Hr(HRESULT),
// Maybe include the full error from the direct2d crate.
D2Error,
/// A function is available on newer version of windows.
OldWindows,
}

pub fn as_result(hr: HRESULT) -> Result<(), Error> {
Expand Down Expand Up @@ -97,12 +102,24 @@ type GetDpiForSystem = unsafe extern "system" fn() -> UINT;
type GetDpiForMonitor = unsafe extern "system" fn(HMONITOR, MONITOR_DPI_TYPE, *mut UINT, *mut UINT);
// from user32.dll
type SetProcessDpiAwareness = unsafe extern "system" fn(PROCESS_DPI_AWARENESS) -> HRESULT;
type DCompositionCreateDevice2 = unsafe extern "system" fn(
renderingDevice: *const IUnknown,
iid: REFIID,
dcompositionDevice: *mut *mut c_void,
) -> HRESULT;
type CreateDXGIFactory2 = unsafe extern "system" fn(
Flags: UINT,
riid: REFIID,
ppFactory: *mut *mut c_void,
) -> HRESULT;

#[allow(non_snake_case)] // For member fields
pub struct OptionalFunctions {
pub GetDpiForSystem: Option<GetDpiForSystem>,
pub GetDpiForMonitor: Option<GetDpiForMonitor>,
pub SetProcessDpiAwareness: Option<SetProcessDpiAwareness>,
pub DCompositionCreateDevice2: Option<DCompositionCreateDevice2>,
pub CreateDXGIFactory2: Option<CreateDXGIFactory2>,
}

#[allow(non_snake_case)] // For local variables
Expand Down Expand Up @@ -135,7 +152,7 @@ fn load_optional_functions() -> OptionalFunctions {
fn load_library(name: &str) -> HMODULE {
let encoded_name = name.to_wide();

// If we allready have loaded the library (somewhere else in the process) we don't need to
// If we already have loaded the library (somewhere else in the process) we don't need to
// call LoadLibrary again
let library = unsafe { GetModuleHandleW(encoded_name.as_ptr()) };
if !library.is_null() {
Expand All @@ -148,10 +165,14 @@ fn load_optional_functions() -> OptionalFunctions {

let shcore = load_library("shcore.dll");
let user32 = load_library("user32.dll");
let dcomp = load_library("dcomp.dll");
let dxgi = load_library("dxgi.dll");

let mut GetDpiForSystem = None;
let mut GetDpiForMonitor = None;
let mut SetProcessDpiAwareness = None;
let mut DCompositionCreateDevice2 = None;
let mut CreateDXGIFactory2 = None;

if shcore.is_null() {
println!("No shcore.dll");
Expand All @@ -166,10 +187,20 @@ fn load_optional_functions() -> OptionalFunctions {
load_function!(user32, GetDpiForSystem, "10");
}

if !dcomp.is_null() {
load_function!(dcomp, DCompositionCreateDevice2, "8.1");
}

if !dxgi.is_null() {
load_function!(dxgi, CreateDXGIFactory2, "8.1");
}

OptionalFunctions {
GetDpiForSystem,
GetDpiForMonitor,
SetProcessDpiAwareness,
DCompositionCreateDevice2,
CreateDXGIFactory2,
}
}

Expand Down
185 changes: 110 additions & 75 deletions xi-win-shell/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use winapi::ctypes::{c_int, c_void};
use winapi::shared::basetsd::*;
use winapi::shared::dxgi::*;
use winapi::shared::dxgi1_2::*;
use winapi::shared::dxgi1_3::*;
use winapi::shared::dxgitype::*;
use winapi::shared::dxgiformat::*;
use winapi::shared::minwindef::*;
Expand Down Expand Up @@ -221,10 +220,17 @@ struct MyWndProc {
struct WndState {
swap_chain: *mut IDXGISwapChain1,
render_target: Option<RenderTarget>,
dcomp_state: Option<DCompState>,
dpi: f32,
}

/// State for DirectComposition. This is optional because it is only supported
/// on 8.1 and up.
struct DCompState {
dcomp_device: DCompositionDevice,
dcomp_target: DCompositionTarget,
swapchain_visual: DCompositionVisual,
dpi: f32,
// True if in a drag-resizing gesture (at which point the swapchain is disabled)
sizing: bool,
}

Expand Down Expand Up @@ -301,57 +307,76 @@ impl WndProc for MyWndProc {
self.render();
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
(*s.swap_chain).Present(1, 0);
let _ = s.dcomp_device.commit();
if let Some(ref mut ds) = s.dcomp_state {
if !ds.sizing {
(*s.swap_chain).Present(1, 0);
let _ = ds.dcomp_device.commit();
}
}
ValidateRect(hwnd, null_mut());
Some(0)
},
WM_ENTERSIZEMOVE => unsafe {
let rt = paint::create_render_target(&self.d2d_factory, hwnd);
self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
self.handler.rebuild_resources();
self.render();
if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
let rt = paint::create_render_target(&self.d2d_factory, hwnd);
self.state.borrow_mut().as_mut().unwrap().render_target = rt.ok();
self.handler.rebuild_resources();
self.render();

let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
let _ = s.dcomp_target.clear_root();
let _ = s.dcomp_device.commit();
s.sizing = true;
let mut state = self.state.borrow_mut();
let s = state.as_mut().unwrap();
if let Some(ref mut ds) = s.dcomp_state {
let _ = ds.dcomp_target.clear_root();
let _ = ds.dcomp_device.commit();
ds.sizing = true;
}
}
None
}
WM_EXITSIZEMOVE => unsafe {
let mut rect: RECT = mem::uninitialized();
GetClientRect(hwnd, &mut rect);
let width = (rect.right - rect.left) as u32;
let height = (rect.bottom - rect.top) as u32;
let res = (*self.state.borrow_mut().as_mut().unwrap().swap_chain)
.ResizeBuffers(2, width, height, DXGI_FORMAT_UNKNOWN, 0);
if SUCCEEDED(res) {
self.handler.rebuild_resources();
self.rebuild_render_target();
self.render();
if self.state.borrow().as_ref().unwrap().dcomp_state.is_some() {
let mut rect: RECT = mem::uninitialized();
GetClientRect(hwnd, &mut rect);
let width = (rect.right - rect.left) as u32;
let height = (rect.bottom - rect.top) as u32;
let res = (*self.state.borrow_mut().as_mut().unwrap().swap_chain)
.ResizeBuffers(2, width, height, DXGI_FORMAT_UNKNOWN, 0);
if SUCCEEDED(res) {
self.handler.rebuild_resources();
self.rebuild_render_target();
self.render();
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
(*s.swap_chain).Present(0, 0);
} else {
println!("ResizeBuffers failed: 0x{:x}", res);
}

// Flush to present flicker artifact (old swapchain composited)
// It might actually be better to create a new swapchain here.
DwmFlush();

let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
(*s.swap_chain).Present(0, 0);
} else {
println!("ResizeBuffers failed: 0x{:x}", res);
if let Some(ref mut ds) = s.dcomp_state {
let _ = ds.dcomp_target.set_root(&mut ds.swapchain_visual);
let _ = ds.dcomp_device.commit();
ds.sizing = false;
}
}

// Flush to present flicker artifact (old swapchain composited)
// It might actually be better to create a new swapchain here.
DwmFlush();

let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
let _ = s.dcomp_target.set_root(&mut s.swapchain_visual);
let _ = s.dcomp_device.commit();
s.sizing = false;
None
}
WM_SIZE => unsafe {
let width = LOWORD(lparam as u32) as u32;
let height = HIWORD(lparam as u32) as u32;
if self.state.borrow_mut().as_ref().unwrap().sizing {
let use_hwnd = if let Some(ref dcomp_state) =
self.state.borrow().as_ref().unwrap().dcomp_state
{
dcomp_state.sizing
} else {
true
};
if use_hwnd {
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
if let Some(ref mut rt) = s.render_target {
Expand All @@ -372,7 +397,9 @@ impl WndProc for MyWndProc {
let mut state = self.state.borrow_mut();
let mut s = state.as_mut().unwrap();
(*s.swap_chain).Present(0, 0);
let _ = s.dcomp_device.commit();
if let Some(ref mut dcomp_state) = s.dcomp_state {
let _ = dcomp_state.dcomp_device.commit();
}
ValidateRect(hwnd, null_mut());
} else {
println!("ResizeBuffers failed: 0x{:x}", res);
Expand Down Expand Up @@ -580,50 +607,58 @@ impl WindowBuilder {
return Err(Error::Null);
}

let mut d3d11_device = D3D11Device::new_simple()?;
let mut d2d1_device = d3d11_device.create_d2d1_device()?;
let mut dcomp_device = d2d1_device.create_composition_device()?;
let mut dcomp_target = dcomp_device.create_target_for_hwnd(hwnd, true)?;

let mut factory: *mut IDXGIFactory2 = null_mut();
as_result(CreateDXGIFactory2(0, &IID_IDXGIFactory2,
&mut factory as *mut *mut IDXGIFactory2 as *mut *mut c_void))?;
println!("dxgi factory pointer = {:?}", factory);
let adapter = choose_adapter(factory);
println!("adapter = {:?}", adapter);
let mut swap_chain: *mut IDXGISwapChain1 = null_mut();
let (swap_effect, bufs) = match self.present_strategy {
PresentStrategy::Sequential => (DXGI_SWAP_EFFECT_SEQUENTIAL, 1),
PresentStrategy::Flip | PresentStrategy::FlipRedirect =>
(DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, 2),
};
let desc = DXGI_SWAP_CHAIN_DESC1 {
Width: 1024,
Height: 768,
Format: DXGI_FORMAT_B8G8R8A8_UNORM,
Stereo: FALSE,
SampleDesc: DXGI_SAMPLE_DESC { Count: 1, Quality: 0},
BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: bufs,
Scaling: DXGI_SCALING_STRETCH,
SwapEffect: swap_effect,
AlphaMode: DXGI_ALPHA_MODE_IGNORE,
Flags: 0,
let dcomp_state = if let Some(create_dxgi_factory2) = OPTIONAL_FUNCTIONS.CreateDXGIFactory2 {
let mut d3d11_device = D3D11Device::new_simple()?;
let mut d2d1_device = d3d11_device.create_d2d1_device()?;
let mut dcomp_device = d2d1_device.create_composition_device()?;
let mut dcomp_target = dcomp_device.create_target_for_hwnd(hwnd, true)?;

let mut factory: *mut IDXGIFactory2 = null_mut();
as_result(create_dxgi_factory2(0, &IID_IDXGIFactory2,
&mut factory as *mut *mut IDXGIFactory2 as *mut *mut c_void))?;
println!("dxgi factory pointer = {:?}", factory);
let adapter = choose_adapter(factory);
println!("adapter = {:?}", adapter);
let (swap_effect, bufs) = match self.present_strategy {
PresentStrategy::Sequential => (DXGI_SWAP_EFFECT_SEQUENTIAL, 1),
PresentStrategy::Flip | PresentStrategy::FlipRedirect =>
(DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, 2),
};
let desc = DXGI_SWAP_CHAIN_DESC1 {
Width: 1024,
Height: 768,
Format: DXGI_FORMAT_B8G8R8A8_UNORM,
Stereo: FALSE,
SampleDesc: DXGI_SAMPLE_DESC { Count: 1, Quality: 0},
BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: bufs,
Scaling: DXGI_SCALING_STRETCH,
SwapEffect: swap_effect,
AlphaMode: DXGI_ALPHA_MODE_IGNORE,
Flags: 0,
};
let res = (*factory).CreateSwapChainForComposition(d3d11_device.raw_ptr() as *mut IUnknown,
&desc, null_mut(), &mut swap_chain);
println!("swap chain res = 0x{:x}, pointer = {:?}", res, swap_chain);

let mut swapchain_visual = dcomp_device.create_visual()?;
swapchain_visual.set_content_raw(swap_chain as *mut IUnknown)?;
dcomp_target.set_root(&mut swapchain_visual)?;
Some(DCompState {
dcomp_device, dcomp_target, swapchain_visual,
sizing: false,
})
} else {
None
};
let res = (*factory).CreateSwapChainForComposition(d3d11_device.raw_ptr() as *mut IUnknown,
&desc, null_mut(), &mut swap_chain);
println!("swap chain res = 0x{:x}, pointer = {:?}", res, swap_chain);

let mut swapchain_visual = dcomp_device.create_visual()?;
swapchain_visual.set_content_raw(swap_chain as *mut IUnknown)?;
dcomp_target.set_root(&mut swapchain_visual)?;

win.hwnd.set(hwnd);
let state = WndState {
render_target: None,
swap_chain, dcomp_device, dcomp_target, swapchain_visual,
swap_chain,
dcomp_state,
dpi,
sizing: false,
};
win.wndproc.connect(&handle, state);
mem::drop(win);
Expand Down

0 comments on commit c851d8c

Please sign in to comment.