Skip to content

Commit

Permalink
wip(wgl): add support for pixel buffer surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
SK83RJOSH committed Sep 19, 2024
1 parent 1b30cd7 commit 6f987dd
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Added `Device::drm_device_node_path()` and `Device::drm_render_device_node_path()` getters to EGL via `EGL_EXT_device_drm`.
- Added support for `DrmDisplayHandle` in EGL's `Display::with_device()` using `EGL_DRM_MASTER_FD_EXT` from `EGL_EXT_device_drm`.
- Properly set up OpenGL-specific stuff on the `NSView`, instead of relying on Winit to do it.
- Added support for `Display::create_pbuffer_surface()` in WGL via `WGL_ARB_pbuffer`.

# Version 0.32.0

Expand Down
5 changes: 5 additions & 0 deletions glutin/src/api/wgl/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ impl Display {
attrs.push(1);
}

if template.config_surface_types.contains(ConfigSurfaceTypes::PBUFFER) {
attrs.push(wgl_extra::DRAW_TO_PBUFFER_ARB as c_int);
attrs.push(1);
}

if template.transparency {
attrs.push(wgl_extra::TRANSPARENT_ARB as c_int);
attrs.push(1);
Expand Down
9 changes: 7 additions & 2 deletions glutin/src/api/wgl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::prelude::*;
use crate::private::Sealed;
use crate::surface::SurfaceTypeTrait;

use super::config::Config;
use super::{config::Config, surface::WGLSurface};
use super::display::Display;
use super::surface::Surface;

Expand Down Expand Up @@ -387,7 +387,12 @@ impl ContextInner {

fn make_current<T: SurfaceTypeTrait>(&self, surface: &Surface<T>) -> Result<()> {
unsafe {
if wgl::MakeCurrent(surface.hdc as _, self.raw.cast()) == 0 {
let hdc = match surface.raw {
WGLSurface::Window(_, hdc) => hdc as _,
WGLSurface::PBuffer(_, hdc) => hdc as _,
};

if wgl::MakeCurrent(hdc, self.raw.cast()) == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
Expand Down
139 changes: 115 additions & 24 deletions glutin/src/api/wgl/surface.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! A wrapper around `HWND` used for GL operations.

use std::{fmt, mem};
use std::io::Error as IoError;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::{fmt, mem};
use std::os::raw::c_int;

use glutin_wgl_sys::{wgl::types::GLenum, wgl_extra::{self, types::HPBUFFEREXT}};
use raw_window_handle::RawWindowHandle;
use windows_sys::Win32::Foundation::{HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::HDC;
use windows_sys::Win32::Graphics::{Gdi as gdi, OpenGL as gl};
use windows_sys::Win32::UI::WindowsAndMessaging::GetClientRect;

Expand Down Expand Up @@ -36,10 +37,37 @@ impl Display {

pub(crate) unsafe fn create_pbuffer_surface(
&self,
_config: &Config,
_surface_attributes: &SurfaceAttributes<PbufferSurface>,
config: &Config,
surface_attributes: &SurfaceAttributes<PbufferSurface>,
) -> Result<Surface<PbufferSurface>> {
Err(ErrorKind::NotSupported("pbuffers are not implemented with WGL").into())
let hdc = config.inner.hdc;
let width = surface_attributes.width.unwrap().get() as c_int;
let height = surface_attributes.height.unwrap().get() as c_int;

let mut attrs = Vec::<c_int>::with_capacity(2);
if surface_attributes.largest_pbuffer {
attrs.push(wgl_extra::PBUFFER_LARGEST_ARB as c_int);
attrs.push(1 as c_int);
}
attrs.push(0);

let (hbuf, hdc) = match self.inner.wgl_extra {
Some(extra) if extra.CreatePbufferARB.is_loaded() => unsafe {
let hbuf = extra.CreatePbufferARB(hdc as _, config.inner.pixel_format_index, width, height, attrs.as_ptr());
let hdc = extra.GetPbufferDCARB(hbuf);
(hbuf, hdc)
},
_ => {
return Err(
ErrorKind::NotSupported("pbuffer extensions are not supported").into()
)
},
};

let surface =
Surface { display: self.clone(), config: config.clone(), raw: WGLSurface::PBuffer(hbuf, hdc), _ty: PhantomData };

Ok(surface)
}

pub(crate) unsafe fn create_window_surface(
Expand All @@ -62,28 +90,66 @@ impl Display {
let hdc = unsafe { gdi::GetDC(hwnd) };

let surface =
Surface { display: self.clone(), config: config.clone(), hwnd, hdc, _ty: PhantomData };
Surface { display: self.clone(), config: config.clone(), raw: WGLSurface::Window(hwnd, hdc), _ty: PhantomData };

Ok(surface)
}
}

/// A Wrapper around `HWND`.
/// A wrapper around WGL surfaces.
#[derive(Debug)]
pub enum WGLSurface {
/// Surface backed by a window surface.
Window(HWND, gdi::HDC),
/// Surface backed by a pixel buffer.
PBuffer(HPBUFFEREXT, wgl_extra::types::HDC),
}

/// A Wrapper around `WGLSurface`.
pub struct Surface<T: SurfaceTypeTrait> {
display: Display,
config: Config,
pub(crate) hwnd: HWND,
pub(crate) hdc: HDC,
pub(crate) raw: WGLSurface,
_ty: PhantomData<T>,
}

// Impl only `Send` for Surface.
unsafe impl<T: SurfaceTypeTrait> Send for Surface<T> {}

impl<T: SurfaceTypeTrait> Surface<T> {
/// # Safety
///
/// The caller must ensure that the attribute could be present.
unsafe fn raw_attribute(&self, attr: GLenum) -> c_int {
let mut value = 0;
unsafe {
match self.raw {
WGLSurface::Window(_, _) => unreachable!(),
WGLSurface::PBuffer(hbuf, _) => {
if let Some(extra) = self.display.inner.wgl_extra {
extra.QueryPbufferARB(hbuf, attr as _, &mut value);
}
},
}
}
value
}
}

impl<T: SurfaceTypeTrait> Drop for Surface<T> {
fn drop(&mut self) {
unsafe {
gdi::ReleaseDC(self.hwnd, self.hdc);
match self.raw {
WGLSurface::Window(hwnd, hdc) => {
gdi::ReleaseDC(hwnd, hdc);
}
WGLSurface::PBuffer(hbuf, hdc) => {
if let Some(extra) = self.display.inner.wgl_extra {
extra.ReleasePbufferDCARB(hbuf, hdc);
extra.DestroyPbufferARB(hbuf);
}
},
}
}
}
}
Expand All @@ -97,20 +163,34 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
}

fn width(&self) -> Option<u32> {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.right - rect.left) as u32)
match self.raw {
WGLSurface::Window(hwnd, _) => {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.right - rect.left) as u32)
}
},
WGLSurface::PBuffer(_, _) => {
unsafe { Some(self.raw_attribute(wgl_extra::PBUFFER_WIDTH_ARB) as _) }
},
}
}

fn height(&self) -> Option<u32> {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.bottom - rect.top) as u32)
match self.raw {
WGLSurface::Window(hwnd, _) => {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.bottom - rect.top) as u32)
}
},
WGLSurface::PBuffer(_, _) => {
unsafe { Some(self.raw_attribute(wgl_extra::PBUFFER_HEIGHT_ARB) as _) }
},
}
}

