Skip to content

Commit

Permalink
Merge pull request #1191 from linebender/simpler_d2d
Browse files Browse the repository at this point in the history
Use a simpler approach to Direct2D presentation
  • Loading branch information
raphlinus authored Sep 11, 2020
2 parents d9ceadb + b631667 commit 1bcdecb
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 593 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ You can find its changes [documented below](#060---2020-06-01).
- Allow derivation of lenses for generic types ([#1120]) by [@rjwittams])
- Switch widget: Toggle animation being window refresh rate dependent ([#1145] by [@ForLoveOfCats])
- Multi-click on Windows, partial fix for #859 ([#1157] by [@raphlinus])
- Windows: fix crash on resize from incompatible resources ([#1191 by [@raphlinus]])

### Visual

Expand Down Expand Up @@ -439,6 +440,7 @@ Last release without a changelog :(
[#1173]: https://github.com/linebender/druid/pull/1173
[#1182]: https://github.com/linebender/druid/pull/1182
[#1185]: https://github.com/linebender/druid/pull/1185
[#1191]: https://github.com/linebender/druid/pull/1191
[#1092]: https://github.com/linebender/druid/pull/1092
[#1195]: https://github.com/linebender/druid/pull/1195
[#1204]: https://github.com/linebender/druid/pull/1204
Expand Down
197 changes: 0 additions & 197 deletions druid-shell/src/platform/windows/dcomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,18 @@

// This module could become a general wrapper for DirectComposition, but
// for now we're just using what we need to get a swapchain up.
#![allow(unused)]

use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr::{null, null_mut};

use log::error;

use winapi::shared::dxgi::IDXGIDevice;
use winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_IGNORE;
use winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM;
use winapi::shared::minwindef::{FALSE, TRUE};
use winapi::shared::windef::{HWND, POINT, RECT};
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::d2d1::*;
use winapi::um::d2d1_1::*;
use winapi::um::d3d11::*;
use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE;
use winapi::um::dcomp::*;
use winapi::um::dcompanimation::*;
use winapi::um::unknwnbase::IUnknown;
use winapi::um::winnt::HRESULT;
use winapi::Interface;
use wio::com::ComPtr;

use super::util::OPTIONAL_FUNCTIONS;

unsafe fn wrap<T, U, F>(hr: HRESULT, ptr: *mut T, f: F) -> Result<U, HRESULT>
where
F: Fn(ComPtr<T>) -> U,
Expand All @@ -55,25 +40,7 @@ where
}
}

fn unit_err(hr: HRESULT) -> Result<(), HRESULT> {
if SUCCEEDED(hr) {
Ok(())
} else {
Err(hr)
}
}

pub struct D3D11Device(ComPtr<ID3D11Device>);
pub struct D2D1Device(ComPtr<ID2D1Device>);
pub struct DCompositionDevice(ComPtr<IDCompositionDevice>);
pub struct DCompositionTarget(ComPtr<IDCompositionTarget>);
pub struct DCompositionVisual(ComPtr<IDCompositionVisual>);
pub struct DCompositionVirtualSurface(ComPtr<IDCompositionVirtualSurface>);

/// A trait for content which can be added to a visual.
pub(crate) trait Content {
unsafe fn unknown_ptr(&mut self) -> *mut IUnknown;
}

impl D3D11Device {
/// Creates a new device with basic defaults.
Expand All @@ -100,171 +67,7 @@ impl D3D11Device {
}
}

pub(crate) fn create_d2d1_device(&mut self) -> Result<D2D1Device, HRESULT> {
unsafe {
let mut dxgi_device: ComPtr<IDXGIDevice> = self.0.cast()?;
let mut d2d1_device: *mut ID2D1Device = null_mut();
let hr = D2D1CreateDevice(dxgi_device.as_raw(), null(), &mut d2d1_device);
wrap(hr, d2d1_device, D2D1Device)
}
}

pub(crate) fn raw_ptr(&mut self) -> *mut ID3D11Device {
self.0.as_raw()
}
}

impl D2D1Device {
/// Create a wrapped DCompositionDevice object. Note: returns Err(0) on systems
/// not supporting DirectComposition, available 8.1 and above.
pub(crate) fn create_composition_device(&mut self) -> Result<DCompositionDevice, HRESULT> {
unsafe {
let create = OPTIONAL_FUNCTIONS.DCompositionCreateDevice2.ok_or(0)?;
let mut dcomp_device: *mut IDCompositionDevice = null_mut();
let hr = create(
self.0.as_raw() as *mut IUnknown,
&IDCompositionDevice::uuidof(),
&mut dcomp_device as *mut _ as *mut _,
);
wrap(hr, dcomp_device, DCompositionDevice)
}
}
}

impl DCompositionDevice {
pub(crate) unsafe fn create_target_for_hwnd(
&mut self,
hwnd: HWND,
topmost: bool,
) -> Result<DCompositionTarget, HRESULT> {
let mut dcomp_target: *mut IDCompositionTarget = null_mut();
let hr =
self.0
.CreateTargetForHwnd(hwnd, if topmost { TRUE } else { FALSE }, &mut dcomp_target);
wrap(hr, dcomp_target, DCompositionTarget)
}

pub(crate) fn create_visual(&mut self) -> Result<DCompositionVisual, HRESULT> {
unsafe {
let mut visual: *mut IDCompositionVisual = null_mut();
let hr = self.0.CreateVisual(&mut visual);
wrap(hr, visual, DCompositionVisual)
}
}

/// Creates an RGB surface. Probably should allow more options (including alpha).
pub(crate) fn create_virtual_surface(
&mut self,
height: u32,
width: u32,
) -> Result<DCompositionVirtualSurface, HRESULT> {
unsafe {
let mut surface: *mut IDCompositionVirtualSurface = null_mut();
let hr = self.0.CreateVirtualSurface(
width,
height,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_ALPHA_MODE_IGNORE,
&mut surface,
);
wrap(hr, surface, DCompositionVirtualSurface)
}
}

pub(crate) fn commit(&mut self) -> Result<(), HRESULT> {
unsafe { unit_err(self.0.Commit()) }
}
}

impl DCompositionTarget {
// alternatively could be set_root with an option
pub(crate) fn clear_root(&mut self) -> Result<(), HRESULT> {
unsafe { unit_err(self.0.SetRoot(null_mut())) }
}

pub(crate) fn set_root(&mut self, visual: &mut DCompositionVisual) -> Result<(), HRESULT> {
unsafe { unit_err(self.0.SetRoot(visual.0.as_raw())) }
}
}

impl DCompositionVisual {
pub(crate) fn set_content<T: Content>(&mut self, content: &mut T) -> Result<(), HRESULT> {
unsafe { self.set_content_raw(content.unknown_ptr()) }
}

// TODO: impl Content trait for swapchain, for type safety
pub(crate) unsafe fn set_content_raw(&mut self, content: *mut IUnknown) -> Result<(), HRESULT> {
unit_err(self.0.SetContent(content))
}

pub(crate) fn set_pos(&mut self, x: f32, y: f32) {
unsafe {
self.0.SetOffsetX_1(x);
self.0.SetOffsetY_1(y);
}
}
}

// We don't actually need to draw into DirectComposition virtual surfaces now, this is
// experimental and based on an older version of direct2d-rs. Probably delete.

/*
struct DcBacking(*mut ID2D1DeviceContext);
unsafe impl RenderTargetBacking for DcBacking {
fn create_target(self, _factory: &mut ID2D1Factory1) -> Result<*mut ID2D1RenderTarget, HRESULT> {
Ok(self.0 as *mut ID2D1RenderTarget)
}
}
// TODO: support common methods with DCompositionSurface, probably should be trait
impl DCompositionVirtualSurface {
// could try to expose more DeviceContext capability
pub fn begin_draw(&mut self, d2d_factory: &direct2d::Factory, rect: Option<RECT>)
-> Result<RenderTarget, HRESULT>
{
unsafe {
let mut dc: *mut ID2D1DeviceContext = null_mut();
let rect_ptr = match rect {
None => null(),
Some(r) => &r,
};
let mut offset: POINT = mem::uninitialized();
let hr = self.0.BeginDraw(rect_ptr, &ID2D1DeviceContext::uuidof(),
&mut dc as *mut _ as *mut _, &mut offset);
if !SUCCEEDED(hr) {
return Err(hr);
}
let backing = DcBacking(dc);
let mut rt = d2d_factory.create_render_target(backing).map_err(|e|
match e {
direct2d::Error::ComError(hr) => hr,
_ => 0,
})?;
// TODO: either move dpi scaling somewhere else or figure out how to
// set it correctly here.
rt.set_transform(&Matrix3x2F::new([[2.0, 0.0], [0.0, 2.0],
[offset.x as f32, offset.y as f32]]));
Ok(rt)
}
}
pub fn end_draw(&mut self) -> Result<(), HRESULT> {
unsafe {
unit_err(self.0.EndDraw())
}
}
pub fn resize(&mut self, width: u32, height: u32) -> Result<(), HRESULT> {
unsafe {
unit_err(self.0.Resize(width, height))
}
}
}
impl Content for DCompositionVirtualSurface {
unsafe fn unknown_ptr(&mut self) -> *mut IUnknown {
self.0.as_raw() as *mut IUnknown
}
}
*/
72 changes: 3 additions & 69 deletions druid-shell/src/platform/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,78 +46,12 @@ pub mod screen;
// Basically, go from HwndRenderTarget or DxgiSurfaceRenderTarget (2d or 3d) to a Device Context.
// Go back up for particular needs.

use piet_common::d2d::{D2DFactory, DeviceContext};
use piet_common::d2d::DeviceContext;
use std::fmt::{Debug, Display, Formatter};
use winapi::shared::windef::HWND;
use winapi::shared::winerror::{HRESULT, SUCCEEDED};
use winapi::um::d2d1::{
ID2D1HwndRenderTarget, ID2D1RenderTarget, D2D1_HWND_RENDER_TARGET_PROPERTIES,
D2D1_RENDER_TARGET_PROPERTIES, D2D1_SIZE_U,
};
use winapi::shared::winerror::HRESULT;
use winapi::um::d2d1::ID2D1RenderTarget;
use wio::com::ComPtr;

#[derive(Clone)]
pub struct HwndRenderTarget {
ptr: ComPtr<ID2D1HwndRenderTarget>,
}

impl HwndRenderTarget {
pub fn create(
factory: &D2DFactory,
hwnd: HWND,
width: u32,
height: u32,
rt_props: D2D1_RENDER_TARGET_PROPERTIES,
) -> Result<Self, Error> {
let mut hwnd_props = DEFAULT_HWND_PROPS;

hwnd_props.hwnd = hwnd;
hwnd_props.pixelSize.width = width;
hwnd_props.pixelSize.height = height;

// now build
unsafe {
let mut ptr = std::ptr::null_mut();
let hr = (*factory.get_raw()).CreateHwndRenderTarget(&rt_props, &hwnd_props, &mut ptr);

if SUCCEEDED(hr) {
Ok(HwndRenderTarget::from_raw(ptr))
} else {
Err(hr.into())
}
}
}

/// construct from COM ptr
///
/// # Safety
/// TODO
pub unsafe fn from_ptr(ptr: ComPtr<ID2D1HwndRenderTarget>) -> Self {
Self { ptr }
}

/// construct from raw ptr
///
/// # Safety
/// TODO
pub unsafe fn from_raw(raw: *mut ID2D1HwndRenderTarget) -> Self {
Self::from_ptr(ComPtr::from_raw(raw))
}

pub fn get_comptr(&self) -> &ComPtr<ID2D1HwndRenderTarget> {
&self.ptr
}
}

const DEFAULT_HWND_PROPS: D2D1_HWND_RENDER_TARGET_PROPERTIES = D2D1_HWND_RENDER_TARGET_PROPERTIES {
hwnd: std::ptr::null_mut(),
pixelSize: D2D1_SIZE_U {
width: 0,
height: 0,
},
presentOptions: 0,
};

#[derive(Clone)]
pub struct DxgiSurfaceRenderTarget {
ptr: ComPtr<ID2D1RenderTarget>,
Expand Down
Loading

0 comments on commit 1bcdecb

Please sign in to comment.