Skip to content

Commit

Permalink
wgl: add support for pbuffer surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
SK83RJOSH authored Sep 22, 2024
1 parent 7e46179 commit 23e4ca1
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 45 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- 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 `OpenHarmony` platform support with EGL.
- 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
2 changes: 1 addition & 1 deletion glutin/src/api/wgl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl ContextInner {

fn make_current<T: SurfaceTypeTrait>(&self, surface: &Surface<T>) -> Result<()> {
unsafe {
if wgl::MakeCurrent(surface.hdc as _, self.raw.cast()) == 0 {
if wgl::MakeCurrent(surface.raw.hdc() as _, self.raw.cast()) == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
Expand Down
192 changes: 150 additions & 42 deletions glutin/src/api/wgl/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
use std::io::Error as IoError;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::os::raw::c_int;
use std::{fmt, mem};

use glutin_wgl_sys::wgl::types::GLenum;
use glutin_wgl_sys::wgl_extra::types::HPBUFFEREXT;
use glutin_wgl_sys::wgl_extra::{self};
use raw_window_handle::RawWindowHandle;
use windows_sys::Win32::Foundation::{HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::HDC;
Expand Down Expand Up @@ -36,10 +40,50 @@ 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 extra = self
.inner
.wgl_extra
.filter(|_| self.inner.client_extensions.contains("WGL_ARB_pbuffer"))
.ok_or(ErrorKind::NotSupported("pbuffer extensions are not supported"))?;

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 = [0; 3];
if surface_attributes.largest_pbuffer {
attrs[0] = wgl_extra::PBUFFER_LARGEST_ARB as c_int;
attrs[1] = 1;
}

let hbuf = unsafe {
extra.CreatePbufferARB(
hdc as _,
config.inner.pixel_format_index,
width,
height,
attrs.as_ptr(),
)
};
if hbuf.is_null() {
return Err(IoError::last_os_error().into());
}

let hdc = unsafe { extra.GetPbufferDCARB(hbuf) };
if hdc.is_null() {
return Err(IoError::last_os_error().into());
}

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

Ok(surface)
}

pub(crate) unsafe fn create_window_surface(
Expand All @@ -61,29 +105,58 @@ impl Display {

let hdc = unsafe { gdi::GetDC(hwnd) };

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

Ok(surface)
}
}

/// A Wrapper around `HWND`.
/// 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> {
fn raw_attribute(&self, attr: GLenum) -> Option<c_int> {
match self.raw {
WglSurface::Window(..) => None,
WglSurface::PBuffer(hbuf, _) => {
let extra = self.display.inner.wgl_extra.unwrap();
let mut value = 0;
if unsafe { extra.QueryPbufferARB(hbuf, attr as _, &mut value) } == false.into() {
None
} else {
Some(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) => {
let extra = self.display.inner.wgl_extra.unwrap();
extra.ReleasePbufferDCARB(hbuf, hdc as _);
extra.DestroyPbufferARB(hbuf);
},
}
}
}
}
Expand All @@ -97,20 +170,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(..) => {
self.raw_attribute(wgl_extra::PBUFFER_WIDTH_ARB).map(|x| x 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(..) => {
self.raw_attribute(wgl_extra::PBUFFER_HEIGHT_ARB).map(|x| x as _)
},
}
}

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

fn swap_buffers(&self, _context: &Self::Context) -> Result<()> {
unsafe {
if gl::SwapBuffers(self.hdc) == 0 {
if gl::SwapBuffers(self.raw.hdc()) == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
Expand All @@ -129,26 +216,27 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
}

fn set_swap_interval(&self, _context: &Self::Context, interval: SwapInterval) -> Result<()> {
let interval = match interval {
SwapInterval::DontWait => 0,
SwapInterval::Wait(n) => n.get(),
};

let res = match self.display.inner.wgl_extra {
Some(extra) if self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL) => unsafe {
extra.SwapIntervalEXT(interval as _)
},
_ => {
return Err(
ErrorKind::NotSupported("swap control extensions are not supported").into()
)
match self.raw {
WglSurface::Window(..) => {
let extra = self
.display
.inner
.wgl_extra
.filter(|_| self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL))
.ok_or(ErrorKind::NotSupported("swap control extensions are not supported"))?;

let interval = match interval {
SwapInterval::DontWait => 0,
SwapInterval::Wait(n) => n.get(),
};

if unsafe { extra.SwapIntervalEXT(interval as _) } == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
}
},
};

if res == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
_ => Err(ErrorKind::NotSupported("swap control not supported for surface").into()),
}
}

Expand All @@ -173,15 +261,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(hbuf, _) => RawSurface::Wgl(hbuf as _),
}
}
}

Expand All @@ -202,3 +292,21 @@ impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> {
}

impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}

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

impl WglSurface {
pub(crate) fn hdc(&self) -> HDC {
*match self {
WglSurface::Window(_, hdc) => hdc,
WglSurface::PBuffer(_, hdc) => hdc,
}
}
}
2 changes: 1 addition & 1 deletion glutin/src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ pub enum RawSurface {
#[cfg(glx_backend)]
Glx(u64),

/// HWND
/// Either a `HWND` or `HPBUFFEREXT` depending on [`SurfaceType`].
#[cfg(wgl_backend)]
Wgl(*const std::ffi::c_void),

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 23e4ca1

Please sign in to comment.