Expand All @@ -120,7 +200,12 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {

fn swap_buffers(&self, _context: &Self::Context) -> Result<()> {
unsafe {
if gl::SwapBuffers(self.hdc) == 0 {
let hdc = match self.raw {
WGLSurface::Window(_, hdc) => hdc as _,
WGLSurface::PBuffer(_, hdc) => hdc as _
};

if gl::SwapBuffers(hdc) == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
Expand All @@ -129,6 +214,10 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
}

fn set_swap_interval(&self, _context: &Self::Context, interval: SwapInterval) -> Result<()> {
let WGLSurface::Window(_, _) = self.raw else {
return Ok(());
};

let interval = match interval {
SwapInterval::DontWait => 0,
SwapInterval::Wait(n) => n.get(),
Expand Down Expand Up @@ -173,15 +262,17 @@ impl<T: SurfaceTypeTrait> fmt::Debug for Surface<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Surface")
.field("config", &self.config.inner.pixel_format_index)
.field("hwnd", &self.hwnd)
.field("hdc", &self.hdc)
.field("raw", &self.raw)
.finish()
}
}

impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
fn raw_surface(&self) -> RawSurface {
RawSurface::Wgl(self.hwnd as _)
match self.raw {
WGLSurface::Window(hwnd, _) => RawSurface::Wgl(hwnd as _),
WGLSurface::PBuffer(_, _) => RawSurface::Wgl(0 as _),
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion glutin_wgl_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ fn main() {
let mut file = File::create(dest.join("wgl_extra_bindings.rs")).unwrap();
Registry::new(Api::Wgl, (1, 0), Profile::Core, Fallbacks::All, [
"WGL_ARB_context_flush_control",
"WGL_ARB_create_context",
"WGL_ARB_create_context_no_error",
"WGL_ARB_create_context_profile",
"WGL_ARB_create_context_robustness",
"WGL_ARB_create_context",
"WGL_ARB_extensions_string",
"WGL_ARB_framebuffer_sRGB",
"WGL_ARB_pbuffer",
"WGL_ARB_multisample",
"WGL_ARB_pixel_format",
"WGL_ARB_pixel_format_float",
Expand Down

0 comments on commit 6f987dd

Please sign in to comment.