From 4f67edd2c390d4ff7c1e83ea41364bafe7e46b09 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 30 Jan 2018 19:58:39 +0100 Subject: [PATCH 01/73] Initial commit --- .gitignore | 4 ++++ Cargo.toml | 6 ++++++ src/main.rs | 3 +++ 3 files changed, 13 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..143b1ca014 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +/target/ +**/*.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..4c69fbf07e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "directcomposition" +version = "0.1.0" +authors = ["Simon Sapin "] + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000000..6686bd0e33 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!") +} From 7dfa0b45b3f38e13c6f8f830a64c64679cffabc7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 30 Jan 2018 19:59:52 +0100 Subject: [PATCH 02/73] =?UTF-8?q?Copy=20example=20program=20from=20glutin?= =?UTF-8?q?=E2=80=99s=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 ++ src/main.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4c69fbf07e..a55ffad8e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" authors = ["Simon Sapin "] [dependencies] +gl = "0.6.0" +glutin = "0.12" diff --git a/src/main.rs b/src/main.rs index 6686bd0e33..a8ab908d4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,44 @@ +extern crate gl; +extern crate glutin; + +use glutin::GlContext; + fn main() { - println!("Hello, world!") + let mut events_loop = glutin::EventsLoop::new(); + let window = glutin::WindowBuilder::new() + .with_title("Hello, world!") + .with_dimensions(1024, 768); + let context = glutin::ContextBuilder::new() + .with_vsync(true); + let gl_window = glutin::GlWindow::new(window, context, &events_loop).unwrap(); + + unsafe { + gl_window.make_current().unwrap(); + } + + unsafe { + gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _); + gl::ClearColor(0.0, 1.0, 0.0, 1.0); + } + + let mut running = true; + while running { + events_loop.poll_events(|event| { + match event { + glutin::Event::WindowEvent{ event, .. } => match event { + glutin::WindowEvent::Closed => running = false, + glutin::WindowEvent::Resized(w, h) => gl_window.resize(w, h), + _ => () + }, + _ => () + } + }); + + unsafe { + gl::Clear(gl::COLOR_BUFFER_BIT); + } + + gl_window.swap_buffers().unwrap(); + } } + From 5c80249dbb9c067fc4e8d42bd5c845ba21d829b3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 30 Jan 2018 20:00:38 +0100 Subject: [PATCH 03/73] Start to translate "How to initialize DirectComposition" example https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx So far, the `InitializeDirectCompositionDevice` method. --- Cargo.toml | 1 + src/main.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a55ffad8e9..f729ff93a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ authors = ["Simon Sapin "] [dependencies] gl = "0.6.0" glutin = "0.12" +winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} diff --git a/src/main.rs b/src/main.rs index a8ab908d4f..e9b9aeaf10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,27 @@ +#![allow(non_snake_case)] + extern crate gl; extern crate glutin; +extern crate winapi; use glutin::GlContext; +use glutin::os::windows::WindowExt; +use std::ops::Deref; +use std::os::raw::c_void; +use std::ptr; +use winapi::Interface; +use winapi::shared::dxgi::IDXGIDevice; +use winapi::shared::minwindef::TRUE; +use winapi::shared::winerror::HRESULT; +use winapi::shared::winerror::SUCCEEDED; +use winapi::shared::windef::HWND; +use winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT; +use winapi::um::d3d11::D3D11_SDK_VERSION; +use winapi::um::d3d11::D3D11CreateDevice; +use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE; +use winapi::um::dcomp::IDCompositionDevice; +use winapi::um::dcomp::DCompositionCreateDevice; +use winapi::um::unknwnbase::IUnknown; fn main() { let mut events_loop = glutin::EventsLoop::new(); @@ -19,9 +39,12 @@ fn main() { unsafe { gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _); gl::ClearColor(0.0, 1.0, 0.0, 1.0); + + initialize_direct_composition_device(gl_window.window().get_hwnd() as _).unwrap(); } - let mut running = true; +// let mut running = true; + let mut running = false; while running { events_loop.poll_events(|event| { match event { @@ -40,5 +63,72 @@ fn main() { gl_window.swap_buffers().unwrap(); } + println!("Ok") +} + +trait ToResult: Sized { + fn to_result(self) -> Result<(), Self>; +} + +impl ToResult for HRESULT { + fn to_result(self) -> Result<(), Self> { + if SUCCEEDED(self) { + Ok(()) + } else { + Err(self) + } + } +} + +fn as_void(p: *mut *mut T) -> *mut *mut c_void { + p as _ } +unsafe fn query_interface(p: *mut T) -> Result<*mut U, HRESULT> + where T: Deref, U: Interface +{ + let mut ret = ptr::null_mut(); + (*p).QueryInterface(&U::uuidof(), as_void(&mut ret)).to_result()?; + Ok(ret) +} + +/// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx + +unsafe fn initialize_direct_composition_device(m_hwnd: HWND) -> Result<(), HRESULT> { + let mut m_pD3D11Device = ptr::null_mut(); + let mut featureLevelSupported = 0; + + // Create the D3D device object. The D3D11_CREATE_DEVICE_BGRA_SUPPORT + // flag enables rendering on surfaces using Direct2D. + D3D11CreateDevice( + ptr::null_mut(), + D3D_DRIVER_TYPE_HARDWARE, + ptr::null_mut(), + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + ptr::null_mut(), + 0, + D3D11_SDK_VERSION, + &mut m_pD3D11Device, + &mut featureLevelSupported, + ptr::null_mut(), + ).to_result()?; + + // Create the DXGI device used to create bitmap surfaces. + let pDXGIDevice: *mut IDXGIDevice = query_interface(m_pD3D11Device)?; + + // Create the DirectComposition device object. + let mut m_pDCompDevice: *mut IDCompositionDevice = ptr::null_mut(); + DCompositionCreateDevice( + pDXGIDevice, &IDCompositionDevice::uuidof(), as_void(&mut m_pDCompDevice), + ).to_result()?; + + // Create the composition target object based on the + // specified application window. + let mut m_pDCompTarget = ptr::null_mut(); + (*m_pDCompDevice).CreateTargetForHwnd(m_hwnd, TRUE, &mut m_pDCompTarget).to_result()?; + + // FIXME: make/use a type with a destructor, so that this runs even in case of early return + (*pDXGIDevice).Release(); + + Ok(()) +} From fdab306576b37779ee609c5421fb2d26f25ebfb3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 30 Jan 2018 20:06:03 +0100 Subject: [PATCH 04/73] Return these pointers we so arduously obtained --- src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index e9b9aeaf10..57ac066a30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,8 +18,10 @@ use winapi::shared::windef::HWND; use winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT; use winapi::um::d3d11::D3D11_SDK_VERSION; use winapi::um::d3d11::D3D11CreateDevice; +use winapi::um::d3d11::ID3D11Device; use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE; use winapi::um::dcomp::IDCompositionDevice; +use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::DCompositionCreateDevice; use winapi::um::unknwnbase::IUnknown; @@ -94,7 +96,9 @@ unsafe fn query_interface(p: *mut T) -> Result<*mut U, HRESULT> /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx -unsafe fn initialize_direct_composition_device(m_hwnd: HWND) -> Result<(), HRESULT> { +unsafe fn initialize_direct_composition_device(m_hwnd: HWND) + -> Result<(*mut ID3D11Device, *mut IDCompositionDevice, *mut IDCompositionTarget), HRESULT> +{ let mut m_pD3D11Device = ptr::null_mut(); let mut featureLevelSupported = 0; @@ -130,5 +134,5 @@ unsafe fn initialize_direct_composition_device(m_hwnd: HWND) -> Result<(), HRESU // FIXME: make/use a type with a destructor, so that this runs even in case of early return (*pDXGIDevice).Release(); - Ok(()) + Ok((m_pD3D11Device, m_pDCompDevice, m_pDCompTarget)) } From 307b3f0dab64074b31c433a2006ed88e82b436b7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 13 Feb 2018 16:33:19 +0100 Subject: [PATCH 05/73] Add a COM pointer abstraction --- src/com.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 62 +++++++++++----------------------- 2 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 src/com.rs diff --git a/src/com.rs b/src/com.rs new file mode 100644 index 0000000000..b978473f19 --- /dev/null +++ b/src/com.rs @@ -0,0 +1,96 @@ +//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null + +use std::ops::Deref; +use std::ptr::null_mut; +use winapi; +use winapi::Interface; +use winapi::ctypes::c_void; +use winapi::shared::winerror::HRESULT; +use winapi::shared::winerror::SUCCEEDED; +use winapi::um::unknwnbase::IUnknown; + +pub trait ToResult: Sized { + fn to_result(self) -> Result<(), Self>; +} + +impl ToResult for HRESULT { + fn to_result(self) -> Result<(), Self> { + if SUCCEEDED(self) { + Ok(()) + } else { + Err(self) + } + } +} + +/// Nullable pointer to an owned COM object +pub struct Com where T: AsIUnknown { + ptr: *mut T, +} + +impl Com where T: AsIUnknown { + pub fn null() -> Self { + Com { ptr: null_mut() } + } + + pub fn as_ref(&self) -> Option<&T> { + unsafe { + self.ptr.as_ref() + } + } + + pub unsafe fn as_ptr_ptr(&mut self) -> *mut *mut T { + &mut self.ptr + } + + pub unsafe fn as_void_ptr_ptr(&mut self) -> *mut *mut c_void { + self.as_ptr_ptr() as _ + } + + pub fn query_interface(&self) -> Result, HRESULT> where U: AsIUnknown { + let mut obj = Com::::null(); + unsafe { + self.as_iunknown().QueryInterface(&U::uuidof(), obj.as_void_ptr_ptr()).to_result()? + }; + Ok(obj) + } +} + +impl Deref for Com where T: AsIUnknown { + type Target = T; + + fn deref(&self) -> &T { + self.as_ref().expect("dereferencing a null COM pointer") + } +} + +impl Drop for Com where T: AsIUnknown { + fn drop(&mut self) { + unsafe { + if let Some(r) = self.ptr.as_ref() { + r.as_iunknown().Release(); + } + } + } +} + +pub trait AsIUnknown: Interface { + fn as_iunknown(&self) -> &IUnknown; +} + +macro_rules! impl_as_iunknown { + ($( $ty: path, )+) => { + $( + impl AsIUnknown for $ty { + fn as_iunknown(&self) -> &IUnknown { self } + } + )+ + } +} + +impl_as_iunknown! { + winapi::shared::dxgi::IDXGIDevice, + winapi::um::d3d11::ID3D11Device, + winapi::um::dcomp::IDCompositionDevice, + winapi::um::dcomp::IDCompositionTarget, +} diff --git a/src/main.rs b/src/main.rs index 57ac066a30..36f898cd77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,14 @@ extern crate gl; extern crate glutin; extern crate winapi; +use com::{Com, ToResult}; use glutin::GlContext; use glutin::os::windows::WindowExt; -use std::ops::Deref; -use std::os::raw::c_void; use std::ptr; use winapi::Interface; use winapi::shared::dxgi::IDXGIDevice; use winapi::shared::minwindef::TRUE; use winapi::shared::winerror::HRESULT; -use winapi::shared::winerror::SUCCEEDED; use winapi::shared::windef::HWND; use winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT; use winapi::um::d3d11::D3D11_SDK_VERSION; @@ -23,7 +21,8 @@ use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::DCompositionCreateDevice; -use winapi::um::unknwnbase::IUnknown; + +mod com; fn main() { let mut events_loop = glutin::EventsLoop::new(); @@ -68,38 +67,12 @@ fn main() { println!("Ok") } -trait ToResult: Sized { - fn to_result(self) -> Result<(), Self>; -} - -impl ToResult for HRESULT { - fn to_result(self) -> Result<(), Self> { - if SUCCEEDED(self) { - Ok(()) - } else { - Err(self) - } - } -} - -fn as_void(p: *mut *mut T) -> *mut *mut c_void { - p as _ -} - -unsafe fn query_interface(p: *mut T) -> Result<*mut U, HRESULT> - where T: Deref, U: Interface -{ - let mut ret = ptr::null_mut(); - (*p).QueryInterface(&U::uuidof(), as_void(&mut ret)).to_result()?; - Ok(ret) -} - /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx -unsafe fn initialize_direct_composition_device(m_hwnd: HWND) - -> Result<(*mut ID3D11Device, *mut IDCompositionDevice, *mut IDCompositionTarget), HRESULT> +unsafe fn initialize_direct_composition_device(hwnd: HWND) + -> Result<(Com, Com, Com), HRESULT> { - let mut m_pD3D11Device = ptr::null_mut(); + let mut d3d_device = Com::::null(); let mut featureLevelSupported = 0; // Create the D3D device object. The D3D11_CREATE_DEVICE_BGRA_SUPPORT @@ -112,27 +85,30 @@ unsafe fn initialize_direct_composition_device(m_hwnd: HWND) ptr::null_mut(), 0, D3D11_SDK_VERSION, - &mut m_pD3D11Device, + d3d_device.as_ptr_ptr(), &mut featureLevelSupported, ptr::null_mut(), ).to_result()?; // Create the DXGI device used to create bitmap surfaces. - let pDXGIDevice: *mut IDXGIDevice = query_interface(m_pD3D11Device)?; + let pDXGIDevice = d3d_device.query_interface::()?; // Create the DirectComposition device object. - let mut m_pDCompDevice: *mut IDCompositionDevice = ptr::null_mut(); + let mut composition_device = Com::::null(); DCompositionCreateDevice( - pDXGIDevice, &IDCompositionDevice::uuidof(), as_void(&mut m_pDCompDevice), + &*pDXGIDevice, + &IDCompositionDevice::uuidof(), + composition_device.as_void_ptr_ptr(), ).to_result()?; // Create the composition target object based on the // specified application window. - let mut m_pDCompTarget = ptr::null_mut(); - (*m_pDCompDevice).CreateTargetForHwnd(m_hwnd, TRUE, &mut m_pDCompTarget).to_result()?; - - // FIXME: make/use a type with a destructor, so that this runs even in case of early return - (*pDXGIDevice).Release(); + let mut composition_target = Com::::null(); + composition_device.CreateTargetForHwnd( + hwnd, + TRUE, + composition_target.as_ptr_ptr(), + ).to_result()?; - Ok((m_pD3D11Device, m_pDCompDevice, m_pDCompTarget)) + Ok((d3d_device, composition_device, composition_target)) } From 0507f4ca689f7aa8d7f39e649f12c5b08dfa0d6a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 13 Feb 2018 16:37:16 +0100 Subject: [PATCH 06/73] Import fewer single-use things --- src/com.rs | 7 +++---- src/main.rs | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/com.rs b/src/com.rs index b978473f19..299b832f85 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,12 +1,11 @@ //! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null use std::ops::Deref; -use std::ptr::null_mut; +use std::ptr; use winapi; use winapi::Interface; use winapi::ctypes::c_void; use winapi::shared::winerror::HRESULT; -use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; pub trait ToResult: Sized { @@ -15,7 +14,7 @@ pub trait ToResult: Sized { impl ToResult for HRESULT { fn to_result(self) -> Result<(), Self> { - if SUCCEEDED(self) { + if winapi::shared::winerror::SUCCEEDED(self) { Ok(()) } else { Err(self) @@ -30,7 +29,7 @@ pub struct Com where T: AsIUnknown { impl Com where T: AsIUnknown { pub fn null() -> Self { - Com { ptr: null_mut() } + Com { ptr: ptr::null_mut() } } pub fn as_ref(&self) -> Option<&T> { diff --git a/src/main.rs b/src/main.rs index 36f898cd77..98b0e1779e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,18 +9,12 @@ use glutin::GlContext; use glutin::os::windows::WindowExt; use std::ptr; use winapi::Interface; -use winapi::shared::dxgi::IDXGIDevice; use winapi::shared::minwindef::TRUE; use winapi::shared::winerror::HRESULT; use winapi::shared::windef::HWND; -use winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT; -use winapi::um::d3d11::D3D11_SDK_VERSION; -use winapi::um::d3d11::D3D11CreateDevice; use winapi::um::d3d11::ID3D11Device; -use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; -use winapi::um::dcomp::DCompositionCreateDevice; mod com; @@ -75,27 +69,27 @@ unsafe fn initialize_direct_composition_device(hwnd: HWND) let mut d3d_device = Com::::null(); let mut featureLevelSupported = 0; - // Create the D3D device object. The D3D11_CREATE_DEVICE_BGRA_SUPPORT - // flag enables rendering on surfaces using Direct2D. - D3D11CreateDevice( + // Create the D3D device object. + // The D3D11_CREATE_DEVICE_BGRA_SUPPORT flag enables rendering on surfaces using Direct2D. + winapi::um::d3d11::D3D11CreateDevice( ptr::null_mut(), - D3D_DRIVER_TYPE_HARDWARE, + winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, ptr::null_mut(), - D3D11_CREATE_DEVICE_BGRA_SUPPORT, + winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT, ptr::null_mut(), 0, - D3D11_SDK_VERSION, + winapi::um::d3d11::D3D11_SDK_VERSION, d3d_device.as_ptr_ptr(), &mut featureLevelSupported, ptr::null_mut(), ).to_result()?; // Create the DXGI device used to create bitmap surfaces. - let pDXGIDevice = d3d_device.query_interface::()?; + let pDXGIDevice = d3d_device.query_interface::()?; // Create the DirectComposition device object. let mut composition_device = Com::::null(); - DCompositionCreateDevice( + winapi::um::dcomp::DCompositionCreateDevice( &*pDXGIDevice, &IDCompositionDevice::uuidof(), composition_device.as_void_ptr_ptr(), From 58b9ab1928f6a45a8538d207f459241d43eafade Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 13 Feb 2018 16:59:21 +0100 Subject: [PATCH 07/73] *mut *mut _ alreay requires unsafe to break invariants --- src/com.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com.rs b/src/com.rs index 299b832f85..b0f1212b3c 100644 --- a/src/com.rs +++ b/src/com.rs @@ -38,11 +38,11 @@ impl Com where T: AsIUnknown { } } - pub unsafe fn as_ptr_ptr(&mut self) -> *mut *mut T { + pub fn as_ptr_ptr(&mut self) -> *mut *mut T { &mut self.ptr } - pub unsafe fn as_void_ptr_ptr(&mut self) -> *mut *mut c_void { + pub fn as_void_ptr_ptr(&mut self) -> *mut *mut c_void { self.as_ptr_ptr() as _ } @@ -73,6 +73,7 @@ impl Drop for Com where T: AsIUnknown { } } +/// FIXME: https://github.com/retep998/winapi-rs/issues/571 or some other way to express this generically. pub trait AsIUnknown: Interface { fn as_iunknown(&self) -> &IUnknown; } From a91c6a82b5e6d0baf3716d6dfb5dd506d85d16c2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 13 Feb 2018 17:23:06 +0100 Subject: [PATCH 08/73] Return a struct --- src/main.rs | 93 ++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/src/main.rs b/src/main.rs index 98b0e1779e..a553c4ab20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ fn main() { gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _); gl::ClearColor(0.0, 1.0, 0.0, 1.0); - initialize_direct_composition_device(gl_window.window().get_hwnd() as _).unwrap(); + DirectComposition::initialize(gl_window.window().get_hwnd() as _).unwrap(); } // let mut running = true; @@ -63,46 +63,53 @@ fn main() { /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx -unsafe fn initialize_direct_composition_device(hwnd: HWND) - -> Result<(Com, Com, Com), HRESULT> -{ - let mut d3d_device = Com::::null(); - let mut featureLevelSupported = 0; - - // Create the D3D device object. - // The D3D11_CREATE_DEVICE_BGRA_SUPPORT flag enables rendering on surfaces using Direct2D. - winapi::um::d3d11::D3D11CreateDevice( - ptr::null_mut(), - winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, - ptr::null_mut(), - winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT, - ptr::null_mut(), - 0, - winapi::um::d3d11::D3D11_SDK_VERSION, - d3d_device.as_ptr_ptr(), - &mut featureLevelSupported, - ptr::null_mut(), - ).to_result()?; - - // Create the DXGI device used to create bitmap surfaces. - let pDXGIDevice = d3d_device.query_interface::()?; - - // Create the DirectComposition device object. - let mut composition_device = Com::::null(); - winapi::um::dcomp::DCompositionCreateDevice( - &*pDXGIDevice, - &IDCompositionDevice::uuidof(), - composition_device.as_void_ptr_ptr(), - ).to_result()?; - - // Create the composition target object based on the - // specified application window. - let mut composition_target = Com::::null(); - composition_device.CreateTargetForHwnd( - hwnd, - TRUE, - composition_target.as_ptr_ptr(), - ).to_result()?; - - Ok((d3d_device, composition_device, composition_target)) +#[allow(unused)] +struct DirectComposition { + d3d_device: Com, + composition_device: Com, + composition_target: Com, +} + +impl DirectComposition { + unsafe fn initialize(hwnd: HWND) -> Result { + let mut d3d_device = Com::::null(); + let mut featureLevelSupported = 0; + + // Create the D3D device object. + // The D3D11_CREATE_DEVICE_BGRA_SUPPORT flag enables rendering on surfaces using Direct2D. + winapi::um::d3d11::D3D11CreateDevice( + ptr::null_mut(), + winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, + ptr::null_mut(), + winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT, + ptr::null_mut(), + 0, + winapi::um::d3d11::D3D11_SDK_VERSION, + d3d_device.as_ptr_ptr(), + &mut featureLevelSupported, + ptr::null_mut(), + ).to_result()?; + + // Create the DXGI device used to create bitmap surfaces. + let pDXGIDevice = d3d_device.query_interface::()?; + + // Create the DirectComposition device object. + let mut composition_device = Com::::null(); + winapi::um::dcomp::DCompositionCreateDevice( + &*pDXGIDevice, + &IDCompositionDevice::uuidof(), + composition_device.as_void_ptr_ptr(), + ).to_result()?; + + // Create the composition target object based on the + // specified application window. + let mut composition_target = Com::::null(); + composition_device.CreateTargetForHwnd( + hwnd, + TRUE, + composition_target.as_ptr_ptr(), + ).to_result()?; + + Ok(DirectComposition { d3d_device, composition_device, composition_target }) + } } From fc680d6688ca9eb6143a2d29eaad0ccc7b300e36 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 14 Feb 2018 10:14:43 +0100 Subject: [PATCH 09/73] Switch to wio::ComPtr --- Cargo.toml | 1 + src/com.rs | 126 ++++++++++++++++++---------------------------------- src/main.rs | 45 +++++++++---------- 3 files changed, 65 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f729ff93a8..91609ae8d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ authors = ["Simon Sapin "] gl = "0.6.0" glutin = "0.12" winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} +wio = "0.2" diff --git a/src/com.rs b/src/com.rs index b0f1212b3c..dedc533d0d 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,96 +1,54 @@ //! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null -use std::ops::Deref; use std::ptr; -use winapi; use winapi::Interface; use winapi::ctypes::c_void; use winapi::shared::winerror::HRESULT; +use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; - -pub trait ToResult: Sized { - fn to_result(self) -> Result<(), Self>; -} - -impl ToResult for HRESULT { - fn to_result(self) -> Result<(), Self> { - if winapi::shared::winerror::SUCCEEDED(self) { - Ok(()) +use wio::com::ComPtr; + +pub trait OutParam: Sized { + /// For use with APIs that "return" a new COM object through a `*mut *mut c_void` out-parameter. + /// + /// # Safety + /// + /// `T` must be a COM interface that inherits from `IUnknown`. + /// If the closure makes the inner pointer non-null, + /// it must point to a valid COM object that implements `T`. + /// Ownership of that object is taken. + unsafe fn from_void_out_param(f: F) -> Result + where F: FnOnce(*mut *mut c_void) -> HRESULT + { + Self::from_out_param(|ptr| f(ptr as _)) + } + + /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter. + /// + /// # Safety + /// + /// `T` must be a COM interface that inherits from `IUnknown`. + /// If the closure makes the inner pointer non-null, + /// it must point to a valid COM object that implements `T`. + /// Ownership of that object is taken. + unsafe fn from_out_param(f: F) -> Result + where F: FnOnce(*mut *mut T) -> HRESULT; +} + +impl OutParam for ComPtr where T: Interface { + unsafe fn from_out_param(f: F) -> Result + where F: FnOnce(*mut *mut T) -> HRESULT + { + let mut ptr = ptr::null_mut(); + let status = f(&mut ptr); + if SUCCEEDED(status) { + Ok(ComPtr::from_raw(ptr)) } else { - Err(self) - } - } -} - -/// Nullable pointer to an owned COM object -pub struct Com where T: AsIUnknown { - ptr: *mut T, -} - -impl Com where T: AsIUnknown { - pub fn null() -> Self { - Com { ptr: ptr::null_mut() } - } - - pub fn as_ref(&self) -> Option<&T> { - unsafe { - self.ptr.as_ref() - } - } - - pub fn as_ptr_ptr(&mut self) -> *mut *mut T { - &mut self.ptr - } - - pub fn as_void_ptr_ptr(&mut self) -> *mut *mut c_void { - self.as_ptr_ptr() as _ - } - - pub fn query_interface(&self) -> Result, HRESULT> where U: AsIUnknown { - let mut obj = Com::::null(); - unsafe { - self.as_iunknown().QueryInterface(&U::uuidof(), obj.as_void_ptr_ptr()).to_result()? - }; - Ok(obj) - } -} - -impl Deref for Com where T: AsIUnknown { - type Target = T; - - fn deref(&self) -> &T { - self.as_ref().expect("dereferencing a null COM pointer") - } -} - -impl Drop for Com where T: AsIUnknown { - fn drop(&mut self) { - unsafe { - if let Some(r) = self.ptr.as_ref() { - r.as_iunknown().Release(); + if !ptr.is_null() { + let ptr = ptr as *mut IUnknown; + (*ptr).Release(); } + Err(status) } } } - -/// FIXME: https://github.com/retep998/winapi-rs/issues/571 or some other way to express this generically. -pub trait AsIUnknown: Interface { - fn as_iunknown(&self) -> &IUnknown; -} - -macro_rules! impl_as_iunknown { - ($( $ty: path, )+) => { - $( - impl AsIUnknown for $ty { - fn as_iunknown(&self) -> &IUnknown { self } - } - )+ - } -} - -impl_as_iunknown! { - winapi::shared::dxgi::IDXGIDevice, - winapi::um::d3d11::ID3D11Device, - winapi::um::dcomp::IDCompositionDevice, - winapi::um::dcomp::IDCompositionTarget, -} diff --git a/src/main.rs b/src/main.rs index a553c4ab20..a7fb27afca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,9 @@ extern crate gl; extern crate glutin; extern crate winapi; +extern crate wio; -use com::{Com, ToResult}; +use com::OutParam; use glutin::GlContext; use glutin::os::windows::WindowExt; use std::ptr; @@ -15,6 +16,7 @@ use winapi::shared::windef::HWND; use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; +use wio::com::ComPtr; mod com; @@ -65,19 +67,18 @@ fn main() { #[allow(unused)] struct DirectComposition { - d3d_device: Com, - composition_device: Com, - composition_target: Com, + d3d_device: ComPtr, + composition_device: ComPtr, + composition_target: ComPtr, } impl DirectComposition { unsafe fn initialize(hwnd: HWND) -> Result { - let mut d3d_device = Com::::null(); - let mut featureLevelSupported = 0; + let mut feature_level_supported = 0; // Create the D3D device object. // The D3D11_CREATE_DEVICE_BGRA_SUPPORT flag enables rendering on surfaces using Direct2D. - winapi::um::d3d11::D3D11CreateDevice( + let d3d_device = ComPtr::from_out_param(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( ptr::null_mut(), winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, ptr::null_mut(), @@ -85,30 +86,28 @@ impl DirectComposition { ptr::null_mut(), 0, winapi::um::d3d11::D3D11_SDK_VERSION, - d3d_device.as_ptr_ptr(), - &mut featureLevelSupported, + ptr_ptr, + &mut feature_level_supported, ptr::null_mut(), - ).to_result()?; + ))?; // Create the DXGI device used to create bitmap surfaces. - let pDXGIDevice = d3d_device.query_interface::()?; + let pDXGIDevice = d3d_device.cast::()?; // Create the DirectComposition device object. - let mut composition_device = Com::::null(); - winapi::um::dcomp::DCompositionCreateDevice( - &*pDXGIDevice, - &IDCompositionDevice::uuidof(), - composition_device.as_void_ptr_ptr(), - ).to_result()?; + let composition_device = ComPtr::::from_void_out_param(|ptr_ptr| { + winapi::um::dcomp::DCompositionCreateDevice( + &*pDXGIDevice, + &IDCompositionDevice::uuidof(), + ptr_ptr, + ) + })?; // Create the composition target object based on the // specified application window. - let mut composition_target = Com::::null(); - composition_device.CreateTargetForHwnd( - hwnd, - TRUE, - composition_target.as_ptr_ptr(), - ).to_result()?; + let composition_target = ComPtr::from_out_param(|ptr_ptr| { + composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) + })?; Ok(DirectComposition { d3d_device, composition_device, composition_target }) } From 7ff8ed17530356a47603c547bde5cff8061e5da0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 14 Feb 2018 18:42:27 +0100 Subject: [PATCH 10/73] Create some DirectComposition visuals --- Cargo.toml | 1 + src/com.rs | 14 ++++++++++++++ src/main.rs | 48 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 91609ae8d4..3e1f9aa75a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ authors = ["Simon Sapin "] gl = "0.6.0" glutin = "0.12" winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} +winit = "0.10" wio = "0.2" diff --git a/src/com.rs b/src/com.rs index dedc533d0d..5fbe242f7f 100644 --- a/src/com.rs +++ b/src/com.rs @@ -8,6 +8,20 @@ use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; use wio::com::ComPtr; +pub trait ToResult: Sized { + fn to_result(self) -> Result<(), Self>; +} + +impl ToResult for HRESULT { + fn to_result(self) -> Result<(), Self> { + if SUCCEEDED(self) { + Ok(()) + } else { + Err(self) + } + } +} + pub trait OutParam: Sized { /// For use with APIs that "return" a new COM object through a `*mut *mut c_void` out-parameter. /// diff --git a/src/main.rs b/src/main.rs index a7fb27afca..992ac504bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,12 +5,12 @@ extern crate glutin; extern crate winapi; extern crate wio; -use com::OutParam; +use com::{OutParam, ToResult}; use glutin::GlContext; use glutin::os::windows::WindowExt; use std::ptr; use winapi::Interface; -use winapi::shared::minwindef::TRUE; +use winapi::shared::minwindef::{TRUE, FALSE}; use winapi::shared::winerror::HRESULT; use winapi::shared::windef::HWND; use winapi::um::d3d11::ID3D11Device; @@ -33,21 +33,26 @@ fn main() { gl_window.make_current().unwrap(); } - unsafe { + let composition = unsafe { gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _); - gl::ClearColor(0.0, 1.0, 0.0, 1.0); + gl::ClearColor(0., 0.5, 0., 1.0); - DirectComposition::initialize(gl_window.window().get_hwnd() as _).unwrap(); - } + DirectComposition::initialize(gl_window.window().get_hwnd() as _).unwrap() + }; -// let mut running = true; - let mut running = false; + let mut running = true; +// let mut running = false; while running { events_loop.poll_events(|event| { match event { glutin::Event::WindowEvent{ event, .. } => match event { glutin::WindowEvent::Closed => running = false, glutin::WindowEvent::Resized(w, h) => gl_window.resize(w, h), + glutin::WindowEvent::MouseInput { button: glutin::MouseButton::Left, .. } => { + unsafe { + composition.click().unwrap() + } + } _ => () }, _ => () @@ -92,12 +97,12 @@ impl DirectComposition { ))?; // Create the DXGI device used to create bitmap surfaces. - let pDXGIDevice = d3d_device.cast::()?; + let dxgi_device = d3d_device.cast::()?; // Create the DirectComposition device object. let composition_device = ComPtr::::from_void_out_param(|ptr_ptr| { winapi::um::dcomp::DCompositionCreateDevice( - &*pDXGIDevice, + &*dxgi_device, &IDCompositionDevice::uuidof(), ptr_ptr, ) @@ -111,4 +116,27 @@ impl DirectComposition { Ok(DirectComposition { d3d_device, composition_device, composition_target }) } + + unsafe fn click(&self) -> Result<(), HRESULT> { + let visual = || ComPtr::from_out_param(|ptr_ptr| { + self.composition_device.CreateVisual(ptr_ptr) + }); + let root_visual = visual()?; + let visual1 = visual()?; + let visual2 = visual()?; + + self.composition_target.SetRoot(&*root_visual).to_result()?; + root_visual.AddVisual(&*visual1, FALSE, ptr::null_mut()).to_result()?; + root_visual.AddVisual(&*visual2, FALSE, ptr::null_mut()).to_result()?; + + let _surface = ComPtr::from_out_param(|ptr_ptr| self.composition_device.CreateSurface( + 100, + 100, + winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, + winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + ptr_ptr, + ))?; + + Ok(()) + } } From f758d2b7461a7566139cbcec01ee1387c0ab86bc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 14 Feb 2018 18:43:29 +0100 Subject: [PATCH 11/73] Use the winit crate directly --- src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 992ac504bc..0a33288dba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,11 @@ extern crate gl; extern crate glutin; extern crate winapi; +extern crate winit; extern crate wio; use com::{OutParam, ToResult}; use glutin::GlContext; -use glutin::os::windows::WindowExt; use std::ptr; use winapi::Interface; use winapi::shared::minwindef::{TRUE, FALSE}; @@ -16,13 +16,14 @@ use winapi::shared::windef::HWND; use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; +use winit::os::windows::WindowExt; use wio::com::ComPtr; mod com; fn main() { - let mut events_loop = glutin::EventsLoop::new(); - let window = glutin::WindowBuilder::new() + let mut events_loop = winit::EventsLoop::new(); + let window = winit::WindowBuilder::new() .with_title("Hello, world!") .with_dimensions(1024, 768); let context = glutin::ContextBuilder::new() @@ -45,10 +46,10 @@ fn main() { while running { events_loop.poll_events(|event| { match event { - glutin::Event::WindowEvent{ event, .. } => match event { - glutin::WindowEvent::Closed => running = false, - glutin::WindowEvent::Resized(w, h) => gl_window.resize(w, h), - glutin::WindowEvent::MouseInput { button: glutin::MouseButton::Left, .. } => { + winit::Event::WindowEvent{ event, .. } => match event { + winit::WindowEvent::Closed => running = false, + winit::WindowEvent::Resized(w, h) => gl_window.resize(w, h), + winit::WindowEvent::MouseInput { button: winit::MouseButton::Left, .. } => { unsafe { composition.click().unwrap() } From 9effb308af7f408185db51de08cedb281c2be8da Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 15 Feb 2018 14:41:07 +0100 Subject: [PATCH 12/73] Drop GL for now --- Cargo.toml | 2 -- src/main.rs | 28 ++++------------------------ 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e1f9aa75a..9b0bf34ddc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" authors = ["Simon Sapin "] [dependencies] -gl = "0.6.0" -glutin = "0.12" winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} winit = "0.10" wio = "0.2" diff --git a/src/main.rs b/src/main.rs index 0a33288dba..a3d3a6531d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,10 @@ #![allow(non_snake_case)] -extern crate gl; -extern crate glutin; extern crate winapi; extern crate winit; extern crate wio; use com::{OutParam, ToResult}; -use glutin::GlContext; use std::ptr; use winapi::Interface; use winapi::shared::minwindef::{TRUE, FALSE}; @@ -25,30 +22,20 @@ fn main() { let mut events_loop = winit::EventsLoop::new(); let window = winit::WindowBuilder::new() .with_title("Hello, world!") - .with_dimensions(1024, 768); - let context = glutin::ContextBuilder::new() - .with_vsync(true); - let gl_window = glutin::GlWindow::new(window, context, &events_loop).unwrap(); - - unsafe { - gl_window.make_current().unwrap(); - } + .with_dimensions(1024, 768) + .build(&events_loop) + .unwrap(); let composition = unsafe { - gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _); - gl::ClearColor(0., 0.5, 0., 1.0); - - DirectComposition::initialize(gl_window.window().get_hwnd() as _).unwrap() + DirectComposition::initialize(window.get_hwnd() as _).unwrap() }; let mut running = true; -// let mut running = false; while running { events_loop.poll_events(|event| { match event { winit::Event::WindowEvent{ event, .. } => match event { winit::WindowEvent::Closed => running = false, - winit::WindowEvent::Resized(w, h) => gl_window.resize(w, h), winit::WindowEvent::MouseInput { button: winit::MouseButton::Left, .. } => { unsafe { composition.click().unwrap() @@ -59,14 +46,7 @@ fn main() { _ => () } }); - - unsafe { - gl::Clear(gl::COLOR_BUFFER_BIT); - } - - gl_window.swap_buffers().unwrap(); } - println!("Ok") } /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx From e637e089a5b051b6dea028f704d565cd8bf9e50f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 15 Feb 2018 14:45:25 +0100 Subject: [PATCH 13/73] Remove click event handling --- src/main.rs | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/main.rs b/src/main.rs index a3d3a6531d..735176140c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,27 +26,16 @@ fn main() { .build(&events_loop) .unwrap(); - let composition = unsafe { + let _composition = unsafe { DirectComposition::initialize(window.get_hwnd() as _).unwrap() }; - let mut running = true; - while running { - events_loop.poll_events(|event| { - match event { - winit::Event::WindowEvent{ event, .. } => match event { - winit::WindowEvent::Closed => running = false, - winit::WindowEvent::MouseInput { button: winit::MouseButton::Left, .. } => { - unsafe { - composition.click().unwrap() - } - } - _ => () - }, - _ => () - } - }); - } + events_loop.run_forever(|event| match event { + winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { + winit::ControlFlow::Break + } + _ => winit::ControlFlow::Continue, + }); } /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx @@ -95,22 +84,18 @@ impl DirectComposition { composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) })?; - Ok(DirectComposition { d3d_device, composition_device, composition_target }) - } + macro_rules! visual { () => { + ComPtr::from_out_param(|ptr_ptr| composition_device.CreateVisual(ptr_ptr)) + }}; + let root_visual = visual!()?; + let visual1 = visual!()?; + let visual2 = visual!()?; - unsafe fn click(&self) -> Result<(), HRESULT> { - let visual = || ComPtr::from_out_param(|ptr_ptr| { - self.composition_device.CreateVisual(ptr_ptr) - }); - let root_visual = visual()?; - let visual1 = visual()?; - let visual2 = visual()?; - - self.composition_target.SetRoot(&*root_visual).to_result()?; + composition_target.SetRoot(&*root_visual).to_result()?; root_visual.AddVisual(&*visual1, FALSE, ptr::null_mut()).to_result()?; root_visual.AddVisual(&*visual2, FALSE, ptr::null_mut()).to_result()?; - let _surface = ComPtr::from_out_param(|ptr_ptr| self.composition_device.CreateSurface( + let _surface = ComPtr::from_out_param(|ptr_ptr| composition_device.CreateSurface( 100, 100, winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, @@ -118,6 +103,6 @@ impl DirectComposition { ptr_ptr, ))?; - Ok(()) + Ok(DirectComposition { d3d_device, composition_device, composition_target }) } } From 955b2101371e680e9948de40effe1796c41fa9db Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 20 Feb 2018 18:37:00 +0100 Subject: [PATCH 14/73] Create swap chains --- src/com.rs | 41 +++++++++++++++------ src/main.rs | 103 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 96 insertions(+), 48 deletions(-) diff --git a/src/com.rs b/src/com.rs index 5fbe242f7f..4c02c45177 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,29 +1,48 @@ //! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null +use std::fmt; use std::ptr; use winapi::Interface; use winapi::ctypes::c_void; +use winapi::shared::guiddef::GUID; use winapi::shared::winerror::HRESULT; use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; use wio::com::ComPtr; +pub type HResult = Result; + +pub struct HResultError(HRESULT); + +impl fmt::Debug for HResultError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "0x{:08X}", self.0 as u32) + } +} + +impl From for HResultError { + fn from(h: HRESULT) -> Self { + HResultError(h) + } +} + pub trait ToResult: Sized { - fn to_result(self) -> Result<(), Self>; + fn to_result(self) -> HResult<()>; } impl ToResult for HRESULT { - fn to_result(self) -> Result<(), Self> { + fn to_result(self) -> HResult<()> { if SUCCEEDED(self) { Ok(()) } else { - Err(self) + Err(HResultError(self)) } } } -pub trait OutParam: Sized { - /// For use with APIs that "return" a new COM object through a `*mut *mut c_void` out-parameter. +pub trait OutParam: Sized where T: Interface { + /// For use with APIs that take an interface UUID and + /// "return" a new COM object through a `*mut *mut c_void` out-parameter. /// /// # Safety /// @@ -31,10 +50,10 @@ pub trait OutParam: Sized { /// If the closure makes the inner pointer non-null, /// it must point to a valid COM object that implements `T`. /// Ownership of that object is taken. - unsafe fn from_void_out_param(f: F) -> Result - where F: FnOnce(*mut *mut c_void) -> HRESULT + unsafe fn new_with_uuid(f: F) -> HResult + where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT { - Self::from_out_param(|ptr| f(ptr as _)) + Self::new_with(|ptr| f(&T::uuidof(), ptr as _)) } /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter. @@ -45,12 +64,12 @@ pub trait OutParam: Sized { /// If the closure makes the inner pointer non-null, /// it must point to a valid COM object that implements `T`. /// Ownership of that object is taken. - unsafe fn from_out_param(f: F) -> Result + unsafe fn new_with(f: F) -> HResult where F: FnOnce(*mut *mut T) -> HRESULT; } impl OutParam for ComPtr where T: Interface { - unsafe fn from_out_param(f: F) -> Result + unsafe fn new_with(f: F) -> HResult where F: FnOnce(*mut *mut T) -> HRESULT { let mut ptr = ptr::null_mut(); @@ -62,7 +81,7 @@ impl OutParam for ComPtr where T: Interface { let ptr = ptr as *mut IUnknown; (*ptr).Release(); } - Err(status) + Err(HResultError(status)) } } } diff --git a/src/main.rs b/src/main.rs index 735176140c..43aa0b931e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,18 @@ -#![allow(non_snake_case)] - extern crate winapi; extern crate winit; extern crate wio; -use com::{OutParam, ToResult}; +use com::{OutParam, ToResult, HResult}; use std::ptr; -use winapi::Interface; +use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; +use winapi::shared::dxgi1_2::IDXGIFactory2; use winapi::shared::minwindef::{TRUE, FALSE}; -use winapi::shared::winerror::HRESULT; use winapi::shared::windef::HWND; use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; +use winapi::um::dcomp::IDCompositionVisual; +use winapi::um::unknwnbase::IUnknown; use winit::os::windows::WindowExt; use wio::com::ComPtr; @@ -27,9 +27,14 @@ fn main() { .unwrap(); let _composition = unsafe { - DirectComposition::initialize(window.get_hwnd() as _).unwrap() + let dc = DirectComposition::initialize(window.get_hwnd() as _).unwrap(); + dc.create_swap_chain(300, 200).unwrap(); }; + if std::env::var_os("INIT_ONLY").is_some() { + return + } + events_loop.run_forever(|event| match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { winit::ControlFlow::Break @@ -43,21 +48,26 @@ fn main() { #[allow(unused)] struct DirectComposition { d3d_device: ComPtr, + dxgi_factory: ComPtr, composition_device: ComPtr, composition_target: ComPtr, + root_visual: ComPtr, } impl DirectComposition { - unsafe fn initialize(hwnd: HWND) -> Result { + unsafe fn initialize(hwnd: HWND) -> HResult { let mut feature_level_supported = 0; - // Create the D3D device object. - // The D3D11_CREATE_DEVICE_BGRA_SUPPORT flag enables rendering on surfaces using Direct2D. - let d3d_device = ComPtr::from_out_param(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( + let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( ptr::null_mut(), winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, ptr::null_mut(), - winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT, + winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT | + if cfg!(debug_assertions) { + winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG + } else { + 0 + }, ptr::null_mut(), 0, winapi::um::d3d11::D3D11_SDK_VERSION, @@ -66,43 +76,62 @@ impl DirectComposition { ptr::null_mut(), ))?; - // Create the DXGI device used to create bitmap surfaces. let dxgi_device = d3d_device.cast::()?; + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 + // “Because you can create a Direct3D device without creating a swap chain, + // you might need to retrieve the factory that is used to create the device + // in order to create a swap chain.” + let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; + let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + adapter.GetParent(uuid, ptr_ptr) + })?; + // Create the DirectComposition device object. - let composition_device = ComPtr::::from_void_out_param(|ptr_ptr| { - winapi::um::dcomp::DCompositionCreateDevice( - &*dxgi_device, - &IDCompositionDevice::uuidof(), - ptr_ptr, - ) + let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) })?; // Create the composition target object based on the // specified application window. - let composition_target = ComPtr::from_out_param(|ptr_ptr| { + let composition_target = ComPtr::new_with(|ptr_ptr| { composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) })?; - macro_rules! visual { () => { - ComPtr::from_out_param(|ptr_ptr| composition_device.CreateVisual(ptr_ptr)) - }}; - let root_visual = visual!()?; - let visual1 = visual!()?; - let visual2 = visual!()?; - + let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; composition_target.SetRoot(&*root_visual).to_result()?; - root_visual.AddVisual(&*visual1, FALSE, ptr::null_mut()).to_result()?; - root_visual.AddVisual(&*visual2, FALSE, ptr::null_mut()).to_result()?; - - let _surface = ComPtr::from_out_param(|ptr_ptr| composition_device.CreateSurface( - 100, - 100, - winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, - winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, - ptr_ptr, - ))?; - Ok(DirectComposition { d3d_device, composition_device, composition_target }) + Ok(DirectComposition { + d3d_device, dxgi_factory, composition_device, composition_target, root_visual, + }) + } + + unsafe fn create_swap_chain(&self, width: u32, height: u32) + -> HResult> + { + let desc = DXGI_SWAP_CHAIN_DESC1 { + Width: width, + Height: height, + Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, + Stereo: FALSE, + SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 2, + Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, + SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, + AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + Flags: 0, + }; + ComPtr::::new_with(|ptr_ptr| { + self.dxgi_factory.CreateSwapChainForComposition( + self.d3d_device.as_raw() as *mut IUnknown, + &desc, + ptr::null_mut(), + ptr_ptr, + ) + }) } } From 7fd064c0a901fe7596847282466eeb44adc179d4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 20 Feb 2018 20:11:38 +0100 Subject: [PATCH 15/73] Fork wio::ComPtr --- Cargo.toml | 1 - src/com.rs | 82 ++++++++++++++++++++++++++++++++++++++--------------- src/main.rs | 23 +++++++++------ 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b0bf34ddc..004cf70274 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,3 @@ authors = ["Simon Sapin "] [dependencies] winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} winit = "0.10" -wio = "0.2" diff --git a/src/com.rs b/src/com.rs index 4c02c45177..43e4fd166b 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,6 +1,7 @@ //! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null use std::fmt; +use std::ops; use std::ptr; use winapi::Interface; use winapi::ctypes::c_void; @@ -8,7 +9,6 @@ use winapi::shared::guiddef::GUID; use winapi::shared::winerror::HRESULT; use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; -use wio::com::ComPtr; pub type HResult = Result; @@ -40,36 +40,29 @@ impl ToResult for HRESULT { } } -pub trait OutParam: Sized where T: Interface { +/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs +#[derive(PartialEq, Debug)] +pub struct ComPtr(*mut T) where T: Interface; + +impl ComPtr where T: Interface { + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// For use with APIs that take an interface UUID and /// "return" a new COM object through a `*mut *mut c_void` out-parameter. - /// - /// # Safety - /// - /// `T` must be a COM interface that inherits from `IUnknown`. - /// If the closure makes the inner pointer non-null, - /// it must point to a valid COM object that implements `T`. - /// Ownership of that object is taken. - unsafe fn new_with_uuid(f: F) -> HResult + pub unsafe fn new_with_uuid(f: F) -> HResult where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT { Self::new_with(|ptr| f(&T::uuidof(), ptr as _)) } /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter. - /// - /// # Safety - /// - /// `T` must be a COM interface that inherits from `IUnknown`. - /// If the closure makes the inner pointer non-null, - /// it must point to a valid COM object that implements `T`. - /// Ownership of that object is taken. - unsafe fn new_with(f: F) -> HResult - where F: FnOnce(*mut *mut T) -> HRESULT; -} - -impl OutParam for ComPtr where T: Interface { - unsafe fn new_with(f: F) -> HResult + pub unsafe fn new_with(f: F) -> HResult where F: FnOnce(*mut *mut T) -> HRESULT { let mut ptr = ptr::null_mut(); @@ -84,4 +77,47 @@ impl OutParam for ComPtr where T: Interface { Err(HResultError(status)) } } + + pub fn as_unknown(&self) -> *mut IUnknown { + self.0 as *mut IUnknown + } + + /// Performs QueryInterface fun. + pub fn cast(&self) -> HResult> where U: Interface { + unsafe { + let mut obj = ptr::null_mut(); + (*self.as_unknown()).QueryInterface(&U::uuidof(), &mut obj).to_result()?; + Ok(ComPtr::from_raw(obj as *mut U)) + } + } +} + +impl ops::Deref for ComPtr where T: Interface { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} + +impl ops::DerefMut for ComPtr where T: Interface { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.0 } + } +} + +impl Clone for ComPtr where T: Interface { + fn clone(&self) -> Self { + unsafe { + (*self.as_unknown()).AddRef(); + ComPtr(self.0) + } + } +} + +impl Drop for ComPtr where T: Interface { + fn drop(&mut self) { + unsafe { + (*self.as_unknown()).Release(); + } + } } diff --git a/src/main.rs b/src/main.rs index 43aa0b931e..01de1de663 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,7 @@ extern crate winapi; extern crate winit; -extern crate wio; -use com::{OutParam, ToResult, HResult}; +use com::{ComPtr, ToResult, HResult}; use std::ptr; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; use winapi::shared::dxgi1_2::IDXGIFactory2; @@ -12,9 +11,7 @@ use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::IDCompositionVisual; -use winapi::um::unknwnbase::IUnknown; use winit::os::windows::WindowExt; -use wio::com::ComPtr; mod com; @@ -27,8 +24,7 @@ fn main() { .unwrap(); let _composition = unsafe { - let dc = DirectComposition::initialize(window.get_hwnd() as _).unwrap(); - dc.create_swap_chain(300, 200).unwrap(); + initialize(window.get_hwnd() as _).unwrap() }; if std::env::var_os("INIT_ONLY").is_some() { @@ -45,6 +41,15 @@ fn main() { /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx +unsafe fn initialize(hwnd: HWND) -> HResult { + let mut composition = DirectComposition::new(hwnd)?; + + let swap_chain = composition.create_swap_chain(300, 200)?; + composition.root_visual.SetContent(&*****swap_chain).to_result()?; + + Ok(composition) +} + #[allow(unused)] struct DirectComposition { d3d_device: ComPtr, @@ -55,7 +60,7 @@ struct DirectComposition { } impl DirectComposition { - unsafe fn initialize(hwnd: HWND) -> HResult { + unsafe fn new(hwnd: HWND) -> HResult { let mut feature_level_supported = 0; let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( @@ -106,7 +111,7 @@ impl DirectComposition { }) } - unsafe fn create_swap_chain(&self, width: u32, height: u32) + unsafe fn create_swap_chain(&mut self, width: u32, height: u32) -> HResult> { let desc = DXGI_SWAP_CHAIN_DESC1 { @@ -127,7 +132,7 @@ impl DirectComposition { }; ComPtr::::new_with(|ptr_ptr| { self.dxgi_factory.CreateSwapChainForComposition( - self.d3d_device.as_raw() as *mut IUnknown, + self.d3d_device.as_unknown(), &desc, ptr::null_mut(), ptr_ptr, From 8d40fdf8b47c9f3d44e867498d5c22d16f89e587 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 20 Feb 2018 20:48:21 +0100 Subject: [PATCH 16/73] First D3D rectangle! --- src/com.rs | 20 +++++++++++++++----- src/main.rs | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/com.rs b/src/com.rs index 43e4fd166b..1b86c4e8b9 100644 --- a/src/com.rs +++ b/src/com.rs @@ -40,6 +40,10 @@ impl ToResult for HRESULT { } } +pub fn as_ptr(x: &T) -> *mut T { + x as *const T as _ +} + /// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs #[derive(PartialEq, Debug)] pub struct ComPtr(*mut T) where T: Interface; @@ -78,15 +82,21 @@ impl ComPtr where T: Interface { } } - pub fn as_unknown(&self) -> *mut IUnknown { - self.0 as *mut IUnknown + pub fn as_raw(&self) -> *mut T { + self.0 + } + + fn as_unknown(&self) -> &IUnknown { + unsafe { + &*(self.0 as *mut IUnknown) + } } /// Performs QueryInterface fun. pub fn cast(&self) -> HResult> where U: Interface { unsafe { let mut obj = ptr::null_mut(); - (*self.as_unknown()).QueryInterface(&U::uuidof(), &mut obj).to_result()?; + self.as_unknown().QueryInterface(&U::uuidof(), &mut obj).to_result()?; Ok(ComPtr::from_raw(obj as *mut U)) } } @@ -108,7 +118,7 @@ impl ops::DerefMut for ComPtr where T: Interface { impl Clone for ComPtr where T: Interface { fn clone(&self) -> Self { unsafe { - (*self.as_unknown()).AddRef(); + self.as_unknown().AddRef(); ComPtr(self.0) } } @@ -117,7 +127,7 @@ impl Clone for ComPtr where T: Interface { impl Drop for ComPtr where T: Interface { fn drop(&mut self) { unsafe { - (*self.as_unknown()).Release(); + self.as_unknown().Release(); } } } diff --git a/src/main.rs b/src/main.rs index 01de1de663..1ebbabe24b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,13 @@ extern crate winapi; extern crate winit; -use com::{ComPtr, ToResult, HResult}; +use com::{ComPtr, ToResult, HResult, as_ptr}; use std::ptr; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; use winapi::shared::dxgi1_2::IDXGIFactory2; use winapi::shared::minwindef::{TRUE, FALSE}; use winapi::shared::windef::HWND; +use winapi::shared::winerror::S_OK; use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; @@ -28,7 +29,7 @@ fn main() { }; if std::env::var_os("INIT_ONLY").is_some() { - return +// return } events_loop.run_forever(|event| match event { @@ -41,13 +42,36 @@ fn main() { /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx -unsafe fn initialize(hwnd: HWND) -> HResult { +unsafe fn initialize(hwnd: HWND) -> HResult<( + DirectComposition, + ComPtr, + ComPtr, + ComPtr, +)> { let mut composition = DirectComposition::new(hwnd)?; let swap_chain = composition.create_swap_chain(300, 200)?; composition.root_visual.SetContent(&*****swap_chain).to_result()?; - - Ok(composition) + composition.composition_device.Commit().to_result()?; + + let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + swap_chain.GetBuffer(0, uuid, ptr_ptr) + })?; + let render_target = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.CreateRenderTargetView( + as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, + ) + })?; + let context = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.GetImmediateContext(ptr_ptr); + S_OK + })?; + context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); + let green_rgba = [0., 0.5, 0., 1.]; + context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); + swap_chain.Present(0, 0).to_result()?; + + Ok((composition, swap_chain, back_buffer, context)) } #[allow(unused)] @@ -132,7 +156,7 @@ impl DirectComposition { }; ComPtr::::new_with(|ptr_ptr| { self.dxgi_factory.CreateSwapChainForComposition( - self.d3d_device.as_unknown(), + as_ptr(&self.d3d_device), &desc, ptr::null_mut(), ptr_ptr, From 5c6ae42ca53fcfe4ceee7635e9e3ea4c1c6d5511 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 14:33:51 +0100 Subject: [PATCH 17/73] Try to provide safe APIs. (Still needs safety review.) --- src/main.rs | 213 ++++++++++++++++++++++++++-------------------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1ebbabe24b..2f4f73a93a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,12 +24,10 @@ fn main() { .build(&events_loop) .unwrap(); - let _composition = unsafe { - initialize(window.get_hwnd() as _).unwrap() - }; + let _composition = initialize(window.get_hwnd() as _).unwrap(); if std::env::var_os("INIT_ONLY").is_some() { -// return + return } events_loop.run_forever(|event| match event { @@ -42,36 +40,33 @@ fn main() { /// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx -unsafe fn initialize(hwnd: HWND) -> HResult<( - DirectComposition, - ComPtr, - ComPtr, - ComPtr, -)> { - let mut composition = DirectComposition::new(hwnd)?; - - let swap_chain = composition.create_swap_chain(300, 200)?; - composition.root_visual.SetContent(&*****swap_chain).to_result()?; - composition.composition_device.Commit().to_result()?; - - let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - swap_chain.GetBuffer(0, uuid, ptr_ptr) - })?; - let render_target = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.CreateRenderTargetView( - as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, - ) - })?; - let context = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.GetImmediateContext(ptr_ptr); - S_OK - })?; - context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); - let green_rgba = [0., 0.5, 0., 1.]; - context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); - swap_chain.Present(0, 0).to_result()?; - - Ok((composition, swap_chain, back_buffer, context)) +fn initialize(hwnd: HWND) -> HResult { + unsafe { + let mut composition = DirectComposition::new(hwnd)?; + + let swap_chain = composition.create_swap_chain(300, 200)?; + composition.root_visual.SetContent(&*****swap_chain).to_result()?; + composition.composition_device.Commit().to_result()?; + + let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + swap_chain.GetBuffer(0, uuid, ptr_ptr) + })?; + let render_target = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.CreateRenderTargetView( + as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, + ) + })?; + let context = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.GetImmediateContext(ptr_ptr); + S_OK + })?; + context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); + let green_rgba = [0., 0.5, 0., 1.]; + context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); + swap_chain.Present(0, 0).to_result()?; + + Ok(composition) + } } #[allow(unused)] @@ -84,83 +79,87 @@ struct DirectComposition { } impl DirectComposition { - unsafe fn new(hwnd: HWND) -> HResult { - let mut feature_level_supported = 0; - - let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( - ptr::null_mut(), - winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, - ptr::null_mut(), - winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT | - if cfg!(debug_assertions) { - winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG - } else { - 0 - }, - ptr::null_mut(), - 0, - winapi::um::d3d11::D3D11_SDK_VERSION, - ptr_ptr, - &mut feature_level_supported, - ptr::null_mut(), - ))?; - - let dxgi_device = d3d_device.cast::()?; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 - // “Because you can create a Direct3D device without creating a swap chain, - // you might need to retrieve the factory that is used to create the device - // in order to create a swap chain.” - let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; - let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - adapter.GetParent(uuid, ptr_ptr) - })?; - - // Create the DirectComposition device object. - let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) - })?; - - // Create the composition target object based on the - // specified application window. - let composition_target = ComPtr::new_with(|ptr_ptr| { - composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) - })?; - - let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; - composition_target.SetRoot(&*root_visual).to_result()?; + pub fn new(hwnd: HWND) -> HResult { + unsafe { + let mut feature_level_supported = 0; - Ok(DirectComposition { - d3d_device, dxgi_factory, composition_device, composition_target, root_visual, - }) + let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( + ptr::null_mut(), + winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, + ptr::null_mut(), + winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT | + if cfg!(debug_assertions) { + winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG + } else { + 0 + }, + ptr::null_mut(), + 0, + winapi::um::d3d11::D3D11_SDK_VERSION, + ptr_ptr, + &mut feature_level_supported, + ptr::null_mut(), + ))?; + + let dxgi_device = d3d_device.cast::()?; + + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 + // “Because you can create a Direct3D device without creating a swap chain, + // you might need to retrieve the factory that is used to create the device + // in order to create a swap chain.” + let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; + let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + adapter.GetParent(uuid, ptr_ptr) + })?; + + // Create the DirectComposition device object. + let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) + })?; + + // Create the composition target object based on the + // specified application window. + let composition_target = ComPtr::new_with(|ptr_ptr| { + composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) + })?; + + let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; + composition_target.SetRoot(&*root_visual).to_result()?; + + Ok(DirectComposition { + d3d_device, dxgi_factory, composition_device, composition_target, root_visual, + }) + } } - unsafe fn create_swap_chain(&mut self, width: u32, height: u32) + pub fn create_swap_chain(&mut self, width: u32, height: u32) -> HResult> { - let desc = DXGI_SWAP_CHAIN_DESC1 { - Width: width, - Height: height, - Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, - Stereo: FALSE, - SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, - BufferCount: 2, - Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, - SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, - AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, - Flags: 0, - }; - ComPtr::::new_with(|ptr_ptr| { - self.dxgi_factory.CreateSwapChainForComposition( - as_ptr(&self.d3d_device), - &desc, - ptr::null_mut(), - ptr_ptr, - ) - }) + unsafe { + let desc = DXGI_SWAP_CHAIN_DESC1 { + Width: width, + Height: height, + Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, + Stereo: FALSE, + SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 2, + Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, + SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, + AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + Flags: 0, + }; + ComPtr::::new_with(|ptr_ptr| { + self.dxgi_factory.CreateSwapChainForComposition( + as_ptr(&self.d3d_device), + &desc, + ptr::null_mut(), + ptr_ptr, + ) + }) + } } } From e10178dd89db266f37343b7d0659ba4537e32a08 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 14:52:41 +0100 Subject: [PATCH 18/73] Separate the library crate from the demo app --- Cargo.toml | 5 +- src/com.rs | 1 + src/lib.rs | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 148 +++------------------------------------------------- 4 files changed, 157 insertions(+), 142 deletions(-) create mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 004cf70274..03bcaf672f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "directcomposition" version = "0.1.0" authors = ["Simon Sapin "] -[dependencies] +[target.'cfg(windows)'.dependencies] winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} + +# For the `main.rs` demo +[dependencies] winit = "0.10" diff --git a/src/com.rs b/src/com.rs index 1b86c4e8b9..54d2dc5244 100644 --- a/src/com.rs +++ b/src/com.rs @@ -12,6 +12,7 @@ use winapi::um::unknwnbase::IUnknown; pub type HResult = Result; +/// An error code returned by a Windows API. pub struct HResultError(HRESULT); impl fmt::Debug for HResultError { diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000000..f91b5acf0d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,145 @@ +#![cfg(windows)] + +extern crate winapi; + +use com::{ComPtr, ToResult, as_ptr}; +use std::ptr; +use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; +use winapi::shared::dxgi1_2::IDXGIFactory2; +use winapi::shared::minwindef::{TRUE, FALSE}; +use winapi::shared::windef::HWND; +use winapi::shared::winerror::S_OK; +use winapi::um::d3d11::ID3D11Device; +use winapi::um::dcomp::IDCompositionDevice; +use winapi::um::dcomp::IDCompositionTarget; +use winapi::um::dcomp::IDCompositionVisual; + +mod com; + +pub use com::{HResult, HResultError}; + +/// Initialize DirectComposition in the given window +/// +/// # Safety +/// +/// `hwnd` must be a valid handle to a window. +pub unsafe fn initialize(hwnd: *mut ()) -> HResult { + let composition = DirectComposition::new(hwnd as HWND)?; + + let swap_chain = composition.create_swap_chain(300, 200)?; + composition.root_visual.SetContent(&*****swap_chain).to_result()?; + composition.composition_device.Commit().to_result()?; + + let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + swap_chain.GetBuffer(0, uuid, ptr_ptr) + })?; + let render_target = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.CreateRenderTargetView( + as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, + ) + })?; + let context = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.GetImmediateContext(ptr_ptr); + S_OK + })?; + context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); + let green_rgba = [0., 0.5, 0., 1.]; + context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); + swap_chain.Present(0, 0).to_result()?; + + Ok(composition) +} + +pub struct DirectComposition { + d3d_device: ComPtr, + dxgi_factory: ComPtr, + composition_device: ComPtr, + root_visual: ComPtr, + + #[allow(unused)] // Needs to be kept alive + composition_target: ComPtr, +} + +impl DirectComposition { + unsafe fn new(hwnd: HWND) -> HResult { + let mut feature_level_supported = 0; + + let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( + ptr::null_mut(), + winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, + ptr::null_mut(), + winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT | + if cfg!(debug_assertions) { + winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG + } else { + 0 + }, + ptr::null_mut(), + 0, + winapi::um::d3d11::D3D11_SDK_VERSION, + ptr_ptr, + &mut feature_level_supported, + ptr::null_mut(), + ))?; + + let dxgi_device = d3d_device.cast::()?; + + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 + // “Because you can create a Direct3D device without creating a swap chain, + // you might need to retrieve the factory that is used to create the device + // in order to create a swap chain.” + let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; + let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + adapter.GetParent(uuid, ptr_ptr) + })?; + + // Create the DirectComposition device object. + let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) + })?; + + // Create the composition target object based on the + // specified application window. + let composition_target = ComPtr::new_with(|ptr_ptr| { + composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) + })?; + + let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; + composition_target.SetRoot(&*root_visual).to_result()?; + + Ok(DirectComposition { + d3d_device, dxgi_factory, composition_device, composition_target, root_visual, + }) + } + + fn create_swap_chain(&self, width: u32, height: u32) + -> HResult> + { + unsafe { + let desc = DXGI_SWAP_CHAIN_DESC1 { + Width: width, + Height: height, + Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, + Stereo: FALSE, + SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 2, + Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, + SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, + AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + Flags: 0, + }; + ComPtr::::new_with(|ptr_ptr| { + self.dxgi_factory.CreateSwapChainForComposition( + as_ptr(&self.d3d_device), + &desc, + ptr::null_mut(), + ptr_ptr, + ) + }) + } + } +} diff --git a/src/main.rs b/src/main.rs index 2f4f73a93a..f871a34d2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,11 @@ -extern crate winapi; +#[cfg(not(windows))] +compile_error!("This demo only runs on Windows."); + +extern crate directcomposition; extern crate winit; -use com::{ComPtr, ToResult, HResult, as_ptr}; -use std::ptr; -use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; -use winapi::shared::dxgi1_2::IDXGIFactory2; -use winapi::shared::minwindef::{TRUE, FALSE}; -use winapi::shared::windef::HWND; -use winapi::shared::winerror::S_OK; -use winapi::um::d3d11::ID3D11Device; -use winapi::um::dcomp::IDCompositionDevice; -use winapi::um::dcomp::IDCompositionTarget; -use winapi::um::dcomp::IDCompositionVisual; use winit::os::windows::WindowExt; -mod com; - fn main() { let mut events_loop = winit::EventsLoop::new(); let window = winit::WindowBuilder::new() @@ -24,7 +14,9 @@ fn main() { .build(&events_loop) .unwrap(); - let _composition = initialize(window.get_hwnd() as _).unwrap(); + let _composition = unsafe { + directcomposition::initialize(window.get_hwnd() as _).unwrap() + }; if std::env::var_os("INIT_ONLY").is_some() { return @@ -37,129 +29,3 @@ fn main() { _ => winit::ControlFlow::Continue, }); } - -/// https://msdn.microsoft.com/en-us/library/windows/desktop/hh449180(v=vs.85).aspx - -fn initialize(hwnd: HWND) -> HResult { - unsafe { - let mut composition = DirectComposition::new(hwnd)?; - - let swap_chain = composition.create_swap_chain(300, 200)?; - composition.root_visual.SetContent(&*****swap_chain).to_result()?; - composition.composition_device.Commit().to_result()?; - - let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - swap_chain.GetBuffer(0, uuid, ptr_ptr) - })?; - let render_target = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.CreateRenderTargetView( - as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, - ) - })?; - let context = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.GetImmediateContext(ptr_ptr); - S_OK - })?; - context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); - let green_rgba = [0., 0.5, 0., 1.]; - context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); - swap_chain.Present(0, 0).to_result()?; - - Ok(composition) - } -} - -#[allow(unused)] -struct DirectComposition { - d3d_device: ComPtr, - dxgi_factory: ComPtr, - composition_device: ComPtr, - composition_target: ComPtr, - root_visual: ComPtr, -} - -impl DirectComposition { - pub fn new(hwnd: HWND) -> HResult { - unsafe { - let mut feature_level_supported = 0; - - let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( - ptr::null_mut(), - winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, - ptr::null_mut(), - winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT | - if cfg!(debug_assertions) { - winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG - } else { - 0 - }, - ptr::null_mut(), - 0, - winapi::um::d3d11::D3D11_SDK_VERSION, - ptr_ptr, - &mut feature_level_supported, - ptr::null_mut(), - ))?; - - let dxgi_device = d3d_device.cast::()?; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 - // “Because you can create a Direct3D device without creating a swap chain, - // you might need to retrieve the factory that is used to create the device - // in order to create a swap chain.” - let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; - let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - adapter.GetParent(uuid, ptr_ptr) - })?; - - // Create the DirectComposition device object. - let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) - })?; - - // Create the composition target object based on the - // specified application window. - let composition_target = ComPtr::new_with(|ptr_ptr| { - composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) - })?; - - let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; - composition_target.SetRoot(&*root_visual).to_result()?; - - Ok(DirectComposition { - d3d_device, dxgi_factory, composition_device, composition_target, root_visual, - }) - } - } - - pub fn create_swap_chain(&mut self, width: u32, height: u32) - -> HResult> - { - unsafe { - let desc = DXGI_SWAP_CHAIN_DESC1 { - Width: width, - Height: height, - Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, - Stereo: FALSE, - SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, - BufferCount: 2, - Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, - SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, - AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, - Flags: 0, - }; - ComPtr::::new_with(|ptr_ptr| { - self.dxgi_factory.CreateSwapChainForComposition( - as_ptr(&self.d3d_device), - &desc, - ptr::null_mut(), - ptr_ptr, - ) - }) - } - } -} From 17c39578e9adc0983404400769f046ac8bf66838 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 15:27:43 +0100 Subject: [PATCH 19/73] Make the lib more library-like, keep hard-coded values in the demo app. --- src/lib.rs | 109 ++++++++++++++++++++++++++++++++-------------------- src/main.rs | 12 +++++- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f91b5acf0d..eb841a9f45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ extern crate winapi; -use com::{ComPtr, ToResult, as_ptr}; +use com::{ComPtr, ToResult, HResult, as_ptr}; use std::ptr; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; use winapi::shared::dxgi1_2::IDXGIFactory2; @@ -14,41 +14,7 @@ use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::IDCompositionVisual; -mod com; - -pub use com::{HResult, HResultError}; - -/// Initialize DirectComposition in the given window -/// -/// # Safety -/// -/// `hwnd` must be a valid handle to a window. -pub unsafe fn initialize(hwnd: *mut ()) -> HResult { - let composition = DirectComposition::new(hwnd as HWND)?; - - let swap_chain = composition.create_swap_chain(300, 200)?; - composition.root_visual.SetContent(&*****swap_chain).to_result()?; - composition.composition_device.Commit().to_result()?; - - let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - swap_chain.GetBuffer(0, uuid, ptr_ptr) - })?; - let render_target = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.CreateRenderTargetView( - as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, - ) - })?; - let context = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.GetImmediateContext(ptr_ptr); - S_OK - })?; - context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); - let green_rgba = [0., 0.5, 0., 1.]; - context.ClearRenderTargetView(render_target.as_raw(), &green_rgba); - swap_chain.Present(0, 0).to_result()?; - - Ok(composition) -} +pub mod com; pub struct DirectComposition { d3d_device: ComPtr, @@ -61,7 +27,12 @@ pub struct DirectComposition { } impl DirectComposition { - unsafe fn new(hwnd: HWND) -> HResult { + /// Initialize DirectComposition in the given window + /// + /// # Safety + /// + /// `hwnd` must be a valid handle to a window. + pub unsafe fn new(hwnd: HWND) -> HResult { let mut feature_level_supported = 0; let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( @@ -112,9 +83,14 @@ impl DirectComposition { }) } - fn create_swap_chain(&self, width: u32, height: u32) - -> HResult> - { + /// Execute changes to the DirectComposition scene. + pub fn commit(&self) -> HResult<()> { + unsafe { + self.composition_device.Commit().to_result() + } + } + + pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult { unsafe { let desc = DXGI_SWAP_CHAIN_DESC1 { Width: width, @@ -132,14 +108,63 @@ impl DirectComposition { AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, Flags: 0, }; - ComPtr::::new_with(|ptr_ptr| { + let swap_chain = ComPtr::::new_with(|ptr_ptr| { self.dxgi_factory.CreateSwapChainForComposition( as_ptr(&self.d3d_device), &desc, ptr::null_mut(), ptr_ptr, ) - }) + })?; + let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; + visual.SetContent(&*****swap_chain).to_result()?; + self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; + + Ok(D3DVisual { visual, swap_chain }) + } + } +} + +/// A DirectComposition "visual" configured for rendering with Direct3D. +pub struct D3DVisual { + visual: ComPtr, + swap_chain: ComPtr, +} + +impl D3DVisual { + pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> { + unsafe { + self.visual.SetOffsetX_1(offset_x).to_result() + } + } + + pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> { + unsafe { + self.visual.SetOffsetY_1(offset_y).to_result() + } + } + + pub fn render_and_present_solid_frame(&self, composition: &DirectComposition, rgba: &[f32; 4]) + -> HResult<()> { + unsafe { + let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + self.swap_chain.GetBuffer(0, uuid, ptr_ptr) + })?; + let render_target = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.CreateRenderTargetView( + as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, + ) + })?; + let context = ComPtr::new_with(|ptr_ptr| { + composition.d3d_device.GetImmediateContext(ptr_ptr); + S_OK + })?; + + // FIXME: arbitrary D3D rendering here? + context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); + context.ClearRenderTargetView(render_target.as_raw(), &rgba); + + self.swap_chain.Present(0, 0).to_result() } } } diff --git a/src/main.rs b/src/main.rs index f871a34d2b..6bec6e4a5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,18 @@ fn main() { .build(&events_loop) .unwrap(); - let _composition = unsafe { - directcomposition::initialize(window.get_hwnd() as _).unwrap() + let composition = unsafe { + directcomposition::DirectComposition::new(window.get_hwnd() as _).unwrap() }; + let visual = composition.create_d3d_visual(300, 200).unwrap(); + visual.set_offset_x(100.).unwrap(); + visual.set_offset_y(50.).unwrap(); + composition.commit().unwrap(); + + let green_rgba = [0., 0.5, 0., 1.]; + visual.render_and_present_solid_frame(&composition, &green_rgba).unwrap(); + if std::env::var_os("INIT_ONLY").is_some() { return } From aff6c39aac619a78bb1007fddf7c913957a79f5e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 15:32:15 +0100 Subject: [PATCH 20/73] =?UTF-8?q?Move=20demo=20app=E2=80=99s=20unsafe=20co?= =?UTF-8?q?de=20into=20a=20safe=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6bec6e4a5e..163a320825 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ compile_error!("This demo only runs on Windows."); extern crate directcomposition; extern crate winit; +use directcomposition::DirectComposition; use winit::os::windows::WindowExt; fn main() { @@ -14,9 +15,7 @@ fn main() { .build(&events_loop) .unwrap(); - let composition = unsafe { - directcomposition::DirectComposition::new(window.get_hwnd() as _).unwrap() - }; + let composition = direct_composition_from_window(&window); let visual = composition.create_d3d_visual(300, 200).unwrap(); visual.set_offset_x(100.).unwrap(); @@ -37,3 +36,9 @@ fn main() { _ => winit::ControlFlow::Continue, }); } + +fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { + unsafe { + DirectComposition::new(window.get_hwnd() as _).unwrap() + } +} From 39c125c1bf6265c90d6c5f3685809c546867ba88 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 15:34:56 +0100 Subject: [PATCH 21/73] Two D3D things in the same window --- src/main.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 163a320825..dcf519d18b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,17 +17,18 @@ fn main() { let composition = direct_composition_from_window(&window); - let visual = composition.create_d3d_visual(300, 200).unwrap(); - visual.set_offset_x(100.).unwrap(); - visual.set_offset_y(50.).unwrap(); - composition.commit().unwrap(); + let visual1 = composition.create_d3d_visual(300, 200).unwrap(); + visual1.set_offset_x(100.).unwrap(); + visual1.set_offset_y(50.).unwrap(); - let green_rgba = [0., 0.5, 0., 1.]; - visual.render_and_present_solid_frame(&composition, &green_rgba).unwrap(); + let visual2 = composition.create_d3d_visual(400, 300).unwrap(); + visual2.set_offset_x(200.).unwrap(); + visual2.set_offset_y(100.).unwrap(); - if std::env::var_os("INIT_ONLY").is_some() { - return - } + composition.commit().unwrap(); + + visual1.render_and_present_solid_frame(&composition, &[0., 0.2, 0.4, 1.]).unwrap(); + visual2.render_and_present_solid_frame(&composition, &[0., 0.5, 0., 0.5]).unwrap(); events_loop.run_forever(|event| match event { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { From 828c2850436b060123a35ef034073fd69182ea12 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 15:37:45 +0100 Subject: [PATCH 22/73] Alpha transparency! --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index eb841a9f45..866801ad23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ impl DirectComposition { BufferCount: 2, Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH, SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, - AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + AlphaMode: winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED, Flags: 0, }; let swap_chain = ComPtr::::new_with(|ptr_ptr| { From c7eea0bffa3de807ce069a8d64565e0451c22d19 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 15:44:29 +0100 Subject: [PATCH 23/73] Scrolling without re-rendering --- src/main.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index dcf519d18b..fda1414c5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,8 +22,9 @@ fn main() { visual1.set_offset_y(50.).unwrap(); let visual2 = composition.create_d3d_visual(400, 300).unwrap(); + let mut offset_y = 100.; visual2.set_offset_x(200.).unwrap(); - visual2.set_offset_y(100.).unwrap(); + visual2.set_offset_y(offset_y).unwrap(); composition.commit().unwrap(); @@ -34,7 +35,21 @@ fn main() { winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { winit::ControlFlow::Break } - _ => winit::ControlFlow::Continue, + winit::Event::DeviceEvent { event: winit::DeviceEvent::MouseWheel { delta }, .. } => { + let dy = match delta { + winit::MouseScrollDelta::LineDelta(_, dy) => dy, + winit::MouseScrollDelta::PixelDelta(_, dy) => dy, + }; + offset_y = (offset_y - 10. * dy).max(0.).min(468.); + + visual2.set_offset_y(offset_y).unwrap(); + composition.commit().unwrap(); + + winit::ControlFlow::Continue + } + _ => { + winit::ControlFlow::Continue + } }); } From 281a5115449e30f1acae1d67ca369728d3997d3a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 16:56:52 +0100 Subject: [PATCH 24/73] Remove unused and unsound DerefMut --- src/com.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/com.rs b/src/com.rs index 54d2dc5244..be41211704 100644 --- a/src/com.rs +++ b/src/com.rs @@ -110,12 +110,6 @@ impl ops::Deref for ComPtr where T: Interface { } } -impl ops::DerefMut for ComPtr where T: Interface { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.0 } - } -} - impl Clone for ComPtr where T: Interface { fn clone(&self) -> Self { unsafe { From b8458bbf2018a7e670af75365a75ac80eb8cf9d1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 22 Feb 2018 18:32:23 +0100 Subject: [PATCH 25/73] Repaint one of the visuals on click --- src/main.rs | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index fda1414c5e..683e94ef96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,28 +28,41 @@ fn main() { composition.commit().unwrap(); + let mut green = 0.5; visual1.render_and_present_solid_frame(&composition, &[0., 0.2, 0.4, 1.]).unwrap(); - visual2.render_and_present_solid_frame(&composition, &[0., 0.5, 0., 0.5]).unwrap(); + visual2.render_and_present_solid_frame(&composition, &[0., green, 0., 0.5]).unwrap(); - events_loop.run_forever(|event| match event { - winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => { - winit::ControlFlow::Break - } - winit::Event::DeviceEvent { event: winit::DeviceEvent::MouseWheel { delta }, .. } => { - let dy = match delta { - winit::MouseScrollDelta::LineDelta(_, dy) => dy, - winit::MouseScrollDelta::PixelDelta(_, dy) => dy, - }; - offset_y = (offset_y - 10. * dy).max(0.).min(468.); - - visual2.set_offset_y(offset_y).unwrap(); - composition.commit().unwrap(); + events_loop.run_forever(|event| { + if let winit::Event::WindowEvent { event, .. } = event { + match event { + winit::WindowEvent::Closed => { + return winit::ControlFlow::Break + } + winit::WindowEvent::MouseWheel { delta, .. } => { + let dy = match delta { + winit::MouseScrollDelta::LineDelta(_, dy) => dy, + winit::MouseScrollDelta::PixelDelta(_, dy) => dy, + }; + offset_y = (offset_y - 10. * dy).max(0.).min(468.); - winit::ControlFlow::Continue - } - _ => { - winit::ControlFlow::Continue + visual2.set_offset_y(offset_y).unwrap(); + composition.commit().unwrap(); + } + winit::WindowEvent::MouseInput { + button: winit::MouseButton::Left, + state: winit::ElementState::Pressed, + .. + } => { + green += 0.1; + green %= 1.; + visual2.render_and_present_solid_frame( + &composition, &[0., green, 0., 0.5] + ).unwrap(); + } + _ => {} + } } + winit::ControlFlow::Continue }); } From b69dbd634b866f960af04138e1d27a182b1888fd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:04:15 +0100 Subject: [PATCH 26/73] OMSetRenderTargets appears to be unnecessary here --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 866801ad23..0031de3727 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,7 +161,6 @@ impl D3DVisual { })?; // FIXME: arbitrary D3D rendering here? - context.OMSetRenderTargets(1, &render_target.as_raw(), ptr::null_mut()); context.ClearRenderTargetView(render_target.as_raw(), &rgba); self.swap_chain.Present(0, 0).to_result() From a730f98158409aa8425699c68e0e2459e9c6a105 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:11:55 +0100 Subject: [PATCH 27/73] Keep one shared D3D context --- src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0031de3727..bfd643d3dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub mod com; pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, + d3d_device_context: ComPtr, composition_device: ComPtr, root_visual: ComPtr, @@ -64,6 +65,11 @@ impl DirectComposition { adapter.GetParent(uuid, ptr_ptr) })?; + let d3d_device_context = ComPtr::new_with(|ptr_ptr| { + d3d_device.GetImmediateContext(ptr_ptr); + S_OK + })?; + // Create the DirectComposition device object. let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) @@ -79,7 +85,8 @@ impl DirectComposition { composition_target.SetRoot(&*root_visual).to_result()?; Ok(DirectComposition { - d3d_device, dxgi_factory, composition_device, composition_target, root_visual, + d3d_device, dxgi_factory, d3d_device_context, + composition_device, composition_target, root_visual, }) } @@ -155,13 +162,9 @@ impl D3DVisual { as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, ) })?; - let context = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.GetImmediateContext(ptr_ptr); - S_OK - })?; // FIXME: arbitrary D3D rendering here? - context.ClearRenderTargetView(render_target.as_raw(), &rgba); + composition.d3d_device_context.ClearRenderTargetView(render_target.as_raw(), &rgba); self.swap_chain.Present(0, 0).to_result() } From ce02a22acd238d02288cf13c5c44f6fb9f581778 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:19:00 +0100 Subject: [PATCH 28/73] Make sure we can keep rendering both visuals --- src/main.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 683e94ef96..f22bdb6fb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,9 +28,12 @@ fn main() { composition.commit().unwrap(); - let mut green = 0.5; - visual1.render_and_present_solid_frame(&composition, &[0., 0.2, 0.4, 1.]).unwrap(); - visual2.render_and_present_solid_frame(&composition, &[0., green, 0., 0.5]).unwrap(); + let mut rgba1 = [0., 0.2, 0.4, 1.]; + let mut rgba2 = [0., 0.5, 0., 0.5]; + visual1.render_and_present_solid_frame(&composition, &rgba1).unwrap(); + visual2.render_and_present_solid_frame(&composition, &rgba2).unwrap(); + + let mut clicks: u32 = 0; events_loop.run_forever(|event| { if let winit::Event::WindowEvent { event, .. } = event { @@ -53,11 +56,15 @@ fn main() { state: winit::ElementState::Pressed, .. } => { - green += 0.1; - green %= 1.; - visual2.render_and_present_solid_frame( - &composition, &[0., green, 0., 0.5] - ).unwrap(); + clicks += 1; + let (rgba, visual) = if clicks % 2 == 0 { + (&mut rgba1, &visual1) + } else { + (&mut rgba2, &visual2) + }; + rgba[1] += 0.1; + rgba[1] %= 1.; + visual.render_and_present_solid_frame(&composition, &rgba).unwrap(); } _ => {} } From 1842280545056377f1edcd8626b56b219a6eb21d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:42:38 +0100 Subject: [PATCH 29/73] Rewrite ComPtr::cast in terms of new_with_uuid --- src/com.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com.rs b/src/com.rs index be41211704..d60e84f0d7 100644 --- a/src/com.rs +++ b/src/com.rs @@ -96,9 +96,7 @@ impl ComPtr where T: Interface { /// Performs QueryInterface fun. pub fn cast(&self) -> HResult> where U: Interface { unsafe { - let mut obj = ptr::null_mut(); - self.as_unknown().QueryInterface(&U::uuidof(), &mut obj).to_result()?; - Ok(ComPtr::from_raw(obj as *mut U)) + ComPtr::::new_with_uuid(|uuid, ptr| self.as_unknown().QueryInterface(uuid, ptr)) } } } From c264c97bb2176a6a20301f188d94b7fe7bd71000 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:48:52 +0100 Subject: [PATCH 30/73] Keep a "render target view" together with each visual --- src/lib.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bfd643d3dc..6b286541e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,11 +123,20 @@ impl DirectComposition { ptr_ptr, ) })?; + let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { + swap_chain.GetBuffer(0, uuid, ptr_ptr) + })?; + let render_target_view = ComPtr::new_with(|ptr_ptr| { + self.d3d_device.CreateRenderTargetView( + as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, + ) + })?; + let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain }) + Ok(D3DVisual { visual, swap_chain, render_target_view }) } } } @@ -136,6 +145,7 @@ impl DirectComposition { pub struct D3DVisual { visual: ComPtr, swap_chain: ComPtr, + render_target_view: ComPtr, } impl D3DVisual { @@ -154,17 +164,8 @@ impl D3DVisual { pub fn render_and_present_solid_frame(&self, composition: &DirectComposition, rgba: &[f32; 4]) -> HResult<()> { unsafe { - let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - self.swap_chain.GetBuffer(0, uuid, ptr_ptr) - })?; - let render_target = ComPtr::new_with(|ptr_ptr| { - composition.d3d_device.CreateRenderTargetView( - as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, - ) - })?; - // FIXME: arbitrary D3D rendering here? - composition.d3d_device_context.ClearRenderTargetView(render_target.as_raw(), &rgba); + composition.d3d_device_context.ClearRenderTargetView(self.render_target_view.as_raw(), &rgba); self.swap_chain.Present(0, 0).to_result() } From 6a46a4b7d5afe0b35df89ea88e67a0ad30766f56 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 15:58:45 +0100 Subject: [PATCH 31/73] Make D3D stuff public, move rendering to the app --- src/lib.rs | 17 ++++------------- src/main.rs | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b286541e0..6a8d0c851c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,8 @@ pub mod com; pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, - d3d_device_context: ComPtr, + pub d3d_device_context: ComPtr, + composition_device: ComPtr, root_visual: ComPtr, @@ -144,8 +145,8 @@ impl DirectComposition { /// A DirectComposition "visual" configured for rendering with Direct3D. pub struct D3DVisual { visual: ComPtr, - swap_chain: ComPtr, - render_target_view: ComPtr, + pub swap_chain: ComPtr, + pub render_target_view: ComPtr, } impl D3DVisual { @@ -160,14 +161,4 @@ impl D3DVisual { self.visual.SetOffsetY_1(offset_y).to_result() } } - - pub fn render_and_present_solid_frame(&self, composition: &DirectComposition, rgba: &[f32; 4]) - -> HResult<()> { - unsafe { - // FIXME: arbitrary D3D rendering here? - composition.d3d_device_context.ClearRenderTargetView(self.render_target_view.as_raw(), &rgba); - - self.swap_chain.Present(0, 0).to_result() - } - } } diff --git a/src/main.rs b/src/main.rs index f22bdb6fb3..a323d446b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,8 @@ compile_error!("This demo only runs on Windows."); extern crate directcomposition; extern crate winit; -use directcomposition::DirectComposition; +use directcomposition::{DirectComposition, D3DVisual}; +use directcomposition::com::ToResult; use winit::os::windows::WindowExt; fn main() { @@ -30,8 +31,8 @@ fn main() { let mut rgba1 = [0., 0.2, 0.4, 1.]; let mut rgba2 = [0., 0.5, 0., 0.5]; - visual1.render_and_present_solid_frame(&composition, &rgba1).unwrap(); - visual2.render_and_present_solid_frame(&composition, &rgba2).unwrap(); + render_plain_rgba_frame(&composition, &visual1, &rgba1); + render_plain_rgba_frame(&composition, &visual2, &rgba2); let mut clicks: u32 = 0; @@ -64,7 +65,7 @@ fn main() { }; rgba[1] += 0.1; rgba[1] %= 1.; - visual.render_and_present_solid_frame(&composition, &rgba).unwrap(); + render_plain_rgba_frame(&composition, visual, rgba) } _ => {} } @@ -78,3 +79,13 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { DirectComposition::new(window.get_hwnd() as _).unwrap() } } + +fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { + unsafe { + composition.d3d_device_context.ClearRenderTargetView( + visual.render_target_view.as_raw(), &rgba, + ); + + visual.swap_chain.Present(0, 0).to_result().unwrap() + } +} From bb9fbbfc3efe144f4b2188ee2464fe5d44fe9f29 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 22:28:24 +0100 Subject: [PATCH 32/73] Add EGL bindings through the gl_generator crate --- Cargo.toml | 3 +++ build.rs | 15 +++++++++++++++ src/egl.rs | 16 ++++++++++++++++ src/lib.rs | 1 + 4 files changed, 35 insertions(+) create mode 100644 build.rs create mode 100644 src/egl.rs diff --git a/Cargo.toml b/Cargo.toml index 03bcaf672f..ceab2cce8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} # For the `main.rs` demo [dependencies] winit = "0.10" + +[build-dependencies] +gl_generator = "0.9.0" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000..90b4d5a5c3 --- /dev/null +++ b/build.rs @@ -0,0 +1,15 @@ +extern crate gl_generator; + +use gl_generator::{Registry, Api, Profile, Fallbacks, StaticStructGenerator}; +use std::env; +use std::fs::File; +use std::path::Path; + +fn main() { + let dest = env::var("OUT_DIR").unwrap(); + let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap(); + + Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, []) + .write_bindings(StaticStructGenerator, &mut file) + .unwrap(); +} diff --git a/src/egl.rs b/src/egl.rs new file mode 100644 index 0000000000..00c4e1898a --- /dev/null +++ b/src/egl.rs @@ -0,0 +1,16 @@ +use winapi; +use winapi::ctypes as libc; + +include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); + +// Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs +#[allow(non_camel_case_types)] pub type khronos_utime_nanoseconds_t = khronos_uint64_t; +#[allow(non_camel_case_types)] pub type khronos_uint64_t = u64; +#[allow(non_camel_case_types)] pub type khronos_ssize_t = libc::c_long; +pub type EGLint = i32; +pub type EGLNativeDisplayType = *const libc::c_void; +pub type EGLNativePixmapType = *const libc::c_void; +pub type EGLNativeWindowType = winapi::shared::windef::HWND; +pub type NativeDisplayType = EGLNativeDisplayType; +pub type NativePixmapType = EGLNativePixmapType; +pub type NativeWindowType = EGLNativeWindowType; diff --git a/src/lib.rs b/src/lib.rs index 6a8d0c851c..690279cd49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::IDCompositionVisual; pub mod com; +pub mod egl; pub struct DirectComposition { d3d_device: ComPtr, From d3803316b2a3fa797d05974156b44556ac00791f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 22:37:21 +0100 Subject: [PATCH 33/73] Remove obsolete comment --- src/com.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com.rs b/src/com.rs index d60e84f0d7..076880febc 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,5 +1,3 @@ -//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null - use std::fmt; use std::ops; use std::ptr; From 118d0b12a575b7b3ac5090b718d96bca8c066348 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Feb 2018 23:07:59 +0100 Subject: [PATCH 34/73] Link to ANGLE (but assume it is already built) --- build.rs | 36 +++++++++++++++++++++++++++++++----- src/lib.rs | 12 +++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/build.rs b/build.rs index 90b4d5a5c3..07f4ad2dd0 100644 --- a/build.rs +++ b/build.rs @@ -1,15 +1,41 @@ extern crate gl_generator; -use gl_generator::{Registry, Api, Profile, Fallbacks, StaticStructGenerator}; +use gl_generator::{Registry, Api, Profile, Fallbacks}; use std::env; use std::fs::File; -use std::path::Path; +use std::path::PathBuf; fn main() { - let dest = env::var("OUT_DIR").unwrap(); - let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap(); + // Building ANGLE is left as an exercise for the reader: + // https://chromium.googlesource.com/angle/angle/+/HEAD/doc/DevSetup.md + let relative_angle_dir = PathBuf::from("..").join("angle"); + let angle_build_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()) + .join(relative_angle_dir) + // Assume `gn gen out/Debug` or `gn gen out/Release` like in build instructions. + .join("out") + .join(if &env::var_os("PROFILE").unwrap() == "release" { "Release" } else { "Debug" }); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Assuming that OUT_DIR is something like `target/debug/build/directcomposition-*/out`, + // bin_dir is `target/debug` (where the final executable goes). + let bin_dir = out_dir.join("..").join("..").join(".."); + for name in &[ + "libEGL.dll.lib", + "libEGL.dll", + "libGLESv2.dll", + ] { + std::fs::copy(angle_build_dir.join(name), bin_dir.join(name)).unwrap(); + } + println!("cargo:rustc-link-search=native={}", bin_dir.display()); + println!("cargo:rustc-link-lib=dylib=libEGL.dll"); + + let bindings = "egl_bindings.rs"; Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, []) - .write_bindings(StaticStructGenerator, &mut file) + .write_bindings( + gl_generator::StaticStructGenerator, + &mut File::create(&out_dir.join(bindings)).unwrap() + ) .unwrap(); + } diff --git a/src/lib.rs b/src/lib.rs index 690279cd49..4215e534c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,12 +15,13 @@ use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::IDCompositionVisual; pub mod com; -pub mod egl; +mod egl; pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, pub d3d_device_context: ComPtr, + egl: egl::Egl, composition_device: ComPtr, root_visual: ComPtr, @@ -36,8 +37,6 @@ impl DirectComposition { /// /// `hwnd` must be a valid handle to a window. pub unsafe fn new(hwnd: HWND) -> HResult { - let mut feature_level_supported = 0; - let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( ptr::null_mut(), winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, @@ -52,7 +51,7 @@ impl DirectComposition { 0, winapi::um::d3d11::D3D11_SDK_VERSION, ptr_ptr, - &mut feature_level_supported, + &mut 0, ptr::null_mut(), ))?; @@ -86,14 +85,17 @@ impl DirectComposition { let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; composition_target.SetRoot(&*root_visual).to_result()?; + let egl = egl::Egl; Ok(DirectComposition { - d3d_device, dxgi_factory, d3d_device_context, + d3d_device, dxgi_factory, d3d_device_context, egl, composition_device, composition_target, root_visual, }) } /// Execute changes to the DirectComposition scene. pub fn commit(&self) -> HResult<()> { + self.egl.GetError(); // Dummy call to check that linking works. + unsafe { self.composition_device.Commit().to_result() } From fa95b1287909e6a8578aadcbd02111309b4684ad Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Feb 2018 22:11:54 +0100 Subject: [PATCH 35/73] Create and initialize an EGL display --- build.rs | 15 +++++++++------ src/egl.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 11 +++++++---- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/build.rs b/build.rs index 07f4ad2dd0..b4ccb7d74f 100644 --- a/build.rs +++ b/build.rs @@ -31,11 +31,14 @@ fn main() { println!("cargo:rustc-link-lib=dylib=libEGL.dll"); let bindings = "egl_bindings.rs"; - Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, []) - .write_bindings( - gl_generator::StaticStructGenerator, - &mut File::create(&out_dir.join(bindings)).unwrap() - ) - .unwrap(); + Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [ + "EGL_ANGLE_device_d3d", + "EGL_EXT_platform_base", + "EGL_EXT_platform_device", + ]).write_bindings( + gl_generator::StaticStructGenerator, + &mut File::create(&out_dir.join(bindings)).unwrap() + ) + .unwrap(); } diff --git a/src/egl.rs b/src/egl.rs index 00c4e1898a..6d4b827f56 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -1,16 +1,59 @@ +use std::ptr; use winapi; -use winapi::ctypes as libc; +use winapi::ctypes::{c_void, c_long}; +use winapi::um::d3d11::ID3D11Device; -include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); +impl Egl { + pub unsafe fn initialize(&self, d3d_device: *mut ID3D11Device) -> types::EGLDisplay { + let egl_device = eglCreateDeviceANGLE( + D3D11_DEVICE_ANGLE, + d3d_device, + ptr::null(), + ); + assert!(!egl_device.is_null()); + let attrib_list = [ + EXPERIMENTAL_PRESENT_PATH_ANGLE, + EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, + NONE, + ]; + let egl_display = self.GetPlatformDisplayEXT( + PLATFORM_DEVICE_EXT, + egl_device, + attrib_list.as_ptr() as *const i32, + ); + assert!(!egl_display.is_null()); + assert!(egl_display != NO_DISPLAY); + + self.Initialize(egl_display, ptr::null_mut(), ptr::null_mut()); + + egl_display + } +} // Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs #[allow(non_camel_case_types)] pub type khronos_utime_nanoseconds_t = khronos_uint64_t; #[allow(non_camel_case_types)] pub type khronos_uint64_t = u64; -#[allow(non_camel_case_types)] pub type khronos_ssize_t = libc::c_long; +#[allow(non_camel_case_types)] pub type khronos_ssize_t = c_long; pub type EGLint = i32; -pub type EGLNativeDisplayType = *const libc::c_void; -pub type EGLNativePixmapType = *const libc::c_void; +pub type EGLNativeDisplayType = *const c_void; +pub type EGLNativePixmapType = *const c_void; pub type EGLNativeWindowType = winapi::shared::windef::HWND; pub type NativeDisplayType = EGLNativeDisplayType; pub type NativePixmapType = EGLNativePixmapType; pub type NativeWindowType = EGLNativeWindowType; + +include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); + + +// Adapted from https://chromium.googlesource.com/angle/angle/+/master/include/EGL/eglext_angle.h +pub type EGLDeviceEXT = *mut c_void; +pub const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4; +pub const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9; + +extern "C" { + pub fn eglCreateDeviceANGLE( + device_type: types::EGLenum, + device: *mut ID3D11Device, + attrib_list: *const types::EGLAttrib, + ) -> EGLDeviceEXT; +} diff --git a/src/lib.rs b/src/lib.rs index 4215e534c1..4a436d6d6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,9 @@ pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, pub d3d_device_context: ComPtr, + egl: egl::Egl, + egl_display: egl::types::EGLDisplay, composition_device: ComPtr, root_visual: ComPtr, @@ -55,6 +57,9 @@ impl DirectComposition { ptr::null_mut(), ))?; + let egl = egl::Egl; + let egl_display = egl.initialize(d3d_device.as_raw()); + let dxgi_device = d3d_device.cast::()?; // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 @@ -85,17 +90,15 @@ impl DirectComposition { let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; composition_target.SetRoot(&*root_visual).to_result()?; - let egl = egl::Egl; Ok(DirectComposition { - d3d_device, dxgi_factory, d3d_device_context, egl, + d3d_device, dxgi_factory, d3d_device_context, + egl, egl_display, composition_device, composition_target, root_visual, }) } /// Execute changes to the DirectComposition scene. pub fn commit(&self) -> HResult<()> { - self.egl.GetError(); // Dummy call to check that linking works. - unsafe { self.composition_device.Commit().to_result() } From ac0ac79bf5af70114854becd61b86856b2552993 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Feb 2018 22:55:34 +0100 Subject: [PATCH 36/73] Create EGL configs and surfaces --- src/egl.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 7 ++++++- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/egl.rs b/src/egl.rs index 6d4b827f56..dc2e5e40f6 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -2,6 +2,7 @@ use std::ptr; use winapi; use winapi::ctypes::{c_void, c_long}; use winapi::um::d3d11::ID3D11Device; +use winapi::um::d3d11::ID3D11Texture2D; impl Egl { pub unsafe fn initialize(&self, d3d_device: *mut ID3D11Device) -> types::EGLDisplay { @@ -12,8 +13,7 @@ impl Egl { ); assert!(!egl_device.is_null()); let attrib_list = [ - EXPERIMENTAL_PRESENT_PATH_ANGLE, - EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, + EXPERIMENTAL_PRESENT_PATH_ANGLE, EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, NONE, ]; let egl_display = self.GetPlatformDisplayEXT( @@ -28,6 +28,53 @@ impl Egl { egl_display } + + // Adapted from + // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 + pub unsafe fn config(&self, display: types::EGLSurface) -> types::EGLConfig { + let mut configs = [ptr::null(); 64]; + let attrib_list = [ + SURFACE_TYPE, WINDOW_BIT, + RENDERABLE_TYPE, OPENGL_ES2_BIT, + RED_SIZE, 8, + GREEN_SIZE, 8, + BLUE_SIZE, 8, + ALPHA_SIZE, 8, + NONE, + ]; + let mut num_configs = 0; + let choose_config_result = self.ChooseConfig( + display, + attrib_list.as_ptr() as *const i32, + configs.as_mut_ptr(), + configs.len() as i32, + &mut num_configs, + ); + assert!(choose_config_result != FALSE); + assert!(num_configs >= 0); + // FIXME: pick a preferable config? + configs[0] + } + + pub unsafe fn create_surface(&self, display: types::EGLSurface, buffer: *const ID3D11Texture2D, + config: types::EGLConfig, width: u32, height: u32) + -> types::EGLSurface { + let attrib_list = [ + WIDTH, width, + HEIGHT, height, + FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, TRUE, + NONE, + ]; + let surface = self.CreatePbufferFromClientBuffer( + display, + D3D_TEXTURE_ANGLE, + buffer as types::EGLClientBuffer, + config, + attrib_list.as_ptr() as *const i32, + ); + assert!(!surface.is_null()); + surface + } } // Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs @@ -46,9 +93,11 @@ include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); // Adapted from https://chromium.googlesource.com/angle/angle/+/master/include/EGL/eglext_angle.h -pub type EGLDeviceEXT = *mut c_void; -pub const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4; -pub const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9; +type EGLDeviceEXT = *mut c_void; +const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4; +const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9; +const D3D_TEXTURE_ANGLE: types::EGLenum = 0x33A3; +const FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: types::EGLenum = 0x33A6; extern "C" { pub fn eglCreateDeviceANGLE( diff --git a/src/lib.rs b/src/lib.rs index 4a436d6d6d..72e9e464ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ pub struct DirectComposition { egl: egl::Egl, egl_display: egl::types::EGLDisplay, + egl_config: egl::types::EGLConfig, composition_device: ComPtr, root_visual: ComPtr, @@ -59,6 +60,7 @@ impl DirectComposition { let egl = egl::Egl; let egl_display = egl.initialize(d3d_device.as_raw()); + let egl_config = egl.config(egl_display); let dxgi_device = d3d_device.cast::()?; @@ -92,7 +94,7 @@ impl DirectComposition { Ok(DirectComposition { d3d_device, dxgi_factory, d3d_device_context, - egl, egl_display, + egl, egl_display, egl_config, composition_device, composition_target, root_visual, }) } @@ -133,6 +135,9 @@ impl DirectComposition { let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { swap_chain.GetBuffer(0, uuid, ptr_ptr) })?; + let egl_surface = self.egl.create_surface( + self.egl_display, &*back_buffer, self.egl_config, width, height, + ); let render_target_view = ComPtr::new_with(|ptr_ptr| { self.d3d_device.CreateRenderTargetView( as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, From 8553788cb631b4a180aae146a009f6bb7c914d3a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 10:20:15 +0100 Subject: [PATCH 37/73] Create EGL contexts and call MakeCurrent() --- src/egl.rs | 15 +++++++++++++++ src/lib.rs | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/egl.rs b/src/egl.rs index dc2e5e40f6..40557fc140 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -56,6 +56,21 @@ impl Egl { configs[0] } + pub unsafe fn create_context(&self, display: types::EGLSurface, config: types::EGLConfig) + -> types::EGLContext { + let attrib_list = [ + NONE, + ]; + let context = self.CreateContext( + display, + config, + NO_CONTEXT, + attrib_list.as_ptr() as *const i32, + ); + assert!(!context.is_null()); + context + } + pub unsafe fn create_surface(&self, display: types::EGLSurface, buffer: *const ID3D11Texture2D, config: types::EGLConfig, width: u32, height: u32) -> types::EGLSurface { diff --git a/src/lib.rs b/src/lib.rs index 72e9e464ec..d7fc553733 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,7 @@ impl DirectComposition { let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { swap_chain.GetBuffer(0, uuid, ptr_ptr) })?; + let egl_context = self.egl.create_context(self.egl_display, self.egl_config); let egl_surface = self.egl.create_surface( self.egl_display, &*back_buffer, self.egl_config, width, height, ); @@ -148,7 +149,7 @@ impl DirectComposition { visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, render_target_view }) + Ok(D3DVisual { visual, swap_chain, render_target_view, egl_context, egl_surface }) } } } @@ -158,6 +159,8 @@ pub struct D3DVisual { visual: ComPtr, pub swap_chain: ComPtr, pub render_target_view: ComPtr, + egl_context: egl::types::EGLContext, + egl_surface: egl::types::EGLSurface, } impl D3DVisual { @@ -172,4 +175,16 @@ impl D3DVisual { self.visual.SetOffsetY_1(offset_y).to_result() } } + + pub fn make_current(&self, composition: &DirectComposition) { + unsafe { + let make_current_result = composition.egl.MakeCurrent( + composition.egl_display, + self.egl_surface, + self.egl_surface, + self.egl_context, + ); + assert!(make_current_result == egl::TRUE); + } + } } From e7b96144fa39d5caa9d8d525a840b73e5a5f1073 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 10:27:28 +0100 Subject: [PATCH 38/73] Use gleam --- Cargo.toml | 1 + src/lib.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ceab2cce8a..8418265aa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} # For the `main.rs` demo [dependencies] +gleam = "0.4" winit = "0.10" [build-dependencies] diff --git a/src/lib.rs b/src/lib.rs index d7fc553733..889d97c82d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,11 @@ #![cfg(windows)] extern crate winapi; +extern crate gleam; use com::{ComPtr, ToResult, HResult, as_ptr}; use std::ptr; +use std::rc::Rc; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; use winapi::shared::dxgi1_2::IDXGIFactory2; use winapi::shared::minwindef::{TRUE, FALSE}; @@ -25,6 +27,7 @@ pub struct DirectComposition { egl: egl::Egl, egl_display: egl::types::EGLDisplay, egl_config: egl::types::EGLConfig, + pub gleam: Rc, composition_device: ComPtr, root_visual: ComPtr, @@ -61,6 +64,9 @@ impl DirectComposition { let egl = egl::Egl; let egl_display = egl.initialize(d3d_device.as_raw()); let egl_config = egl.config(egl_display); + let gleam = gleam::gl::GlesFns::load_with(|name| { + egl.GetProcAddress(name.as_ptr() as _) as *const _ as _ + }); let dxgi_device = d3d_device.cast::()?; @@ -94,7 +100,7 @@ impl DirectComposition { Ok(DirectComposition { d3d_device, dxgi_factory, d3d_device_context, - egl, egl_display, egl_config, + egl, egl_display, egl_config, gleam, composition_device, composition_target, root_visual, }) } From be24ac2118765cd0497a58a5248d1f66028f5350 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 10:37:33 +0100 Subject: [PATCH 39/73] =?UTF-8?q?Attempt=20to=20use=20OpenGL=20through=20g?= =?UTF-8?q?leam=20+=20ANGLE=20+=20EGL=E2=80=A6=20but=20the=20window=20stay?= =?UTF-8?q?s=20blank?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 4 +++- src/main.rs | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 889d97c82d..eed44ed13f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ extern crate winapi; extern crate gleam; use com::{ComPtr, ToResult, HResult, as_ptr}; +use std::ffi::CString; use std::ptr; use std::rc::Rc; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; @@ -65,7 +66,8 @@ impl DirectComposition { let egl_display = egl.initialize(d3d_device.as_raw()); let egl_config = egl.config(egl_display); let gleam = gleam::gl::GlesFns::load_with(|name| { - egl.GetProcAddress(name.as_ptr() as _) as *const _ as _ + let name = CString::new(name.as_bytes()).unwrap(); + egl.GetProcAddress(name.as_ptr()) as *const _ as _ }); let dxgi_device = d3d_device.cast::()?; diff --git a/src/main.rs b/src/main.rs index a323d446b3..933b6dab7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,11 +81,9 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { + visual.make_current(composition); + composition.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); unsafe { - composition.d3d_device_context.ClearRenderTargetView( - visual.render_target_view.as_raw(), &rgba, - ); - visual.swap_chain.Present(0, 0).to_result().unwrap() } } From fede9295f00f7e0b69c1cf82a00d7b16c9764a53 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 13:40:58 +0100 Subject: [PATCH 40/73] Add Visual::present --- src/com.rs | 2 +- src/lib.rs | 6 ++++++ src/main.rs | 5 +---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/com.rs b/src/com.rs index 076880febc..11b5368ddd 100644 --- a/src/com.rs +++ b/src/com.rs @@ -43,7 +43,7 @@ pub fn as_ptr(x: &T) -> *mut T { x as *const T as _ } -/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs +/// Forked from #[derive(PartialEq, Debug)] pub struct ComPtr(*mut T) where T: Interface; diff --git a/src/lib.rs b/src/lib.rs index eed44ed13f..c8ab6e332e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,4 +195,10 @@ impl D3DVisual { assert!(make_current_result == egl::TRUE); } } + + pub fn present(&self) { + unsafe { + self.swap_chain.Present(0, 0).to_result().unwrap() + } + } } diff --git a/src/main.rs b/src/main.rs index 933b6dab7c..ee74f88506 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,6 @@ extern crate directcomposition; extern crate winit; use directcomposition::{DirectComposition, D3DVisual}; -use directcomposition::com::ToResult; use winit::os::windows::WindowExt; fn main() { @@ -83,7 +82,5 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { visual.make_current(composition); composition.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); - unsafe { - visual.swap_chain.Present(0, 0).to_result().unwrap() - } + visual.present(); } From 68d8fefd1f896c265fc46a75ad140fad52e4ce0b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 13:41:20 +0100 Subject: [PATCH 41/73] Remove public APIs for rendering with Direct3D --- src/lib.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c8ab6e332e..f00db3cb63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,6 @@ use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; use winapi::shared::dxgi1_2::IDXGIFactory2; use winapi::shared::minwindef::{TRUE, FALSE}; use winapi::shared::windef::HWND; -use winapi::shared::winerror::S_OK; use winapi::um::d3d11::ID3D11Device; use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; @@ -23,7 +22,6 @@ mod egl; pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, - pub d3d_device_context: ComPtr, egl: egl::Egl, egl_display: egl::types::EGLDisplay, @@ -81,11 +79,6 @@ impl DirectComposition { adapter.GetParent(uuid, ptr_ptr) })?; - let d3d_device_context = ComPtr::new_with(|ptr_ptr| { - d3d_device.GetImmediateContext(ptr_ptr); - S_OK - })?; - // Create the DirectComposition device object. let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) @@ -101,7 +94,7 @@ impl DirectComposition { composition_target.SetRoot(&*root_visual).to_result()?; Ok(DirectComposition { - d3d_device, dxgi_factory, d3d_device_context, + d3d_device, dxgi_factory, egl, egl_display, egl_config, gleam, composition_device, composition_target, root_visual, }) @@ -147,17 +140,12 @@ impl DirectComposition { let egl_surface = self.egl.create_surface( self.egl_display, &*back_buffer, self.egl_config, width, height, ); - let render_target_view = ComPtr::new_with(|ptr_ptr| { - self.d3d_device.CreateRenderTargetView( - as_ptr(&back_buffer), ptr::null_mut(), ptr_ptr, - ) - })?; let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, render_target_view, egl_context, egl_surface }) + Ok(D3DVisual { visual, swap_chain, egl_context, egl_surface }) } } } @@ -165,8 +153,7 @@ impl DirectComposition { /// A DirectComposition "visual" configured for rendering with Direct3D. pub struct D3DVisual { visual: ComPtr, - pub swap_chain: ComPtr, - pub render_target_view: ComPtr, + swap_chain: ComPtr, egl_context: egl::types::EGLContext, egl_surface: egl::types::EGLSurface, } From 6327ed12b39a9441a9b32e56adb0ea5c64113f10 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 14:27:01 +0100 Subject: [PATCH 42/73] Check for EGL errors more systematically --- src/egl.rs | 127 +++++++++++++++++++++++++++++++--------------------- src/lib.rs | 8 +--- src/main.rs | 1 + 3 files changed, 79 insertions(+), 57 deletions(-) diff --git a/src/egl.rs b/src/egl.rs index 40557fc140..51e9770c26 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -1,94 +1,119 @@ +use std::os::raw::{c_void, c_long}; use std::ptr; use winapi; -use winapi::ctypes::{c_void, c_long}; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; +fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint { + unsafe { + &*(slice.as_ptr() as *const EGLint) + } +} + +macro_rules! attributes { + ($( $key: expr => $value: expr, )*) => { + cast_attributes(&[ + $( $key, $value, )* + NONE, + ]) + } +} impl Egl { + fn check_error(&self) { + unsafe { + let error = self.GetError() as types::EGLenum; + assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS); + } + } + + fn check_ptr(&self, p: *const c_void) -> *const c_void { + self.check_error(); + assert!(!p.is_null()); + p + } + + fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void { + self.check_error(); + assert!(!p.is_null()); + p + } + + fn check_bool(&self, bool_result: types::EGLBoolean) { + self.check_error(); + assert_eq!(bool_result, TRUE); + } + pub unsafe fn initialize(&self, d3d_device: *mut ID3D11Device) -> types::EGLDisplay { - let egl_device = eglCreateDeviceANGLE( + let egl_device = self.check_mut_ptr(eglCreateDeviceANGLE( D3D11_DEVICE_ANGLE, d3d_device, ptr::null(), - ); - assert!(!egl_device.is_null()); - let attrib_list = [ - EXPERIMENTAL_PRESENT_PATH_ANGLE, EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, - NONE, - ]; - let egl_display = self.GetPlatformDisplayEXT( + )); + let egl_display = self.check_ptr(self.GetPlatformDisplayEXT( PLATFORM_DEVICE_EXT, egl_device, - attrib_list.as_ptr() as *const i32, - ); - assert!(!egl_display.is_null()); - assert!(egl_display != NO_DISPLAY); - - self.Initialize(egl_display, ptr::null_mut(), ptr::null_mut()); + attributes! [ + EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, + ], + )); + self.check_bool(self.Initialize(egl_display, ptr::null_mut(), ptr::null_mut())); egl_display } // Adapted from // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 - pub unsafe fn config(&self, display: types::EGLSurface) -> types::EGLConfig { + pub unsafe fn config(&self, display: types::EGLDisplay) -> types::EGLConfig { let mut configs = [ptr::null(); 64]; - let attrib_list = [ - SURFACE_TYPE, WINDOW_BIT, - RENDERABLE_TYPE, OPENGL_ES2_BIT, - RED_SIZE, 8, - GREEN_SIZE, 8, - BLUE_SIZE, 8, - ALPHA_SIZE, 8, - NONE, - ]; let mut num_configs = 0; - let choose_config_result = self.ChooseConfig( + self.check_bool(self.ChooseConfig( display, - attrib_list.as_ptr() as *const i32, + attributes! [ + SURFACE_TYPE => WINDOW_BIT, + RENDERABLE_TYPE => OPENGL_ES2_BIT, + RED_SIZE => 8, + GREEN_SIZE => 8, + BLUE_SIZE => 8, + ALPHA_SIZE => 8, + ], configs.as_mut_ptr(), configs.len() as i32, &mut num_configs, - ); - assert!(choose_config_result != FALSE); + )); assert!(num_configs >= 0); // FIXME: pick a preferable config? configs[0] } - pub unsafe fn create_context(&self, display: types::EGLSurface, config: types::EGLConfig) + pub unsafe fn create_context(&self, display: types::EGLDisplay, config: types::EGLConfig) -> types::EGLContext { - let attrib_list = [ - NONE, - ]; - let context = self.CreateContext( + self.check_ptr(self.CreateContext( display, config, NO_CONTEXT, - attrib_list.as_ptr() as *const i32, - ); - assert!(!context.is_null()); - context + attributes![], + )) } - pub unsafe fn create_surface(&self, display: types::EGLSurface, buffer: *const ID3D11Texture2D, + pub unsafe fn create_surface(&self, display: types::EGLDisplay, buffer: *const ID3D11Texture2D, config: types::EGLConfig, width: u32, height: u32) -> types::EGLSurface { - let attrib_list = [ - WIDTH, width, - HEIGHT, height, - FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, TRUE, - NONE, - ]; - let surface = self.CreatePbufferFromClientBuffer( + self.check_ptr(self.CreatePbufferFromClientBuffer( display, D3D_TEXTURE_ANGLE, buffer as types::EGLClientBuffer, config, - attrib_list.as_ptr() as *const i32, - ); - assert!(!surface.is_null()); - surface + attributes! [ + WIDTH => width, + HEIGHT => height, + FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE, + ], + )) + } + + pub unsafe fn make_current(&self, display: types::EGLDisplay, surface: types::EGLSurface, + context: types::EGLContext) { + self.check_bool(self.MakeCurrent(display, surface, surface, context)) } } @@ -115,7 +140,7 @@ const D3D_TEXTURE_ANGLE: types::EGLenum = 0x33A3; const FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: types::EGLenum = 0x33A6; extern "C" { - pub fn eglCreateDeviceANGLE( + fn eglCreateDeviceANGLE( device_type: types::EGLenum, device: *mut ID3D11Device, attrib_list: *const types::EGLAttrib, diff --git a/src/lib.rs b/src/lib.rs index f00db3cb63..79335e2f59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,13 +173,9 @@ impl D3DVisual { pub fn make_current(&self, composition: &DirectComposition) { unsafe { - let make_current_result = composition.egl.MakeCurrent( - composition.egl_display, - self.egl_surface, - self.egl_surface, - self.egl_context, + composition.egl.make_current( + composition.egl_display, self.egl_surface, self.egl_context, ); - assert!(make_current_result == egl::TRUE); } } diff --git a/src/main.rs b/src/main.rs index ee74f88506..1ee2439f5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,5 +82,6 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { visual.make_current(composition); composition.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); + assert_eq!(composition.gleam.get_error(), 0); visual.present(); } From 959a56a9ef32c0d7da2bc4ec72a3f2fd73552e16 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 15:04:04 +0100 Subject: [PATCH 43/73] More well-defined public API for EGL things --- src/egl.rs | 128 +++++++++++++++++++++++++++++++---------------------- src/lib.rs | 30 ++++--------- 2 files changed, 84 insertions(+), 74 deletions(-) diff --git a/src/egl.rs b/src/egl.rs index 51e9770c26..54c48b97ad 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -1,9 +1,16 @@ +use std::ffi::CString; use std::os::raw::{c_void, c_long}; use std::ptr; use winapi; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; +pub struct SharedEglThings { + functions: Egl, + display: types::EGLDisplay, + config: types::EGLConfig, +} + fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint { unsafe { &*(slice.as_ptr() as *const EGLint) @@ -18,55 +25,30 @@ macro_rules! attributes { ]) } } -impl Egl { - fn check_error(&self) { - unsafe { - let error = self.GetError() as types::EGLenum; - assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS); - } - } - - fn check_ptr(&self, p: *const c_void) -> *const c_void { - self.check_error(); - assert!(!p.is_null()); - p - } - - fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void { - self.check_error(); - assert!(!p.is_null()); - p - } - fn check_bool(&self, bool_result: types::EGLBoolean) { - self.check_error(); - assert_eq!(bool_result, TRUE); - } +impl SharedEglThings { + pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Self { + let functions = Egl; - pub unsafe fn initialize(&self, d3d_device: *mut ID3D11Device) -> types::EGLDisplay { - let egl_device = self.check_mut_ptr(eglCreateDeviceANGLE( + let device = functions.check_mut_ptr(eglCreateDeviceANGLE( D3D11_DEVICE_ANGLE, d3d_device, ptr::null(), )); - let egl_display = self.check_ptr(self.GetPlatformDisplayEXT( + let display = functions.check_ptr(functions.GetPlatformDisplayEXT( PLATFORM_DEVICE_EXT, - egl_device, + device, attributes! [ EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, ], )); - self.check_bool(self.Initialize(egl_display, ptr::null_mut(), ptr::null_mut())); + functions.check_bool(functions.Initialize(display, ptr::null_mut(), ptr::null_mut())); - egl_display - } - - // Adapted from - // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 - pub unsafe fn config(&self, display: types::EGLDisplay) -> types::EGLConfig { + // Adapted from + // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 let mut configs = [ptr::null(); 64]; let mut num_configs = 0; - self.check_bool(self.ChooseConfig( + functions.check_bool(functions.ChooseConfig( display, attributes! [ SURFACE_TYPE => WINDOW_BIT, @@ -82,38 +64,80 @@ impl Egl { )); assert!(num_configs >= 0); // FIXME: pick a preferable config? - configs[0] + let config = configs[0]; + + SharedEglThings { functions, display, config } } - pub unsafe fn create_context(&self, display: types::EGLDisplay, config: types::EGLConfig) - -> types::EGLContext { - self.check_ptr(self.CreateContext( - display, - config, + pub fn get_proc_address(&self, name: &str) -> *const c_void { + let name = CString::new(name.as_bytes()).unwrap(); + unsafe { + self.functions.GetProcAddress(name.as_ptr()) as *const _ as _ + } + } +} + +pub struct PerVisualEglThings { + context: types::EGLContext, + surface: types::EGLSurface, +} + +impl PerVisualEglThings { + pub unsafe fn new(shared: &SharedEglThings, buffer: *const ID3D11Texture2D, + width: u32, height: u32) + -> Self { + let context = shared.functions.check_ptr(shared.functions.CreateContext( + shared.display, + shared.config, NO_CONTEXT, attributes![], - )) - } + )); - pub unsafe fn create_surface(&self, display: types::EGLDisplay, buffer: *const ID3D11Texture2D, - config: types::EGLConfig, width: u32, height: u32) - -> types::EGLSurface { - self.check_ptr(self.CreatePbufferFromClientBuffer( - display, + let surface = shared.functions.check_ptr(shared.functions.CreatePbufferFromClientBuffer( + shared.display, D3D_TEXTURE_ANGLE, buffer as types::EGLClientBuffer, - config, + shared.config, attributes! [ WIDTH => width, HEIGHT => height, FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE, ], + )); + + PerVisualEglThings { context, surface } + } + + pub unsafe fn make_current(&self, shared: &SharedEglThings) { + shared.functions.check_bool(shared.functions.MakeCurrent( + shared.display, self.surface, self.surface, self.context )) } +} + +impl Egl { + fn check_error(&self) { + unsafe { + let error = self.GetError() as types::EGLenum; + assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS); + } + } - pub unsafe fn make_current(&self, display: types::EGLDisplay, surface: types::EGLSurface, - context: types::EGLContext) { - self.check_bool(self.MakeCurrent(display, surface, surface, context)) + fn check_ptr(&self, p: *const c_void) -> *const c_void { + self.check_error(); + assert!(!p.is_null()); + p + } + + fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void { + self.check_error(); + assert!(!p.is_null()); + p + } + + fn check_bool(&self, bool_result: types::EGLBoolean) { + self.check_error(); + assert_eq!(bool_result, TRUE); } } diff --git a/src/lib.rs b/src/lib.rs index 79335e2f59..2726509af0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ extern crate winapi; extern crate gleam; use com::{ComPtr, ToResult, HResult, as_ptr}; -use std::ffi::CString; use std::ptr; use std::rc::Rc; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; @@ -23,9 +22,7 @@ pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, - egl: egl::Egl, - egl_display: egl::types::EGLDisplay, - egl_config: egl::types::EGLConfig, + egl: egl::SharedEglThings, pub gleam: Rc, composition_device: ComPtr, @@ -60,13 +57,8 @@ impl DirectComposition { ptr::null_mut(), ))?; - let egl = egl::Egl; - let egl_display = egl.initialize(d3d_device.as_raw()); - let egl_config = egl.config(egl_display); - let gleam = gleam::gl::GlesFns::load_with(|name| { - let name = CString::new(name.as_bytes()).unwrap(); - egl.GetProcAddress(name.as_ptr()) as *const _ as _ - }); + let egl = egl::SharedEglThings::new(d3d_device.as_raw()); + let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name)); let dxgi_device = d3d_device.cast::()?; @@ -95,7 +87,7 @@ impl DirectComposition { Ok(DirectComposition { d3d_device, dxgi_factory, - egl, egl_display, egl_config, gleam, + egl, gleam, composition_device, composition_target, root_visual, }) } @@ -136,16 +128,13 @@ impl DirectComposition { let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { swap_chain.GetBuffer(0, uuid, ptr_ptr) })?; - let egl_context = self.egl.create_context(self.egl_display, self.egl_config); - let egl_surface = self.egl.create_surface( - self.egl_display, &*back_buffer, self.egl_config, width, height, - ); + let egl = egl::PerVisualEglThings::new(&self.egl, &*back_buffer, width, height); let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, egl_context, egl_surface }) + Ok(D3DVisual { visual, swap_chain, egl }) } } } @@ -154,8 +143,7 @@ impl DirectComposition { pub struct D3DVisual { visual: ComPtr, swap_chain: ComPtr, - egl_context: egl::types::EGLContext, - egl_surface: egl::types::EGLSurface, + egl: egl::PerVisualEglThings, } impl D3DVisual { @@ -173,9 +161,7 @@ impl D3DVisual { pub fn make_current(&self, composition: &DirectComposition) { unsafe { - composition.egl.make_current( - composition.egl_display, self.egl_surface, self.egl_context, - ); + self.egl.make_current(&composition.egl) } } From 567f82c96fa980020e502fcd32ce5011944da4c0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 15:12:30 +0100 Subject: [PATCH 44/73] Keep a reference to shared EGL things next to per-visual things --- src/egl.rs | 21 +++++++++++++-------- src/lib.rs | 10 ++++------ src/main.rs | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/egl.rs b/src/egl.rs index 54c48b97ad..5ddc9c629d 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -1,6 +1,7 @@ use std::ffi::CString; use std::os::raw::{c_void, c_long}; use std::ptr; +use std::rc::Rc; use winapi; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; @@ -27,7 +28,7 @@ macro_rules! attributes { } impl SharedEglThings { - pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Self { + pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc { let functions = Egl; let device = functions.check_mut_ptr(eglCreateDeviceANGLE( @@ -66,7 +67,7 @@ impl SharedEglThings { // FIXME: pick a preferable config? let config = configs[0]; - SharedEglThings { functions, display, config } + Rc::new(SharedEglThings { functions, display, config }) } pub fn get_proc_address(&self, name: &str) -> *const c_void { @@ -78,14 +79,16 @@ impl SharedEglThings { } pub struct PerVisualEglThings { + shared: Rc, context: types::EGLContext, surface: types::EGLSurface, } impl PerVisualEglThings { - pub unsafe fn new(shared: &SharedEglThings, buffer: *const ID3D11Texture2D, + pub unsafe fn new(shared: Rc, buffer: *const ID3D11Texture2D, width: u32, height: u32) -> Self { + let shared = shared.clone(); let context = shared.functions.check_ptr(shared.functions.CreateContext( shared.display, shared.config, @@ -105,13 +108,15 @@ impl PerVisualEglThings { ], )); - PerVisualEglThings { context, surface } + PerVisualEglThings { shared, context, surface } } - pub unsafe fn make_current(&self, shared: &SharedEglThings) { - shared.functions.check_bool(shared.functions.MakeCurrent( - shared.display, self.surface, self.surface, self.context - )) + pub fn make_current(&self) { + unsafe { + self.shared.functions.check_bool(self.shared.functions.MakeCurrent( + self.shared.display, self.surface, self.surface, self.context + )) + } } } diff --git a/src/lib.rs b/src/lib.rs index 2726509af0..8f63ad25b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ pub struct DirectComposition { d3d_device: ComPtr, dxgi_factory: ComPtr, - egl: egl::SharedEglThings, + egl: Rc, pub gleam: Rc, composition_device: ComPtr, @@ -128,7 +128,7 @@ impl DirectComposition { let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { swap_chain.GetBuffer(0, uuid, ptr_ptr) })?; - let egl = egl::PerVisualEglThings::new(&self.egl, &*back_buffer, width, height); + let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height); let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; visual.SetContent(&*****swap_chain).to_result()?; @@ -159,10 +159,8 @@ impl D3DVisual { } } - pub fn make_current(&self, composition: &DirectComposition) { - unsafe { - self.egl.make_current(&composition.egl) - } + pub fn make_current(&self) { + self.egl.make_current() } pub fn present(&self) { diff --git a/src/main.rs b/src/main.rs index 1ee2439f5b..aef56e0a19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,7 +80,7 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { - visual.make_current(composition); + visual.make_current(); composition.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); assert_eq!(composition.gleam.get_error(), 0); visual.present(); From f3c21a399e142cfb602554808a7c79bbc2bceb6b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 17:50:11 +0100 Subject: [PATCH 45/73] Destroy EGL things in Drop --- src/egl.rs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/egl.rs b/src/egl.rs index 5ddc9c629d..d4b87ce1e2 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -8,6 +8,7 @@ use winapi::um::d3d11::ID3D11Texture2D; pub struct SharedEglThings { functions: Egl, + device: EGLDeviceEXT, display: types::EGLDisplay, config: types::EGLConfig, } @@ -67,7 +68,7 @@ impl SharedEglThings { // FIXME: pick a preferable config? let config = configs[0]; - Rc::new(SharedEglThings { functions, display, config }) + Rc::new(SharedEglThings { functions, device, display, config }) } pub fn get_proc_address(&self, name: &str) -> *const c_void { @@ -78,6 +79,14 @@ impl SharedEglThings { } } +impl Drop for SharedEglThings { + fn drop(&mut self) { + unsafe { + self.functions.check_bool(eglReleaseDeviceANGLE(self.device)) + } + } +} + pub struct PerVisualEglThings { shared: Rc, context: types::EGLContext, @@ -114,12 +123,31 @@ impl PerVisualEglThings { pub fn make_current(&self) { unsafe { self.shared.functions.check_bool(self.shared.functions.MakeCurrent( - self.shared.display, self.surface, self.surface, self.context + self.shared.display, self.surface, self.surface, self.context, )) } } } +impl Drop for PerVisualEglThings { + fn drop(&mut self) { + unsafe { + if self.shared.functions.GetCurrentContext() == self.context { + // release the current context without assigning a new one + self.shared.functions.check_bool(self.shared.functions.MakeCurrent( + self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT, + )) + } + self.shared.functions.check_bool(self.shared.functions.DestroyContext( + self.shared.display, self.context, + )); + self.shared.functions.check_bool(self.shared.functions.DestroySurface( + self.shared.display, self.surface, + )); + } + } +} + impl Egl { fn check_error(&self) { unsafe { @@ -174,4 +202,6 @@ extern "C" { device: *mut ID3D11Device, attrib_list: *const types::EGLAttrib, ) -> EGLDeviceEXT; + + fn eglReleaseDeviceANGLE(device: EGLDeviceEXT) -> types::EGLBoolean; } From c35ccfcdb1ccbe6d32dd3eeeb981381cd2d6253b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:21:15 +0100 Subject: [PATCH 46/73] Keep the DXGI back buffer object alive, in case that matters --- src/egl.rs | 1 + src/lib.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/egl.rs b/src/egl.rs index d4b87ce1e2..32898f9d52 100644 --- a/src/egl.rs +++ b/src/egl.rs @@ -82,6 +82,7 @@ impl SharedEglThings { impl Drop for SharedEglThings { fn drop(&mut self) { unsafe { + // FIXME does EGLDisplay or EGLConfig need clean up? How? self.functions.check_bool(eglReleaseDeviceANGLE(self.device)) } } diff --git a/src/lib.rs b/src/lib.rs index 8f63ad25b3..13ba24f468 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,7 @@ impl DirectComposition { visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, egl }) + Ok(D3DVisual { visual, swap_chain, back_buffer, egl }) } } } @@ -143,6 +143,10 @@ impl DirectComposition { pub struct D3DVisual { visual: ComPtr, swap_chain: ComPtr, + + #[allow(unused)] // FIXME: does this need to be kept alive? + back_buffer: ComPtr, + egl: egl::PerVisualEglThings, } From 3c3611830d7b28c7d315cdc0fd303d15e8e06663 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:22:05 +0100 Subject: [PATCH 47/73] Call glFinish() before IDXGISwapChain::Present --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 13ba24f468..ba4e56a377 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,12 +129,13 @@ impl DirectComposition { swap_chain.GetBuffer(0, uuid, ptr_ptr) })?; let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height); + let gleam = self.gleam.clone(); let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, back_buffer, egl }) + Ok(D3DVisual { visual, swap_chain, back_buffer, egl, gleam }) } } } @@ -148,6 +149,7 @@ pub struct D3DVisual { back_buffer: ComPtr, egl: egl::PerVisualEglThings, + pub gleam: Rc, } impl D3DVisual { @@ -168,6 +170,7 @@ impl D3DVisual { } pub fn present(&self) { + self.gleam.finish(); unsafe { self.swap_chain.Present(0, 0).to_result().unwrap() } From 023022a2727a76b94a452c0bf976bf61821ace47 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:22:40 +0100 Subject: [PATCH 48/73] Demo add: access gleam through visuals --- src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index aef56e0a19..dd89009b7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,8 +30,8 @@ fn main() { let mut rgba1 = [0., 0.2, 0.4, 1.]; let mut rgba2 = [0., 0.5, 0., 0.5]; - render_plain_rgba_frame(&composition, &visual1, &rgba1); - render_plain_rgba_frame(&composition, &visual2, &rgba2); + render_plain_rgba_frame(&visual1, &rgba1); + render_plain_rgba_frame(&visual2, &rgba2); let mut clicks: u32 = 0; @@ -64,7 +64,7 @@ fn main() { }; rgba[1] += 0.1; rgba[1] %= 1.; - render_plain_rgba_frame(&composition, visual, rgba) + render_plain_rgba_frame(visual, rgba) } _ => {} } @@ -79,9 +79,9 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } } -fn render_plain_rgba_frame(composition: &DirectComposition, visual: &D3DVisual, rgba: &[f32; 4]) { +fn render_plain_rgba_frame(visual: &D3DVisual, rgba: &[f32; 4]) { visual.make_current(); - composition.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); - assert_eq!(composition.gleam.get_error(), 0); + visual.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); + assert_eq!(visual.gleam.get_error(), 0); visual.present(); } From 0b45cf731817403fe763d50acc57e092e6f97a2e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:42:11 +0100 Subject: [PATCH 49/73] Rename the crate with a dash --- Cargo.toml | 2 +- src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8418265aa3..15ec434928 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "directcomposition" +name = "direct-composition" version = "0.1.0" authors = ["Simon Sapin "] diff --git a/src/main.rs b/src/main.rs index dd89009b7b..85085d2189 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ #[cfg(not(windows))] compile_error!("This demo only runs on Windows."); -extern crate directcomposition; +extern crate direct_composition; extern crate winit; -use directcomposition::{DirectComposition, D3DVisual}; +use direct_composition::{DirectComposition, D3DVisual}; use winit::os::windows::WindowExt; fn main() { From 75901d635cf022252a8dd4df1b663012d1343ec2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:45:16 +0100 Subject: [PATCH 50/73] Move to a subdirectory, for merging into the webrender repo --- .gitignore => direct-composition/.gitignore | 0 Cargo.toml => direct-composition/Cargo.toml | 0 build.rs => direct-composition/build.rs | 2 +- {src => direct-composition/src}/com.rs | 0 {src => direct-composition/src}/egl.rs | 0 {src => direct-composition/src}/lib.rs | 0 {src => direct-composition/src}/main.rs | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename .gitignore => direct-composition/.gitignore (100%) rename Cargo.toml => direct-composition/Cargo.toml (100%) rename build.rs => direct-composition/build.rs (95%) rename {src => direct-composition/src}/com.rs (100%) rename {src => direct-composition/src}/egl.rs (100%) rename {src => direct-composition/src}/lib.rs (100%) rename {src => direct-composition/src}/main.rs (100%) diff --git a/.gitignore b/direct-composition/.gitignore similarity index 100% rename from .gitignore rename to direct-composition/.gitignore diff --git a/Cargo.toml b/direct-composition/Cargo.toml similarity index 100% rename from Cargo.toml rename to direct-composition/Cargo.toml diff --git a/build.rs b/direct-composition/build.rs similarity index 95% rename from build.rs rename to direct-composition/build.rs index b4ccb7d74f..51ee4ca9db 100644 --- a/build.rs +++ b/direct-composition/build.rs @@ -8,7 +8,7 @@ use std::path::PathBuf; fn main() { // Building ANGLE is left as an exercise for the reader: // https://chromium.googlesource.com/angle/angle/+/HEAD/doc/DevSetup.md - let relative_angle_dir = PathBuf::from("..").join("angle"); + let relative_angle_dir = PathBuf::from("..").join("..").join("angle"); let angle_build_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()) .join(relative_angle_dir) diff --git a/src/com.rs b/direct-composition/src/com.rs similarity index 100% rename from src/com.rs rename to direct-composition/src/com.rs diff --git a/src/egl.rs b/direct-composition/src/egl.rs similarity index 100% rename from src/egl.rs rename to direct-composition/src/egl.rs diff --git a/src/lib.rs b/direct-composition/src/lib.rs similarity index 100% rename from src/lib.rs rename to direct-composition/src/lib.rs diff --git a/src/main.rs b/direct-composition/src/main.rs similarity index 100% rename from src/main.rs rename to direct-composition/src/main.rs From 70937d6fadac4c254c8fac7740799af45a725c66 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Feb 2018 23:49:15 +0100 Subject: [PATCH 51/73] Add direct-composition to the webrender workspace. --- Cargo.lock | 37 +++++++++++++++++++++++-------------- Cargo.toml | 1 + 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88fb59c3d7..87b1e9b01b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,7 +113,7 @@ name = "cgl" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -278,6 +278,16 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "direct-composition" +version = "0.1.0" +dependencies = [ + "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dlib" version = "0.4.0" @@ -436,28 +446,27 @@ name = "gl_generator" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "khronos_api 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "khronos_api 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gl_generator" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "khronos_api 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "khronos_api 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gleam" -version = "0.4.20" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gl_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -580,7 +589,7 @@ dependencies = [ [[package]] name = "khronos_api" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1248,7 +1257,7 @@ dependencies = [ "euclid 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1360,7 +1369,7 @@ dependencies = [ "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "font-loader 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1486,8 +1495,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e41945ba23db3bf51b24756d73d81acb4f28d85c3dccc32c6fae904438c25f" "checksum gl_generator 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3e0220a68b8875b5a311fe67ee3b76d3d9b719a92277aff0ec5bb5e7b0ec1" -"checksum gl_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5c19cde55637681450c92f7a05ea16c78e2b6d0587e601ec1ebdab6960854b" -"checksum gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "959c818d9bbe9f7b7db55dce0bc44673c4da4f4ee122536c40550f984c3b8017" +"checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" +"checksum gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a7f5351837630a7dd0cd6d7976de547929f9fabd381b9d5ac35f82e90be2" "checksum glutin 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25c70edeb14581cb6edb486eb15d55b41815fade469308474932549fd9703fe5" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" @@ -1499,7 +1508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum jpeg-decoder 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0dfe27a6c0dabd772d0f9b9f8701c4ca12c4d1eebcadf2be1f6f70396f6a1434" "checksum json 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7eb285e773498f9473a6e2255feffe95db9c55579c7931a6db83c9e02a4673" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum khronos_api 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d867c645cfeb8a7fec503731679eac03ac11b7105aa5a71cb8f8ee5271636add" +"checksum khronos_api 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ef23fcc4059260c5936f638c9805ebfc87cb172fa6661d130cba7f97d58f55" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b" diff --git a/Cargo.toml b/Cargo.toml index baabc9ad4b..f67115098c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] license = "MPL-2.0" members = [ + "direct-composition", "webrender", "webrender_api", "wrench", From 9c11d75e0485b3d5a8644826bc9d0c3b009dec6d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 10:06:02 +0100 Subject: [PATCH 52/73] =?UTF-8?q?Turns=20out=20ClearColor=20doesn=E2=80=99?= =?UTF-8?q?t=20clear,=20it=20just=20sets=20the=20color=E2=80=A6=20Thanks?= =?UTF-8?q?=20Sotaro!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/servo/webrender/pull/2458#issuecomment-369121264 --- direct-composition/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 85085d2189..39bbebd0df 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -2,6 +2,7 @@ compile_error!("This demo only runs on Windows."); extern crate direct_composition; +extern crate gleam; extern crate winit; use direct_composition::{DirectComposition, D3DVisual}; @@ -82,6 +83,7 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { fn render_plain_rgba_frame(visual: &D3DVisual, rgba: &[f32; 4]) { visual.make_current(); visual.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); + visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); assert_eq!(visual.gleam.get_error(), 0); visual.present(); } From 9d99193c6ffd4066aff0068ff19296b54ec4cf73 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 10:07:35 +0100 Subject: [PATCH 53/73] =?UTF-8?q?Keeping=20a=20reference=20to=20back=5Fbuf?= =?UTF-8?q?fer=20isn=E2=80=99t=20necessary.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- direct-composition/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index ba4e56a377..c26fbcd388 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -135,7 +135,7 @@ impl DirectComposition { visual.SetContent(&*****swap_chain).to_result()?; self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; - Ok(D3DVisual { visual, swap_chain, back_buffer, egl, gleam }) + Ok(D3DVisual { visual, swap_chain, egl, gleam }) } } } @@ -144,10 +144,6 @@ impl DirectComposition { pub struct D3DVisual { visual: ComPtr, swap_chain: ComPtr, - - #[allow(unused)] // FIXME: does this need to be kept alive? - back_buffer: ComPtr, - egl: egl::PerVisualEglThings, pub gleam: Rc, } From 872f356e32eaebe2adcbd917a16e3883a888c020 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 14:44:25 +0100 Subject: [PATCH 54/73] Switch to gl_generator::StaticGenerator --- direct-composition/build.rs | 2 +- direct-composition/src/egl.rs | 90 +++++++++++++++-------------------- direct-composition/src/lib.rs | 2 +- 3 files changed, 40 insertions(+), 54 deletions(-) diff --git a/direct-composition/build.rs b/direct-composition/build.rs index 51ee4ca9db..6c5ce4b2bd 100644 --- a/direct-composition/build.rs +++ b/direct-composition/build.rs @@ -36,7 +36,7 @@ fn main() { "EGL_EXT_platform_base", "EGL_EXT_platform_device", ]).write_bindings( - gl_generator::StaticStructGenerator, + gl_generator::StaticGenerator, &mut File::create(&out_dir.join(bindings)).unwrap() ) .unwrap(); diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index 32898f9d52..0d41d7b960 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -6,8 +6,14 @@ use winapi; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; +pub fn get_proc_address(name: &str) -> *const c_void { + let name = CString::new(name.as_bytes()).unwrap(); + unsafe { + GetProcAddress(name.as_ptr()) as *const _ as _ + } +} + pub struct SharedEglThings { - functions: Egl, device: EGLDeviceEXT, display: types::EGLDisplay, config: types::EGLConfig, @@ -30,27 +36,25 @@ macro_rules! attributes { impl SharedEglThings { pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc { - let functions = Egl; - - let device = functions.check_mut_ptr(eglCreateDeviceANGLE( + let device = check_mut_ptr(eglCreateDeviceANGLE( D3D11_DEVICE_ANGLE, d3d_device, ptr::null(), )); - let display = functions.check_ptr(functions.GetPlatformDisplayEXT( + let display = check_ptr(GetPlatformDisplayEXT( PLATFORM_DEVICE_EXT, device, attributes! [ EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, ], )); - functions.check_bool(functions.Initialize(display, ptr::null_mut(), ptr::null_mut())); + check_bool(Initialize(display, ptr::null_mut(), ptr::null_mut())); // Adapted from // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 let mut configs = [ptr::null(); 64]; let mut num_configs = 0; - functions.check_bool(functions.ChooseConfig( + check_bool(ChooseConfig( display, attributes! [ SURFACE_TYPE => WINDOW_BIT, @@ -68,14 +72,7 @@ impl SharedEglThings { // FIXME: pick a preferable config? let config = configs[0]; - Rc::new(SharedEglThings { functions, device, display, config }) - } - - pub fn get_proc_address(&self, name: &str) -> *const c_void { - let name = CString::new(name.as_bytes()).unwrap(); - unsafe { - self.functions.GetProcAddress(name.as_ptr()) as *const _ as _ - } + Rc::new(SharedEglThings { device, display, config }) } } @@ -83,7 +80,7 @@ impl Drop for SharedEglThings { fn drop(&mut self) { unsafe { // FIXME does EGLDisplay or EGLConfig need clean up? How? - self.functions.check_bool(eglReleaseDeviceANGLE(self.device)) + check_bool(eglReleaseDeviceANGLE(self.device)) } } } @@ -98,15 +95,14 @@ impl PerVisualEglThings { pub unsafe fn new(shared: Rc, buffer: *const ID3D11Texture2D, width: u32, height: u32) -> Self { - let shared = shared.clone(); - let context = shared.functions.check_ptr(shared.functions.CreateContext( + let context = check_ptr(CreateContext( shared.display, shared.config, NO_CONTEXT, attributes![], )); - let surface = shared.functions.check_ptr(shared.functions.CreatePbufferFromClientBuffer( + let surface = check_ptr(CreatePbufferFromClientBuffer( shared.display, D3D_TEXTURE_ANGLE, buffer as types::EGLClientBuffer, @@ -123,9 +119,7 @@ impl PerVisualEglThings { pub fn make_current(&self) { unsafe { - self.shared.functions.check_bool(self.shared.functions.MakeCurrent( - self.shared.display, self.surface, self.surface, self.context, - )) + check_bool(MakeCurrent(self.shared.display, self.surface, self.surface, self.context)) } } } @@ -133,46 +127,38 @@ impl PerVisualEglThings { impl Drop for PerVisualEglThings { fn drop(&mut self) { unsafe { - if self.shared.functions.GetCurrentContext() == self.context { + if GetCurrentContext() == self.context { // release the current context without assigning a new one - self.shared.functions.check_bool(self.shared.functions.MakeCurrent( - self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT, - )) + check_bool(MakeCurrent(self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT)) } - self.shared.functions.check_bool(self.shared.functions.DestroyContext( - self.shared.display, self.context, - )); - self.shared.functions.check_bool(self.shared.functions.DestroySurface( - self.shared.display, self.surface, - )); + check_bool(DestroyContext(self.shared.display, self.context)); + check_bool(DestroySurface(self.shared.display, self.surface)); } } } -impl Egl { - fn check_error(&self) { - unsafe { - let error = self.GetError() as types::EGLenum; - assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS); - } +fn check_error() { + unsafe { + let error = GetError() as types::EGLenum; + assert_eq!(error, SUCCESS, "0x{:x} != 0x{:x}", error, SUCCESS); } +} - fn check_ptr(&self, p: *const c_void) -> *const c_void { - self.check_error(); - assert!(!p.is_null()); - p - } +fn check_ptr(p: *const c_void) -> *const c_void { + check_error(); + assert!(!p.is_null()); + p +} - fn check_mut_ptr(&self, p: *mut c_void) -> *mut c_void { - self.check_error(); - assert!(!p.is_null()); - p - } +fn check_mut_ptr(p: *mut c_void) -> *mut c_void { + check_error(); + assert!(!p.is_null()); + p +} - fn check_bool(&self, bool_result: types::EGLBoolean) { - self.check_error(); - assert_eq!(bool_result, TRUE); - } +fn check_bool(bool_result: types::EGLBoolean) { + check_error(); + assert_eq!(bool_result, TRUE); } // Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index c26fbcd388..c128874d24 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -58,7 +58,7 @@ impl DirectComposition { ))?; let egl = egl::SharedEglThings::new(d3d_device.as_raw()); - let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name)); + let gleam = gleam::gl::GlesFns::load_with(egl::get_proc_address); let dxgi_device = d3d_device.cast::()?; From 9238751257f2041a7ceac7e2f3ae0a67aaf62afe Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 14:55:21 +0100 Subject: [PATCH 55/73] Add a private Check trait for EGL return values --- direct-composition/src/egl.rs | 65 ++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index 0d41d7b960..d98ab53ff5 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -36,25 +36,25 @@ macro_rules! attributes { impl SharedEglThings { pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc { - let device = check_mut_ptr(eglCreateDeviceANGLE( + let device = eglCreateDeviceANGLE( D3D11_DEVICE_ANGLE, d3d_device, ptr::null(), - )); - let display = check_ptr(GetPlatformDisplayEXT( + ).check(); + let display = GetPlatformDisplayEXT( PLATFORM_DEVICE_EXT, device, attributes! [ EXPERIMENTAL_PRESENT_PATH_ANGLE => EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, ], - )); - check_bool(Initialize(display, ptr::null_mut(), ptr::null_mut())); + ).check(); + Initialize(display, ptr::null_mut(), ptr::null_mut()).check(); // Adapted from // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#635 let mut configs = [ptr::null(); 64]; let mut num_configs = 0; - check_bool(ChooseConfig( + ChooseConfig( display, attributes! [ SURFACE_TYPE => WINDOW_BIT, @@ -67,7 +67,7 @@ impl SharedEglThings { configs.as_mut_ptr(), configs.len() as i32, &mut num_configs, - )); + ).check(); assert!(num_configs >= 0); // FIXME: pick a preferable config? let config = configs[0]; @@ -80,7 +80,7 @@ impl Drop for SharedEglThings { fn drop(&mut self) { unsafe { // FIXME does EGLDisplay or EGLConfig need clean up? How? - check_bool(eglReleaseDeviceANGLE(self.device)) + eglReleaseDeviceANGLE(self.device).check(); } } } @@ -95,14 +95,14 @@ impl PerVisualEglThings { pub unsafe fn new(shared: Rc, buffer: *const ID3D11Texture2D, width: u32, height: u32) -> Self { - let context = check_ptr(CreateContext( + let context = CreateContext( shared.display, shared.config, NO_CONTEXT, attributes![], - )); + ).check(); - let surface = check_ptr(CreatePbufferFromClientBuffer( + let surface = CreatePbufferFromClientBuffer( shared.display, D3D_TEXTURE_ANGLE, buffer as types::EGLClientBuffer, @@ -112,14 +112,14 @@ impl PerVisualEglThings { HEIGHT => height, FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE => TRUE, ], - )); + ).check(); PerVisualEglThings { shared, context, surface } } pub fn make_current(&self) { unsafe { - check_bool(MakeCurrent(self.shared.display, self.surface, self.surface, self.context)) + MakeCurrent(self.shared.display, self.surface, self.surface, self.context).check(); } } } @@ -129,10 +129,10 @@ impl Drop for PerVisualEglThings { unsafe { if GetCurrentContext() == self.context { // release the current context without assigning a new one - check_bool(MakeCurrent(self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT)) + MakeCurrent(self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT).check(); } - check_bool(DestroyContext(self.shared.display, self.context)); - check_bool(DestroySurface(self.shared.display, self.surface)); + DestroyContext(self.shared.display, self.context).check(); + DestroySurface(self.shared.display, self.surface).check(); } } } @@ -144,21 +144,32 @@ fn check_error() { } } -fn check_ptr(p: *const c_void) -> *const c_void { - check_error(); - assert!(!p.is_null()); - p +trait Check { + fn check(self) -> Self; } -fn check_mut_ptr(p: *mut c_void) -> *mut c_void { - check_error(); - assert!(!p.is_null()); - p +impl Check for *const c_void { + fn check(self) -> Self { + check_error(); + assert!(!self.is_null()); + self + } } -fn check_bool(bool_result: types::EGLBoolean) { - check_error(); - assert_eq!(bool_result, TRUE); +impl Check for *mut c_void { + fn check(self) -> Self { + check_error(); + assert!(!self.is_null()); + self + } +} + +impl Check for types::EGLBoolean { + fn check(self) -> Self { + check_error(); + assert_eq!(self, TRUE); + self + } } // Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs From a3b8abaf28d949796b123f236c1d278aa3cc5914 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 15:00:10 +0100 Subject: [PATCH 56/73] Move to-be-implemented EGL config choice to a function --- direct-composition/src/egl.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index d98ab53ff5..5c35806a37 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -68,14 +68,20 @@ impl SharedEglThings { configs.len() as i32, &mut num_configs, ).check(); - assert!(num_configs >= 0); - // FIXME: pick a preferable config? - let config = configs[0]; + let config = pick_config(&configs[..num_configs as usize]); Rc::new(SharedEglThings { device, display, config }) } } +fn pick_config(configs: &[types::EGLConfig]) -> types::EGLConfig { + // FIXME: better criteria to make this choice? + // Firefox uses GetConfigAttrib to find a config that has the requested r/g/b/a sizes + // https://searchfox.org/mozilla-central/rev/056a4057/gfx/gl/GLContextProviderEGL.cpp#662-685 + + configs[0] +} + impl Drop for SharedEglThings { fn drop(&mut self) { unsafe { From 41d42832507ad2cf9fb9181f62a11a0bad212975 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 15:01:01 +0100 Subject: [PATCH 57/73] eglDestroyContext/Surface already do the right thing for the current context. https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglDestroyContext.xhtml > If the EGL rendering context context is not current to any thread, > eglDestroyContext destroys it immediately. > Otherwise, context is destroyed when it becomes not current to any thread. --- direct-composition/src/egl.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index 5c35806a37..5d262be2af 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -133,10 +133,6 @@ impl PerVisualEglThings { impl Drop for PerVisualEglThings { fn drop(&mut self) { unsafe { - if GetCurrentContext() == self.context { - // release the current context without assigning a new one - MakeCurrent(self.shared.display, NO_SURFACE, NO_SURFACE, NO_CONTEXT).check(); - } DestroyContext(self.shared.display, self.context).check(); DestroySurface(self.shared.display, self.surface).check(); } From 6c8928db1c4ed8c64313d2ed5804effbef299ed6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 15:08:36 +0100 Subject: [PATCH 58/73] Panic in the library on COM errors --- direct-composition/src/com.rs | 50 +++++++++++-------------------- direct-composition/src/lib.rs | 54 +++++++++++++++++----------------- direct-composition/src/main.rs | 20 ++++++------- 3 files changed, 54 insertions(+), 70 deletions(-) diff --git a/direct-composition/src/com.rs b/direct-composition/src/com.rs index 11b5368ddd..55c2ffc614 100644 --- a/direct-composition/src/com.rs +++ b/direct-composition/src/com.rs @@ -1,4 +1,3 @@ -use std::fmt; use std::ops; use std::ptr; use winapi::Interface; @@ -8,39 +7,24 @@ use winapi::shared::winerror::HRESULT; use winapi::shared::winerror::SUCCEEDED; use winapi::um::unknwnbase::IUnknown; -pub type HResult = Result; - -/// An error code returned by a Windows API. -pub struct HResultError(HRESULT); - -impl fmt::Debug for HResultError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "0x{:08X}", self.0 as u32) - } -} - -impl From for HResultError { - fn from(h: HRESULT) -> Self { - HResultError(h) - } +pub fn as_ptr(x: &T) -> *mut T { + x as *const T as _ } -pub trait ToResult: Sized { - fn to_result(self) -> HResult<()>; +pub trait CheckHResult { + fn check_hresult(self); } -impl ToResult for HRESULT { - fn to_result(self) -> HResult<()> { - if SUCCEEDED(self) { - Ok(()) - } else { - Err(HResultError(self)) +impl CheckHResult for HRESULT { + fn check_hresult(self) { + if !SUCCEEDED(self) { + panic_com(self) } } } -pub fn as_ptr(x: &T) -> *mut T { - x as *const T as _ +fn panic_com(hresult: HRESULT) -> ! { + panic!("COM error 0x{:08X}", hresult as u32) } /// Forked from @@ -58,26 +42,26 @@ impl ComPtr where T: Interface { /// For use with APIs that take an interface UUID and /// "return" a new COM object through a `*mut *mut c_void` out-parameter. - pub unsafe fn new_with_uuid(f: F) -> HResult + pub unsafe fn new_with_uuid(f: F) -> Self where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT { Self::new_with(|ptr| f(&T::uuidof(), ptr as _)) } /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter. - pub unsafe fn new_with(f: F) -> HResult + pub unsafe fn new_with(f: F) -> Self where F: FnOnce(*mut *mut T) -> HRESULT { let mut ptr = ptr::null_mut(); - let status = f(&mut ptr); - if SUCCEEDED(status) { - Ok(ComPtr::from_raw(ptr)) + let hresult = f(&mut ptr); + if SUCCEEDED(hresult) { + ComPtr::from_raw(ptr) } else { if !ptr.is_null() { let ptr = ptr as *mut IUnknown; (*ptr).Release(); } - Err(HResultError(status)) + panic_com(hresult) } } @@ -92,7 +76,7 @@ impl ComPtr where T: Interface { } /// Performs QueryInterface fun. - pub fn cast(&self) -> HResult> where U: Interface { + pub fn cast(&self) -> ComPtr where U: Interface { unsafe { ComPtr::::new_with_uuid(|uuid, ptr| self.as_unknown().QueryInterface(uuid, ptr)) } diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index c128874d24..b9812f3542 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -3,7 +3,7 @@ extern crate winapi; extern crate gleam; -use com::{ComPtr, ToResult, HResult, as_ptr}; +use com::{ComPtr, CheckHResult, as_ptr}; use std::ptr; use std::rc::Rc; use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1; @@ -15,7 +15,7 @@ use winapi::um::dcomp::IDCompositionDevice; use winapi::um::dcomp::IDCompositionTarget; use winapi::um::dcomp::IDCompositionVisual; -pub mod com; +mod com; mod egl; pub struct DirectComposition { @@ -38,7 +38,7 @@ impl DirectComposition { /// # Safety /// /// `hwnd` must be a valid handle to a window. - pub unsafe fn new(hwnd: HWND) -> HResult { + pub unsafe fn new(hwnd: HWND) -> Self { let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice( ptr::null_mut(), winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE, @@ -55,51 +55,51 @@ impl DirectComposition { ptr_ptr, &mut 0, ptr::null_mut(), - ))?; + )); let egl = egl::SharedEglThings::new(d3d_device.as_raw()); let gleam = gleam::gl::GlesFns::load_with(egl::get_proc_address); - let dxgi_device = d3d_device.cast::()?; + let dxgi_device = d3d_device.cast::(); // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1 // “Because you can create a Direct3D device without creating a swap chain, // you might need to retrieve the factory that is used to create the device // in order to create a swap chain.” - let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?; + let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr)); let dxgi_factory = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { adapter.GetParent(uuid, ptr_ptr) - })?; + }); // Create the DirectComposition device object. let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) - })?; + }); // Create the composition target object based on the // specified application window. let composition_target = ComPtr::new_with(|ptr_ptr| { composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr) - })?; + }); - let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?; - composition_target.SetRoot(&*root_visual).to_result()?; + let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr)); + composition_target.SetRoot(&*root_visual).check_hresult(); - Ok(DirectComposition { + DirectComposition { d3d_device, dxgi_factory, egl, gleam, composition_device, composition_target, root_visual, - }) + } } /// Execute changes to the DirectComposition scene. - pub fn commit(&self) -> HResult<()> { + pub fn commit(&self) { unsafe { - self.composition_device.Commit().to_result() + self.composition_device.Commit().check_hresult() } } - pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult { + pub fn create_d3d_visual(&self, width: u32, height: u32) -> D3DVisual { unsafe { let desc = DXGI_SWAP_CHAIN_DESC1 { Width: width, @@ -124,18 +124,18 @@ impl DirectComposition { ptr::null_mut(), ptr_ptr, ) - })?; + }); let back_buffer = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { swap_chain.GetBuffer(0, uuid, ptr_ptr) - })?; + }); let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height); let gleam = self.gleam.clone(); - let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?; - visual.SetContent(&*****swap_chain).to_result()?; - self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?; + let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr)); + visual.SetContent(&*****swap_chain).check_hresult(); + self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).check_hresult(); - Ok(D3DVisual { visual, swap_chain, egl, gleam }) + D3DVisual { visual, swap_chain, egl, gleam } } } } @@ -149,15 +149,15 @@ pub struct D3DVisual { } impl D3DVisual { - pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> { + pub fn set_offset_x(&self, offset_x: f32) { unsafe { - self.visual.SetOffsetX_1(offset_x).to_result() + self.visual.SetOffsetX_1(offset_x).check_hresult() } } - pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> { + pub fn set_offset_y(&self, offset_y: f32) { unsafe { - self.visual.SetOffsetY_1(offset_y).to_result() + self.visual.SetOffsetY_1(offset_y).check_hresult() } } @@ -168,7 +168,7 @@ impl D3DVisual { pub fn present(&self) { self.gleam.finish(); unsafe { - self.swap_chain.Present(0, 0).to_result().unwrap() + self.swap_chain.Present(0, 0).check_hresult() } } } diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 39bbebd0df..2cf96ad868 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -18,16 +18,16 @@ fn main() { let composition = direct_composition_from_window(&window); - let visual1 = composition.create_d3d_visual(300, 200).unwrap(); - visual1.set_offset_x(100.).unwrap(); - visual1.set_offset_y(50.).unwrap(); + let visual1 = composition.create_d3d_visual(300, 200); + visual1.set_offset_x(100.); + visual1.set_offset_y(50.); - let visual2 = composition.create_d3d_visual(400, 300).unwrap(); + let visual2 = composition.create_d3d_visual(400, 300); let mut offset_y = 100.; - visual2.set_offset_x(200.).unwrap(); - visual2.set_offset_y(offset_y).unwrap(); + visual2.set_offset_x(200.); + visual2.set_offset_y(offset_y); - composition.commit().unwrap(); + composition.commit(); let mut rgba1 = [0., 0.2, 0.4, 1.]; let mut rgba2 = [0., 0.5, 0., 0.5]; @@ -49,8 +49,8 @@ fn main() { }; offset_y = (offset_y - 10. * dy).max(0.).min(468.); - visual2.set_offset_y(offset_y).unwrap(); - composition.commit().unwrap(); + visual2.set_offset_y(offset_y); + composition.commit(); } winit::WindowEvent::MouseInput { button: winit::MouseButton::Left, @@ -76,7 +76,7 @@ fn main() { fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { unsafe { - DirectComposition::new(window.get_hwnd() as _).unwrap() + DirectComposition::new(window.get_hwnd() as _) } } From 3dd81172fe5497896fc78f068e9cc3aa9c8d88dd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 15:23:36 +0100 Subject: [PATCH 59/73] Use tuples for RGBA colors --- direct-composition/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 2cf96ad868..c872dd6480 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -29,8 +29,8 @@ fn main() { composition.commit(); - let mut rgba1 = [0., 0.2, 0.4, 1.]; - let mut rgba2 = [0., 0.5, 0., 0.5]; + let mut rgba1 = (0., 0.2, 0.4, 1.); + let mut rgba2 = (0., 0.5, 0., 0.5); render_plain_rgba_frame(&visual1, &rgba1); render_plain_rgba_frame(&visual2, &rgba2); @@ -63,8 +63,8 @@ fn main() { } else { (&mut rgba2, &visual2) }; - rgba[1] += 0.1; - rgba[1] %= 1.; + rgba.1 += 0.1; + rgba.1 %= 1.; render_plain_rgba_frame(visual, rgba) } _ => {} @@ -80,9 +80,9 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } } -fn render_plain_rgba_frame(visual: &D3DVisual, rgba: &[f32; 4]) { +fn render_plain_rgba_frame(visual: &D3DVisual, &(r, g, b, a): &(f32, f32, f32, f32)) { visual.make_current(); - visual.gleam.clear_color(rgba[0], rgba[1], rgba[2], rgba[3]); + visual.gleam.clear_color(r, g, b, a); visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); assert_eq!(visual.gleam.get_error(), 0); visual.present(); From 6c71656561eaadb0a8d0b21d5023b51dad381082 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 17:25:28 +0100 Subject: [PATCH 60/73] One same EGL context can be used with multiple surfaces. --- direct-composition/src/egl.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index 5d262be2af..f34eaa7a24 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -17,6 +17,7 @@ pub struct SharedEglThings { device: EGLDeviceEXT, display: types::EGLDisplay, config: types::EGLConfig, + context: types::EGLContext, } fn cast_attributes(slice: &[types::EGLenum]) -> &EGLint { @@ -70,7 +71,9 @@ impl SharedEglThings { ).check(); let config = pick_config(&configs[..num_configs as usize]); - Rc::new(SharedEglThings { device, display, config }) + let context = CreateContext(display, config, NO_CONTEXT, attributes![]).check(); + + Rc::new(SharedEglThings { device, display, config, context }) } } @@ -86,6 +89,7 @@ impl Drop for SharedEglThings { fn drop(&mut self) { unsafe { // FIXME does EGLDisplay or EGLConfig need clean up? How? + DestroyContext(self.display, self.context).check(); eglReleaseDeviceANGLE(self.device).check(); } } @@ -93,7 +97,6 @@ impl Drop for SharedEglThings { pub struct PerVisualEglThings { shared: Rc, - context: types::EGLContext, surface: types::EGLSurface, } @@ -101,13 +104,6 @@ impl PerVisualEglThings { pub unsafe fn new(shared: Rc, buffer: *const ID3D11Texture2D, width: u32, height: u32) -> Self { - let context = CreateContext( - shared.display, - shared.config, - NO_CONTEXT, - attributes![], - ).check(); - let surface = CreatePbufferFromClientBuffer( shared.display, D3D_TEXTURE_ANGLE, @@ -120,12 +116,12 @@ impl PerVisualEglThings { ], ).check(); - PerVisualEglThings { shared, context, surface } + PerVisualEglThings { shared, surface } } pub fn make_current(&self) { unsafe { - MakeCurrent(self.shared.display, self.surface, self.surface, self.context).check(); + MakeCurrent(self.shared.display, self.surface, self.surface, self.shared.context).check(); } } } @@ -133,7 +129,6 @@ impl PerVisualEglThings { impl Drop for PerVisualEglThings { fn drop(&mut self) { unsafe { - DestroyContext(self.shared.display, self.context).check(); DestroySurface(self.shared.display, self.surface).check(); } } From f94280664915db23db6b7fa53924df7c9ceeaca5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 18:09:52 +0100 Subject: [PATCH 61/73] Initialize WebRender in the DComp demo app --- Cargo.lock | 1 + direct-composition/Cargo.toml | 1 + direct-composition/src/egl.rs | 8 +++++++- direct-composition/src/main.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 87b1e9b01b..9607298f26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,6 +284,7 @@ version = "0.1.0" dependencies = [ "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender 0.57.0", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index 15ec434928..b689742d01 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -9,6 +9,7 @@ winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} # For the `main.rs` demo [dependencies] gleam = "0.4" +webrender = {path = "../webrender"} winit = "0.10" [build-dependencies] diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index f34eaa7a24..19526b1ccd 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -71,7 +71,13 @@ impl SharedEglThings { ).check(); let config = pick_config(&configs[..num_configs as usize]); - let context = CreateContext(display, config, NO_CONTEXT, attributes![]).check(); + let context = CreateContext( + display, config, NO_CONTEXT, + attributes![ + CONTEXT_CLIENT_VERSION => 3, + ] + ).check(); + MakeCurrent(display, NO_SURFACE, NO_SURFACE, context).check(); Rc::new(SharedEglThings { device, display, config, context }) } diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index c872dd6480..1c3012e8c1 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -3,6 +3,7 @@ compile_error!("This demo only runs on Windows."); extern crate direct_composition; extern crate gleam; +extern crate webrender; extern crate winit; use direct_composition::{DirectComposition, D3DVisual}; @@ -18,6 +19,12 @@ fn main() { let composition = direct_composition_from_window(&window); + let (renderer, _api_sender) = webrender::Renderer::new( + composition.gleam.clone(), + Box::new(Notifier { events_proxy: events_loop.create_proxy() }), + webrender::RendererOptions::default(), + ).unwrap(); + let visual1 = composition.create_d3d_visual(300, 200); visual1.set_offset_x(100.); visual1.set_offset_y(50.); @@ -72,6 +79,8 @@ fn main() { } winit::ControlFlow::Continue }); + + renderer.deinit() } fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { @@ -87,3 +96,22 @@ fn render_plain_rgba_frame(visual: &D3DVisual, &(r, g, b, a): &(f32, f32, f32, f assert_eq!(visual.gleam.get_error(), 0); visual.present(); } + +#[derive(Clone)] +struct Notifier { + events_proxy: winit::EventsLoopProxy, +} + +impl webrender::api::RenderNotifier for Notifier { + fn clone(&self) -> Box { + Box::new(Clone::clone(self)) + } + + fn wake_up(&self) { + let _ = self.events_proxy.wakeup(); + } + + fn new_document_ready(&self, _: webrender::api::DocumentId, _: bool, _: bool) { + self.wake_up(); + } +} From eb5de061098334d42f1f7d86641e984045721032 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 19:11:31 +0100 Subject: [PATCH 62/73] Rename D3DVisual to AngleVisual --- direct-composition/src/lib.rs | 8 ++++---- direct-composition/src/main.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index b9812f3542..50341945fa 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -99,7 +99,7 @@ impl DirectComposition { } } - pub fn create_d3d_visual(&self, width: u32, height: u32) -> D3DVisual { + pub fn create_angle_visual(&self, width: u32, height: u32) -> AngleVisual { unsafe { let desc = DXGI_SWAP_CHAIN_DESC1 { Width: width, @@ -135,20 +135,20 @@ impl DirectComposition { visual.SetContent(&*****swap_chain).check_hresult(); self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).check_hresult(); - D3DVisual { visual, swap_chain, egl, gleam } + AngleVisual { visual, swap_chain, egl, gleam } } } } /// A DirectComposition "visual" configured for rendering with Direct3D. -pub struct D3DVisual { +pub struct AngleVisual { visual: ComPtr, swap_chain: ComPtr, egl: egl::PerVisualEglThings, pub gleam: Rc, } -impl D3DVisual { +impl AngleVisual { pub fn set_offset_x(&self, offset_x: f32) { unsafe { self.visual.SetOffsetX_1(offset_x).check_hresult() diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 1c3012e8c1..8d47d94384 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -6,7 +6,7 @@ extern crate gleam; extern crate webrender; extern crate winit; -use direct_composition::{DirectComposition, D3DVisual}; +use direct_composition::{DirectComposition, AngleVisual}; use winit::os::windows::WindowExt; fn main() { @@ -25,11 +25,11 @@ fn main() { webrender::RendererOptions::default(), ).unwrap(); - let visual1 = composition.create_d3d_visual(300, 200); + let visual1 = composition.create_angle_visual(300, 200); visual1.set_offset_x(100.); visual1.set_offset_y(50.); - let visual2 = composition.create_d3d_visual(400, 300); + let visual2 = composition.create_angle_visual(400, 300); let mut offset_y = 100.; visual2.set_offset_x(200.); visual2.set_offset_y(offset_y); @@ -89,7 +89,7 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } } -fn render_plain_rgba_frame(visual: &D3DVisual, &(r, g, b, a): &(f32, f32, f32, f32)) { +fn render_plain_rgba_frame(visual: &AngleVisual, &(r, g, b, a): &(f32, f32, f32, f32)) { visual.make_current(); visual.gleam.clear_color(r, g, b, a); visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); From cc4980f21cc5792204f94631b90c4d24ce8bfd00 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Feb 2018 19:29:57 +0100 Subject: [PATCH 63/73] Add a Rectangle abstraction in the demo app --- direct-composition/src/main.rs | 71 ++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 8d47d94384..520e334844 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -6,7 +6,8 @@ extern crate gleam; extern crate webrender; extern crate winit; -use direct_composition::{DirectComposition, AngleVisual}; +use direct_composition::DirectComposition; +use webrender::api::{ColorF, DeviceUintSize}; use winit::os::windows::WindowExt; fn main() { @@ -25,23 +26,22 @@ fn main() { webrender::RendererOptions::default(), ).unwrap(); - let visual1 = composition.create_angle_visual(300, 200); - visual1.set_offset_x(100.); - visual1.set_offset_y(50.); - - let visual2 = composition.create_angle_visual(400, 300); + let mut clicks: usize = 0; let mut offset_y = 100.; - visual2.set_offset_x(200.); - visual2.set_offset_y(offset_y); + let mut rects = [ + Rectangle::new(&composition, DeviceUintSize::new(300, 200), 0., 0.2, 0.4, 1.), + Rectangle::new(&composition, DeviceUintSize::new(400, 300), 0., 0.5, 0., 0.5), + ]; + rects[0].render(); + rects[1].render(); - composition.commit(); + rects[0].visual.set_offset_x(100.); + rects[0].visual.set_offset_y(50.); - let mut rgba1 = (0., 0.2, 0.4, 1.); - let mut rgba2 = (0., 0.5, 0., 0.5); - render_plain_rgba_frame(&visual1, &rgba1); - render_plain_rgba_frame(&visual2, &rgba2); + rects[1].visual.set_offset_x(200.); + rects[1].visual.set_offset_y(offset_y); - let mut clicks: u32 = 0; + composition.commit(); events_loop.run_forever(|event| { if let winit::Event::WindowEvent { event, .. } = event { @@ -56,7 +56,7 @@ fn main() { }; offset_y = (offset_y - 10. * dy).max(0.).min(468.); - visual2.set_offset_y(offset_y); + rects[1].visual.set_offset_y(offset_y); composition.commit(); } winit::WindowEvent::MouseInput { @@ -65,14 +65,10 @@ fn main() { .. } => { clicks += 1; - let (rgba, visual) = if clicks % 2 == 0 { - (&mut rgba1, &visual1) - } else { - (&mut rgba2, &visual2) - }; - rgba.1 += 0.1; - rgba.1 %= 1.; - render_plain_rgba_frame(visual, rgba) + let rect = &mut rects[clicks % 2]; + rect.color.g += 0.1; + rect.color.g %= 1.; + rect.render() } _ => {} } @@ -89,14 +85,31 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { } } -fn render_plain_rgba_frame(visual: &AngleVisual, &(r, g, b, a): &(f32, f32, f32, f32)) { - visual.make_current(); - visual.gleam.clear_color(r, g, b, a); - visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); - assert_eq!(visual.gleam.get_error(), 0); - visual.present(); +struct Rectangle { + visual: direct_composition::AngleVisual, + color: ColorF, } +impl Rectangle { + fn new(composition: &DirectComposition, size: DeviceUintSize, + r: f32, g: f32, b: f32, a: f32) + -> Self { + Rectangle { + visual: composition.create_angle_visual(size.width, size.height), + color: ColorF { r, g, b, a }, + } + } + + fn render(&self) { + self.visual.make_current(); + self.visual.gleam.clear_color(self.color.r, self.color.g, self.color.b, self.color.a); + self.visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); + assert_eq!(self.visual.gleam.get_error(), 0); + self.visual.present(); + } +} + + #[derive(Clone)] struct Notifier { events_proxy: winit::EventsLoopProxy, From 42a25b4d81a9cd0c83388558a617d9ef879972ba Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 1 Mar 2018 12:01:31 +0100 Subject: [PATCH 64/73] Render with WebRender --- Cargo.lock | 1 + direct-composition/Cargo.toml | 1 + direct-composition/src/main.rs | 110 +++++++++++++++++++++++++-------- 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9607298f26..53eac1228e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,6 +282,7 @@ dependencies = [ name = "direct-composition" version = "0.1.0" dependencies = [ + "euclid 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.57.0", diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index b689742d01..0855a635b1 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -8,6 +8,7 @@ winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} # For the `main.rs` demo [dependencies] +euclid = "0.16" gleam = "0.4" webrender = {path = "../webrender"} winit = "0.10" diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 520e334844..ef5a66fae3 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -2,16 +2,19 @@ compile_error!("This demo only runs on Windows."); extern crate direct_composition; +extern crate euclid; extern crate gleam; extern crate webrender; extern crate winit; use direct_composition::DirectComposition; -use webrender::api::{ColorF, DeviceUintSize}; +use webrender::api; use winit::os::windows::WindowExt; fn main() { let mut events_loop = winit::EventsLoop::new(); + let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy() }); + let window = winit::WindowBuilder::new() .with_title("Hello, world!") .with_dimensions(1024, 768) @@ -19,21 +22,21 @@ fn main() { .unwrap(); let composition = direct_composition_from_window(&window); - - let (renderer, _api_sender) = webrender::Renderer::new( - composition.gleam.clone(), - Box::new(Notifier { events_proxy: events_loop.create_proxy() }), - webrender::RendererOptions::default(), - ).unwrap(); + let factor = window.hidpi_factor(); let mut clicks: usize = 0; let mut offset_y = 100.; + let size = api::DeviceUintSize::new; let mut rects = [ - Rectangle::new(&composition, DeviceUintSize::new(300, 200), 0., 0.2, 0.4, 1.), - Rectangle::new(&composition, DeviceUintSize::new(400, 300), 0., 0.5, 0., 0.5), + Rectangle::new(&composition, ¬ifier, factor, size(300, 200), 0., 0.2, 0.4, 1.), + Rectangle::new(&composition, ¬ifier, factor, size(400, 300), 0., 0.5, 0., 0.5), ]; - rects[0].render(); - rects[1].render(); + rects[0].render(factor); + rects[1].render(factor); + + // FIXME: what shows up on screen for each visual seems to be one frame late? + rects[0].render(factor); + rects[1].render(factor); rects[0].visual.set_offset_x(100.); rects[0].visual.set_offset_y(50.); @@ -68,15 +71,13 @@ fn main() { let rect = &mut rects[clicks % 2]; rect.color.g += 0.1; rect.color.g %= 1.; - rect.render() + rect.render(factor) } _ => {} } } winit::ControlFlow::Continue }); - - renderer.deinit() } fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { @@ -87,36 +88,91 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { struct Rectangle { visual: direct_composition::AngleVisual, - color: ColorF, + renderer: Option, + api: api::RenderApi, + document_id: api::DocumentId, + size: api::DeviceUintSize, + color: api::ColorF, } impl Rectangle { - fn new(composition: &DirectComposition, size: DeviceUintSize, - r: f32, g: f32, b: f32, a: f32) + fn new(composition: &DirectComposition, notifier: &Box, + device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32) -> Self { - Rectangle { - visual: composition.create_angle_visual(size.width, size.height), - color: ColorF { r, g, b, a }, + let visual = composition.create_angle_visual(size.width, size.height); + visual.make_current(); + + let (renderer, sender) = webrender::Renderer::new( + composition.gleam.clone(), + notifier.clone(), + webrender::RendererOptions { + clear_color: Some(api::ColorF::new(0., 0., 0., 0.)), + device_pixel_ratio, + ..webrender::RendererOptions::default() + }, + ).unwrap(); + let api = sender.create_api(); + + Rectangle { + visual, + renderer: Some(renderer), + document_id: api.add_document(size, 0), + api, + size, + color: api::ColorF { r, g, b, a }, } } - fn render(&self) { + fn render(&mut self, device_pixel_ratio: f32) { self.visual.make_current(); - self.visual.gleam.clear_color(self.color.r, self.color.g, self.color.b, self.color.a); - self.visual.gleam.clear(gleam::gl::COLOR_BUFFER_BIT); - assert_eq!(self.visual.gleam.get_error(), 0); + + let pipeline_id = api::PipelineId(0, 0); + let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size); + + let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size); + builder.push_rect( + &api::PrimitiveInfo::with_clip( + rect, + api::LocalClip::RoundedRect(rect, api::ComplexClipRegion::new( + rect, api::BorderRadius::uniform(20.), api::ClipMode::Clip, + )) + ), + self.color, + ); + + let mut transaction = api::Transaction::new(); + transaction.set_display_list( + api::Epoch(0), + None, + layout_size, + builder.finalize(), + true, + ); + transaction.set_root_pipeline(pipeline_id); + transaction.generate_frame(); + self.api.send_transaction(self.document_id, transaction); + let renderer = self.renderer.as_mut().unwrap(); + renderer.update(); + renderer.render(self.size).unwrap(); + let _ = renderer.flush_pipeline_info(); self.visual.present(); } } +impl Drop for Rectangle { + fn drop(&mut self) { + self.renderer.take().unwrap().deinit() + } +} #[derive(Clone)] struct Notifier { events_proxy: winit::EventsLoopProxy, } -impl webrender::api::RenderNotifier for Notifier { - fn clone(&self) -> Box { +impl api::RenderNotifier for Notifier { + fn clone(&self) -> Box { Box::new(Clone::clone(self)) } @@ -124,7 +180,7 @@ impl webrender::api::RenderNotifier for Notifier { let _ = self.events_proxy.wakeup(); } - fn new_document_ready(&self, _: webrender::api::DocumentId, _: bool, _: bool) { + fn new_document_ready(&self, _: api::DocumentId, _: bool, _: bool) { self.wake_up(); } } From 27be7109f9e82bb6bd21f9eb1cdab297577facc8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 2 Mar 2018 09:14:16 +0100 Subject: [PATCH 65/73] Block until the pipeline is ready, before rendering. --- direct-composition/src/main.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index ef5a66fae3..5c40d965a0 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -8,15 +8,18 @@ extern crate webrender; extern crate winit; use direct_composition::DirectComposition; +use std::sync::mpsc; use webrender::api; use winit::os::windows::WindowExt; fn main() { let mut events_loop = winit::EventsLoop::new(); - let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy() }); + + let (tx, rx) = mpsc::channel(); + let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx }); let window = winit::WindowBuilder::new() - .with_title("Hello, world!") + .with_title("WebRender + ANGLE + DirectComposition") .with_dimensions(1024, 768) .build(&events_loop) .unwrap(); @@ -31,12 +34,8 @@ fn main() { Rectangle::new(&composition, ¬ifier, factor, size(300, 200), 0., 0.2, 0.4, 1.), Rectangle::new(&composition, ¬ifier, factor, size(400, 300), 0., 0.5, 0., 0.5), ]; - rects[0].render(factor); - rects[1].render(factor); - - // FIXME: what shows up on screen for each visual seems to be one frame late? - rects[0].render(factor); - rects[1].render(factor); + rects[0].render(factor, &rx); + rects[1].render(factor, &rx); rects[0].visual.set_offset_x(100.); rects[0].visual.set_offset_y(50.); @@ -71,7 +70,7 @@ fn main() { let rect = &mut rects[clicks % 2]; rect.color.g += 0.1; rect.color.g %= 1.; - rect.render(factor) + rect.render(factor, &rx) } _ => {} } @@ -123,7 +122,7 @@ impl Rectangle { } } - fn render(&mut self, device_pixel_ratio: f32) { + fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) { self.visual.make_current(); let pipeline_id = api::PipelineId(0, 0); @@ -152,6 +151,7 @@ impl Rectangle { transaction.set_root_pipeline(pipeline_id); transaction.generate_frame(); self.api.send_transaction(self.document_id, transaction); + rx.recv().unwrap(); let renderer = self.renderer.as_mut().unwrap(); renderer.update(); renderer.render(self.size).unwrap(); @@ -169,6 +169,7 @@ impl Drop for Rectangle { #[derive(Clone)] struct Notifier { events_proxy: winit::EventsLoopProxy, + tx: mpsc::Sender<()>, } impl api::RenderNotifier for Notifier { @@ -177,6 +178,7 @@ impl api::RenderNotifier for Notifier { } fn wake_up(&self) { + self.tx.send(()).unwrap(); let _ = self.events_proxy.wakeup(); } From 8766dfc92a947e47163d54a4e7326fe7e67d1a09 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 3 Mar 2018 17:25:29 +0100 Subject: [PATCH 66/73] Use the mozangle crate --- Cargo.lock | 22 ++++++++++++++++- direct-composition/Cargo.toml | 5 +--- direct-composition/build.rs | 44 --------------------------------- direct-composition/src/egl.rs | 46 +++-------------------------------- direct-composition/src/lib.rs | 3 ++- 5 files changed, 28 insertions(+), 92 deletions(-) delete mode 100644 direct-composition/build.rs diff --git a/Cargo.lock b/Cargo.lock index 53eac1228e..2516d80aca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,14 @@ dependencies = [ "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cfg-if" version = "0.1.2" @@ -283,8 +291,8 @@ name = "direct-composition" version = "0.1.0" dependencies = [ "euclid 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.57.0", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -709,6 +717,16 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mozangle" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "net2" version = "0.2.26" @@ -1459,6 +1477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" +"checksum cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9be26b24e988625409b19736d130f0c7d224f01d06454b5f81d8d23d6c1a618f" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86765cb42c2a2c497e142af72517c1b4d7ae5bb2f25dfa77a5c69642f2342d89" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" @@ -1527,6 +1546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mio 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6d19442734abd7d780b981c590c325680d933e99795fe1f693f0686c9ed48022" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum mozangle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc54cf8feb9e8a7c8368a697653aaeeea3e63357bf184fc02255b0cfbed67781" "checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index 0855a635b1..8b0f2b3140 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -6,12 +6,9 @@ authors = ["Simon Sapin "] [target.'cfg(windows)'.dependencies] winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} -# For the `main.rs` demo [dependencies] euclid = "0.16" gleam = "0.4" +mozangle = {version = "0.1", features = ["egl"]} webrender = {path = "../webrender"} winit = "0.10" - -[build-dependencies] -gl_generator = "0.9.0" diff --git a/direct-composition/build.rs b/direct-composition/build.rs deleted file mode 100644 index 6c5ce4b2bd..0000000000 --- a/direct-composition/build.rs +++ /dev/null @@ -1,44 +0,0 @@ -extern crate gl_generator; - -use gl_generator::{Registry, Api, Profile, Fallbacks}; -use std::env; -use std::fs::File; -use std::path::PathBuf; - -fn main() { - // Building ANGLE is left as an exercise for the reader: - // https://chromium.googlesource.com/angle/angle/+/HEAD/doc/DevSetup.md - let relative_angle_dir = PathBuf::from("..").join("..").join("angle"); - - let angle_build_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()) - .join(relative_angle_dir) - // Assume `gn gen out/Debug` or `gn gen out/Release` like in build instructions. - .join("out") - .join(if &env::var_os("PROFILE").unwrap() == "release" { "Release" } else { "Debug" }); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - - // Assuming that OUT_DIR is something like `target/debug/build/directcomposition-*/out`, - // bin_dir is `target/debug` (where the final executable goes). - let bin_dir = out_dir.join("..").join("..").join(".."); - for name in &[ - "libEGL.dll.lib", - "libEGL.dll", - "libGLESv2.dll", - ] { - std::fs::copy(angle_build_dir.join(name), bin_dir.join(name)).unwrap(); - } - println!("cargo:rustc-link-search=native={}", bin_dir.display()); - println!("cargo:rustc-link-lib=dylib=libEGL.dll"); - - let bindings = "egl_bindings.rs"; - Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [ - "EGL_ANGLE_device_d3d", - "EGL_EXT_platform_base", - "EGL_EXT_platform_device", - ]).write_bindings( - gl_generator::StaticGenerator, - &mut File::create(&out_dir.join(bindings)).unwrap() - ) - .unwrap(); - -} diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index 19526b1ccd..b9d43a060c 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -1,17 +1,11 @@ -use std::ffi::CString; -use std::os::raw::{c_void, c_long}; +use std::os::raw::c_void; use std::ptr; use std::rc::Rc; -use winapi; +use mozangle::egl::ffi::*; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; -pub fn get_proc_address(name: &str) -> *const c_void { - let name = CString::new(name.as_bytes()).unwrap(); - unsafe { - GetProcAddress(name.as_ptr()) as *const _ as _ - } -} +pub use mozangle::egl::get_proc_address; pub struct SharedEglThings { device: EGLDeviceEXT, @@ -39,7 +33,7 @@ impl SharedEglThings { pub unsafe fn new(d3d_device: *mut ID3D11Device) -> Rc { let device = eglCreateDeviceANGLE( D3D11_DEVICE_ANGLE, - d3d_device, + d3d_device as *mut c_void, ptr::null(), ).check(); let display = GetPlatformDisplayEXT( @@ -174,35 +168,3 @@ impl Check for types::EGLBoolean { self } } - -// Adapted from https://github.com/tomaka/glutin/blob/1f3b8360cb/src/api/egl/ffi.rs -#[allow(non_camel_case_types)] pub type khronos_utime_nanoseconds_t = khronos_uint64_t; -#[allow(non_camel_case_types)] pub type khronos_uint64_t = u64; -#[allow(non_camel_case_types)] pub type khronos_ssize_t = c_long; -pub type EGLint = i32; -pub type EGLNativeDisplayType = *const c_void; -pub type EGLNativePixmapType = *const c_void; -pub type EGLNativeWindowType = winapi::shared::windef::HWND; -pub type NativeDisplayType = EGLNativeDisplayType; -pub type NativePixmapType = EGLNativePixmapType; -pub type NativeWindowType = EGLNativeWindowType; - -include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); - - -// Adapted from https://chromium.googlesource.com/angle/angle/+/master/include/EGL/eglext_angle.h -type EGLDeviceEXT = *mut c_void; -const EXPERIMENTAL_PRESENT_PATH_ANGLE: types::EGLenum = 0x33A4; -const EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: types::EGLenum = 0x33A9; -const D3D_TEXTURE_ANGLE: types::EGLenum = 0x33A3; -const FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: types::EGLenum = 0x33A6; - -extern "C" { - fn eglCreateDeviceANGLE( - device_type: types::EGLenum, - device: *mut ID3D11Device, - attrib_list: *const types::EGLAttrib, - ) -> EGLDeviceEXT; - - fn eglReleaseDeviceANGLE(device: EGLDeviceEXT) -> types::EGLBoolean; -} diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index 50341945fa..a98c537647 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -1,7 +1,8 @@ #![cfg(windows)] -extern crate winapi; extern crate gleam; +extern crate mozangle; +extern crate winapi; use com::{ComPtr, CheckHResult, as_ptr}; use std::ptr; From aa39ae5378dff87b690b6d2b4c3c5328178b36d6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 4 Mar 2018 11:27:49 +0100 Subject: [PATCH 67/73] Use mozangle instead of the other angle crate. --- Cargo.lock | 12 +----------- webrender/Cargo.toml | 2 +- webrender/tests/angle_shader_validation.rs | 6 +++--- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2516d80aca..a525d98782 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,15 +16,6 @@ name = "android_glue" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "angle" -version = "0.5.0" -source = "git+https://github.com/servo/angle?branch=servo#c598aafe6a3bf8758f7564e41044d88ca2fd7af5" -dependencies = [ - "cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ansi_term" version = "0.10.2" @@ -1263,7 +1254,6 @@ dependencies = [ name = "webrender" version = "0.57.0" dependencies = [ - "angle 0.5.0 (git+https://github.com/servo/angle?branch=servo)", "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1282,6 +1272,7 @@ dependencies = [ "image 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "plane-split 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1465,7 +1456,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e2b80445d331077679dfc6f3014f3e9ab7083e588423d35041d3fc017198189" -"checksum angle 0.5.0 (git+https://github.com/servo/angle?branch=servo)" = "" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29069a9b483f7780aebb55dafb360c6225eefdc1f98c8d336a65148fd10c37b1" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml index ca493720bb..a8f5354b06 100644 --- a/webrender/Cargo.toml +++ b/webrender/Cargo.toml @@ -40,7 +40,7 @@ base64 = { optional = true, version = "0.3.0" } ron = { optional = true, version = "0.1.7" } [dev-dependencies] -angle = {git = "https://github.com/servo/angle", branch = "servo"} +mozangle = "0.1" env_logger = "0.5" rand = "0.3" # for the benchmarks glutin = "0.12" # for the example apps diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs index abed21a429..4d8cdb3fee 100644 --- a/webrender/tests/angle_shader_validation.rs +++ b/webrender/tests/angle_shader_validation.rs @@ -2,10 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -extern crate angle; +extern crate mozangle; extern crate webrender; -use angle::hl::{BuiltInResources, Output, ShaderSpec, ShaderValidator}; +use mozangle::shaders::{initialize, BuiltInResources, Output, ShaderSpec, ShaderValidator}; // from glslang const FRAGMENT_SHADER: u32 = 0x8B30; @@ -113,7 +113,7 @@ const VERSION_STRING: &str = "#version 300 es\n"; #[test] fn validate_shaders() { - angle::hl::initialize().unwrap(); + initialize().unwrap(); let resources = BuiltInResources::default(); let vs_validator = From 87812ae2c5cf3dde037cba8025b551db6607d843 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 17:38:34 +0100 Subject: [PATCH 68/73] Make the direct-composition demo compile to an empty program on non-windows. --- direct-composition/Cargo.toml | 4 +- direct-composition/src/main.rs | 187 +------------------------ direct-composition/src/main_windows.rs | 185 ++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 187 deletions(-) create mode 100644 direct-composition/src/main_windows.rs diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index f65d85693d..029caa806d 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -4,11 +4,9 @@ version = "0.1.0" authors = ["Simon Sapin "] [target.'cfg(windows)'.dependencies] -winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} - -[dependencies] euclid = "0.17" gleam = "0.4" mozangle = {version = "0.1", features = ["egl"]} webrender = {path = "../webrender"} +winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} winit = "0.10" diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index 5c40d965a0..feef056479 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -1,188 +1,7 @@ #[cfg(not(windows))] -compile_error!("This demo only runs on Windows."); - -extern crate direct_composition; -extern crate euclid; -extern crate gleam; -extern crate webrender; -extern crate winit; - -use direct_composition::DirectComposition; -use std::sync::mpsc; -use webrender::api; -use winit::os::windows::WindowExt; - fn main() { - let mut events_loop = winit::EventsLoop::new(); - - let (tx, rx) = mpsc::channel(); - let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx }); - - let window = winit::WindowBuilder::new() - .with_title("WebRender + ANGLE + DirectComposition") - .with_dimensions(1024, 768) - .build(&events_loop) - .unwrap(); - - let composition = direct_composition_from_window(&window); - let factor = window.hidpi_factor(); - - let mut clicks: usize = 0; - let mut offset_y = 100.; - let size = api::DeviceUintSize::new; - let mut rects = [ - Rectangle::new(&composition, ¬ifier, factor, size(300, 200), 0., 0.2, 0.4, 1.), - Rectangle::new(&composition, ¬ifier, factor, size(400, 300), 0., 0.5, 0., 0.5), - ]; - rects[0].render(factor, &rx); - rects[1].render(factor, &rx); - - rects[0].visual.set_offset_x(100.); - rects[0].visual.set_offset_y(50.); - - rects[1].visual.set_offset_x(200.); - rects[1].visual.set_offset_y(offset_y); - - composition.commit(); - - events_loop.run_forever(|event| { - if let winit::Event::WindowEvent { event, .. } = event { - match event { - winit::WindowEvent::Closed => { - return winit::ControlFlow::Break - } - winit::WindowEvent::MouseWheel { delta, .. } => { - let dy = match delta { - winit::MouseScrollDelta::LineDelta(_, dy) => dy, - winit::MouseScrollDelta::PixelDelta(_, dy) => dy, - }; - offset_y = (offset_y - 10. * dy).max(0.).min(468.); - - rects[1].visual.set_offset_y(offset_y); - composition.commit(); - } - winit::WindowEvent::MouseInput { - button: winit::MouseButton::Left, - state: winit::ElementState::Pressed, - .. - } => { - clicks += 1; - let rect = &mut rects[clicks % 2]; - rect.color.g += 0.1; - rect.color.g %= 1.; - rect.render(factor, &rx) - } - _ => {} - } - } - winit::ControlFlow::Continue - }); -} - -fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { - unsafe { - DirectComposition::new(window.get_hwnd() as _) - } -} - -struct Rectangle { - visual: direct_composition::AngleVisual, - renderer: Option, - api: api::RenderApi, - document_id: api::DocumentId, - size: api::DeviceUintSize, - color: api::ColorF, + println!("This demo only runs on Windows."); } -impl Rectangle { - fn new(composition: &DirectComposition, notifier: &Box, - device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32) - -> Self { - let visual = composition.create_angle_visual(size.width, size.height); - visual.make_current(); - - let (renderer, sender) = webrender::Renderer::new( - composition.gleam.clone(), - notifier.clone(), - webrender::RendererOptions { - clear_color: Some(api::ColorF::new(0., 0., 0., 0.)), - device_pixel_ratio, - ..webrender::RendererOptions::default() - }, - ).unwrap(); - let api = sender.create_api(); - - Rectangle { - visual, - renderer: Some(renderer), - document_id: api.add_document(size, 0), - api, - size, - color: api::ColorF { r, g, b, a }, - } - } - - fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) { - self.visual.make_current(); - - let pipeline_id = api::PipelineId(0, 0); - let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); - let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size); - - let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size); - builder.push_rect( - &api::PrimitiveInfo::with_clip( - rect, - api::LocalClip::RoundedRect(rect, api::ComplexClipRegion::new( - rect, api::BorderRadius::uniform(20.), api::ClipMode::Clip, - )) - ), - self.color, - ); - - let mut transaction = api::Transaction::new(); - transaction.set_display_list( - api::Epoch(0), - None, - layout_size, - builder.finalize(), - true, - ); - transaction.set_root_pipeline(pipeline_id); - transaction.generate_frame(); - self.api.send_transaction(self.document_id, transaction); - rx.recv().unwrap(); - let renderer = self.renderer.as_mut().unwrap(); - renderer.update(); - renderer.render(self.size).unwrap(); - let _ = renderer.flush_pipeline_info(); - self.visual.present(); - } -} - -impl Drop for Rectangle { - fn drop(&mut self) { - self.renderer.take().unwrap().deinit() - } -} - -#[derive(Clone)] -struct Notifier { - events_proxy: winit::EventsLoopProxy, - tx: mpsc::Sender<()>, -} - -impl api::RenderNotifier for Notifier { - fn clone(&self) -> Box { - Box::new(Clone::clone(self)) - } - - fn wake_up(&self) { - self.tx.send(()).unwrap(); - let _ = self.events_proxy.wakeup(); - } - - fn new_document_ready(&self, _: api::DocumentId, _: bool, _: bool) { - self.wake_up(); - } -} +#[cfg(windows)] +include!("main_windows.rs"); diff --git a/direct-composition/src/main_windows.rs b/direct-composition/src/main_windows.rs new file mode 100644 index 0000000000..9090168877 --- /dev/null +++ b/direct-composition/src/main_windows.rs @@ -0,0 +1,185 @@ +extern crate direct_composition; +extern crate euclid; +extern crate gleam; +extern crate webrender; +extern crate winit; + +use direct_composition::DirectComposition; +use std::sync::mpsc; +use webrender::api; +use winit::os::windows::WindowExt; + +fn main() { + let mut events_loop = winit::EventsLoop::new(); + + let (tx, rx) = mpsc::channel(); + let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx }); + + let window = winit::WindowBuilder::new() + .with_title("WebRender + ANGLE + DirectComposition") + .with_dimensions(1024, 768) + .build(&events_loop) + .unwrap(); + + let composition = direct_composition_from_window(&window); + let factor = window.hidpi_factor(); + + let mut clicks: usize = 0; + let mut offset_y = 100.; + let size = api::DeviceUintSize::new; + let mut rects = [ + Rectangle::new(&composition, ¬ifier, factor, size(300, 200), 0., 0.2, 0.4, 1.), + Rectangle::new(&composition, ¬ifier, factor, size(400, 300), 0., 0.5, 0., 0.5), + ]; + rects[0].render(factor, &rx); + rects[1].render(factor, &rx); + + rects[0].visual.set_offset_x(100.); + rects[0].visual.set_offset_y(50.); + + rects[1].visual.set_offset_x(200.); + rects[1].visual.set_offset_y(offset_y); + + composition.commit(); + + events_loop.run_forever(|event| { + if let winit::Event::WindowEvent { event, .. } = event { + match event { + winit::WindowEvent::Closed => { + return winit::ControlFlow::Break + } + winit::WindowEvent::MouseWheel { delta, .. } => { + let dy = match delta { + winit::MouseScrollDelta::LineDelta(_, dy) => dy, + winit::MouseScrollDelta::PixelDelta(_, dy) => dy, + }; + offset_y = (offset_y - 10. * dy).max(0.).min(468.); + + rects[1].visual.set_offset_y(offset_y); + composition.commit(); + } + winit::WindowEvent::MouseInput { + button: winit::MouseButton::Left, + state: winit::ElementState::Pressed, + .. + } => { + clicks += 1; + let rect = &mut rects[clicks % 2]; + rect.color.g += 0.1; + rect.color.g %= 1.; + rect.render(factor, &rx) + } + _ => {} + } + } + winit::ControlFlow::Continue + }); +} + +fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { + unsafe { + DirectComposition::new(window.get_hwnd() as _) + } +} + +struct Rectangle { + visual: direct_composition::AngleVisual, + renderer: Option, + api: api::RenderApi, + document_id: api::DocumentId, + size: api::DeviceUintSize, + color: api::ColorF, +} + +impl Rectangle { + fn new(composition: &DirectComposition, notifier: &Box, + device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32) + -> Self { + let visual = composition.create_angle_visual(size.width, size.height); + visual.make_current(); + + let (renderer, sender) = webrender::Renderer::new( + composition.gleam.clone(), + notifier.clone(), + webrender::RendererOptions { + clear_color: Some(api::ColorF::new(0., 0., 0., 0.)), + device_pixel_ratio, + ..webrender::RendererOptions::default() + }, + ).unwrap(); + let api = sender.create_api(); + + Rectangle { + visual, + renderer: Some(renderer), + document_id: api.add_document(size, 0), + api, + size, + color: api::ColorF { r, g, b, a }, + } + } + + fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) { + self.visual.make_current(); + + let pipeline_id = api::PipelineId(0, 0); + let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size); + + let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size); + builder.push_rect( + &api::PrimitiveInfo::with_clip( + rect, + api::LocalClip::RoundedRect(rect, api::ComplexClipRegion::new( + rect, api::BorderRadius::uniform(20.), api::ClipMode::Clip, + )) + ), + self.color, + ); + + let mut transaction = api::Transaction::new(); + transaction.set_display_list( + api::Epoch(0), + None, + layout_size, + builder.finalize(), + true, + ); + transaction.set_root_pipeline(pipeline_id); + transaction.generate_frame(); + self.api.send_transaction(self.document_id, transaction); + rx.recv().unwrap(); + let renderer = self.renderer.as_mut().unwrap(); + renderer.update(); + renderer.render(self.size).unwrap(); + let _ = renderer.flush_pipeline_info(); + self.visual.present(); + } +} + +impl Drop for Rectangle { + fn drop(&mut self) { + self.renderer.take().unwrap().deinit() + } +} + +#[derive(Clone)] +struct Notifier { + events_proxy: winit::EventsLoopProxy, + tx: mpsc::Sender<()>, +} + +impl api::RenderNotifier for Notifier { + fn clone(&self) -> Box { + Box::new(Clone::clone(self)) + } + + fn wake_up(&self) { + self.tx.send(()).unwrap(); + let _ = self.events_proxy.wakeup(); + } + + fn new_document_ready(&self, _: api::DocumentId, _: bool, _: bool) { + self.wake_up(); + } +} From 9d92ad56c7d43f724f0f4febabffdf78b704b9c9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 17:54:34 +0100 Subject: [PATCH 69/73] direct-composition tidy --- direct-composition/Cargo.toml | 1 + direct-composition/src/com.rs | 4 ++++ direct-composition/src/egl.rs | 6 +++++- direct-composition/src/lib.rs | 6 +++++- direct-composition/src/main.rs | 4 ++++ direct-composition/src/main_windows.rs | 4 ++++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index 029caa806d..205e0df207 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -2,6 +2,7 @@ name = "direct-composition" version = "0.1.0" authors = ["Simon Sapin "] +license = "MPL-2.0" [target.'cfg(windows)'.dependencies] euclid = "0.17" diff --git a/direct-composition/src/com.rs b/direct-composition/src/com.rs index 55c2ffc614..8fb384695c 100644 --- a/direct-composition/src/com.rs +++ b/direct-composition/src/com.rs @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + use std::ops; use std::ptr; use winapi::Interface; diff --git a/direct-composition/src/egl.rs b/direct-composition/src/egl.rs index b9d43a060c..8bd5afb72a 100644 --- a/direct-composition/src/egl.rs +++ b/direct-composition/src/egl.rs @@ -1,7 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use mozangle::egl::ffi::*; use std::os::raw::c_void; use std::ptr; use std::rc::Rc; -use mozangle::egl::ffi::*; use winapi::um::d3d11::ID3D11Device; use winapi::um::d3d11::ID3D11Texture2D; diff --git a/direct-composition/src/lib.rs b/direct-composition/src/lib.rs index a98c537647..01cd32c4e6 100644 --- a/direct-composition/src/lib.rs +++ b/direct-composition/src/lib.rs @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + #![cfg(windows)] extern crate gleam; @@ -74,7 +78,7 @@ impl DirectComposition { // Create the DirectComposition device object. let composition_device = ComPtr::::new_with_uuid(|uuid, ptr_ptr| { - winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr) + winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid, ptr_ptr) }); // Create the composition target object based on the diff --git a/direct-composition/src/main.rs b/direct-composition/src/main.rs index feef056479..e1999f5f8f 100644 --- a/direct-composition/src/main.rs +++ b/direct-composition/src/main.rs @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + #[cfg(not(windows))] fn main() { println!("This demo only runs on Windows."); diff --git a/direct-composition/src/main_windows.rs b/direct-composition/src/main_windows.rs index 9090168877..899635be96 100644 --- a/direct-composition/src/main_windows.rs +++ b/direct-composition/src/main_windows.rs @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + extern crate direct_composition; extern crate euclid; extern crate gleam; From 19b3df10e3d66a9340710b9493671b2617edca41 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 19:49:33 +0100 Subject: [PATCH 70/73] Update mozangle --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f2c6f7d0e..7c1b846cbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,7 +283,7 @@ version = "0.1.0" dependencies = [ "euclid 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.57.0", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -709,7 +709,7 @@ dependencies = [ [[package]] name = "mozangle" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1271,7 +1271,7 @@ dependencies = [ "image 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "plane-split 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1535,7 +1535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mio 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6d19442734abd7d780b981c590c325680d933e99795fe1f693f0686c9ed48022" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4d916e4f2d39a00eeeb082ceb7c63c741e7c9d4f7915945f9225ae5e3b284092" +"checksum mozangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b41d9b5488bd3bf519736839a5b573953bc20b093f9a444a02ca1c8956fe59f" "checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" From 206250154ff73ecc2c95b5b7ee947c4424104e29 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 19:52:36 +0100 Subject: [PATCH 71/73] Appveyor: Switch to MSVC toolchain --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 74b24dc5d1..b1a9364d91 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,11 @@ environment: PATH: 'C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Rust\bin' RUST_BACKTRACE: 1 + TARGET: x86_64-pc-windows-msvc install: - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.23.0-x86_64-pc-windows-gnu.msi" - - msiexec /passive /i "rust-1.23.0-x86_64-pc-windows-gnu.msi" ADDLOCAL=Rustc,Cargo,Std INSTALLDIR=C:\Rust - - bash -lc "pacman -S --noconfirm mingw-w64-x86_64-cmake" + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.23.0-${env:TARGET}.msi" + - msiexec /passive /i "rust-1.23.0-%TARGET%.msi" ADDLOCAL=Rustc,Cargo,Std INSTALLDIR=C:\Rust - rustc -V - cargo -V From 60d8f08c774d964db276be3b6ba84881107eb648 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 17:57:32 +0100 Subject: [PATCH 72/73] Build the direct-composition demo on Appveyor CI --- appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index b1a9364d91..3816a1e85d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,5 @@ +image: Visual Studio 2017 + environment: PATH: 'C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Rust\bin' RUST_BACKTRACE: 1 @@ -18,3 +20,5 @@ test_script: - cargo test --verbose - cd ../wrench - cargo test --verbose + - cd ../direct-composition + - cargo build --verbose From c4a859d6fe3e8a91aa945d203da58463d2ab429a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Mar 2018 20:27:33 +0100 Subject: [PATCH 73/73] Revert AppVeyor image change --- appveyor.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 3816a1e85d..3cd08e8e1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,3 @@ -image: Visual Studio 2017 - environment: PATH: 'C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%;C:\Rust\bin' RUST_BACKTRACE: 1