Skip to content

Commit 23e4ca1

Browse files
authored
wgl: add support for pbuffer surfaces
1 parent 7e46179 commit 23e4ca1

File tree

6 files changed

+160
-45
lines changed

6 files changed

+160
-45
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Added support for `DrmDisplayHandle` in EGL's `Display::with_device()` using `EGL_DRM_MASTER_FD_EXT` from `EGL_EXT_device_drm`.
1111
- Properly set up OpenGL-specific stuff on the `NSView`, instead of relying on Winit to do it.
1212
- Added `OpenHarmony` platform support with EGL.
13+
- Added support for `Display::create_pbuffer_surface()` in WGL via `WGL_ARB_pbuffer`.
1314

1415
# Version 0.32.0
1516

glutin/src/api/wgl/config.rs

+5
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ impl Display {
237237
attrs.push(1);
238238
}
239239

240+
if template.config_surface_types.contains(ConfigSurfaceTypes::PBUFFER) {
241+
attrs.push(wgl_extra::DRAW_TO_PBUFFER_ARB as c_int);
242+
attrs.push(1);
243+
}
244+
240245
if template.transparency {
241246
attrs.push(wgl_extra::TRANSPARENT_ARB as c_int);
242247
attrs.push(1);

glutin/src/api/wgl/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl ContextInner {
387387

388388
fn make_current<T: SurfaceTypeTrait>(&self, surface: &Surface<T>) -> Result<()> {
389389
unsafe {
390-
if wgl::MakeCurrent(surface.hdc as _, self.raw.cast()) == 0 {
390+
if wgl::MakeCurrent(surface.raw.hdc() as _, self.raw.cast()) == 0 {
391391
Err(IoError::last_os_error().into())
392392
} else {
393393
Ok(())

glutin/src/api/wgl/surface.rs

+150-42
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
use std::io::Error as IoError;
44
use std::marker::PhantomData;
55
use std::num::NonZeroU32;
6+
use std::os::raw::c_int;
67
use std::{fmt, mem};
78

9+
use glutin_wgl_sys::wgl::types::GLenum;
10+
use glutin_wgl_sys::wgl_extra::types::HPBUFFEREXT;
11+
use glutin_wgl_sys::wgl_extra::{self};
812
use raw_window_handle::RawWindowHandle;
913
use windows_sys::Win32::Foundation::{HWND, RECT};
1014
use windows_sys::Win32::Graphics::Gdi::HDC;
@@ -36,10 +40,50 @@ impl Display {
3640

3741
pub(crate) unsafe fn create_pbuffer_surface(
3842
&self,
39-
_config: &Config,
40-
_surface_attributes: &SurfaceAttributes<PbufferSurface>,
43+
config: &Config,
44+
surface_attributes: &SurfaceAttributes<PbufferSurface>,
4145
) -> Result<Surface<PbufferSurface>> {
42-
Err(ErrorKind::NotSupported("pbuffers are not implemented with WGL").into())
46+
let extra = self
47+
.inner
48+
.wgl_extra
49+
.filter(|_| self.inner.client_extensions.contains("WGL_ARB_pbuffer"))
50+
.ok_or(ErrorKind::NotSupported("pbuffer extensions are not supported"))?;
51+
52+
let hdc = config.inner.hdc;
53+
let width = surface_attributes.width.unwrap().get() as c_int;
54+
let height = surface_attributes.height.unwrap().get() as c_int;
55+
let mut attrs = [0; 3];
56+
if surface_attributes.largest_pbuffer {
57+
attrs[0] = wgl_extra::PBUFFER_LARGEST_ARB as c_int;
58+
attrs[1] = 1;
59+
}
60+
61+
let hbuf = unsafe {
62+
extra.CreatePbufferARB(
63+
hdc as _,
64+
config.inner.pixel_format_index,
65+
width,
66+
height,
67+
attrs.as_ptr(),
68+
)
69+
};
70+
if hbuf.is_null() {
71+
return Err(IoError::last_os_error().into());
72+
}
73+
74+
let hdc = unsafe { extra.GetPbufferDCARB(hbuf) };
75+
if hdc.is_null() {
76+
return Err(IoError::last_os_error().into());
77+
}
78+
79+
let surface = Surface {
80+
display: self.clone(),
81+
config: config.clone(),
82+
raw: WglSurface::PBuffer(hbuf, hdc as _),
83+
_ty: PhantomData,
84+
};
85+
86+
Ok(surface)
4387
}
4488

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

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

64-
let surface =
65-
Surface { display: self.clone(), config: config.clone(), hwnd, hdc, _ty: PhantomData };
108+
let surface = Surface {
109+
display: self.clone(),
110+
config: config.clone(),
111+
raw: WglSurface::Window(hwnd, hdc),
112+
_ty: PhantomData,
113+
};
66114

67115
Ok(surface)
68116
}
69117
}
70118

71-
/// A Wrapper around `HWND`.
119+
/// A Wrapper around `WglSurface`.
72120
pub struct Surface<T: SurfaceTypeTrait> {
73121
display: Display,
74122
config: Config,
75-
pub(crate) hwnd: HWND,
76-
pub(crate) hdc: HDC,
123+
pub(crate) raw: WglSurface,
77124
_ty: PhantomData<T>,
78125
}
79126

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

130+
impl<T: SurfaceTypeTrait> Surface<T> {
131+
fn raw_attribute(&self, attr: GLenum) -> Option<c_int> {
132+
match self.raw {
133+
WglSurface::Window(..) => None,
134+
WglSurface::PBuffer(hbuf, _) => {
135+
let extra = self.display.inner.wgl_extra.unwrap();
136+
let mut value = 0;
137+
if unsafe { extra.QueryPbufferARB(hbuf, attr as _, &mut value) } == false.into() {
138+
None
139+
} else {
140+
Some(value)
141+
}
142+
},
143+
}
144+
}
145+
}
146+
83147
impl<T: SurfaceTypeTrait> Drop for Surface<T> {
84148
fn drop(&mut self) {
85149
unsafe {
86-
gdi::ReleaseDC(self.hwnd, self.hdc);
150+
match self.raw {
151+
WglSurface::Window(hwnd, hdc) => {
152+
gdi::ReleaseDC(hwnd, hdc);
153+
},
154+
WglSurface::PBuffer(hbuf, hdc) => {
155+
let extra = self.display.inner.wgl_extra.unwrap();
156+
extra.ReleasePbufferDCARB(hbuf, hdc as _);
157+
extra.DestroyPbufferARB(hbuf);
158+
},
159+
}
87160
}
88161
}
89162
}
@@ -97,20 +170,34 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
97170
}
98171

99172
fn width(&self) -> Option<u32> {
100-
let mut rect: RECT = unsafe { mem::zeroed() };
101-
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
102-
None
103-
} else {
104-
Some((rect.right - rect.left) as u32)
173+
match self.raw {
174+
WglSurface::Window(hwnd, _) => {
175+
let mut rect: RECT = unsafe { mem::zeroed() };
176+
if unsafe { GetClientRect(hwnd, &mut rect) } == false.into() {
177+
None
178+
} else {
179+
Some((rect.right - rect.left) as u32)
180+
}
181+
},
182+
WglSurface::PBuffer(..) => {
183+
self.raw_attribute(wgl_extra::PBUFFER_WIDTH_ARB).map(|x| x as _)
184+
},
105185
}
106186
}
107187

108188
fn height(&self) -> Option<u32> {
109-
let mut rect: RECT = unsafe { mem::zeroed() };
110-
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
111-
None
112-
} else {
113-
Some((rect.bottom - rect.top) as u32)
189+
match self.raw {
190+
WglSurface::Window(hwnd, _) => {
191+
let mut rect: RECT = unsafe { mem::zeroed() };
192+
if unsafe { GetClientRect(hwnd, &mut rect) } == false.into() {
193+
None
194+
} else {
195+
Some((rect.bottom - rect.top) as u32)
196+
}
197+
},
198+
WglSurface::PBuffer(..) => {
199+
self.raw_attribute(wgl_extra::PBUFFER_HEIGHT_ARB).map(|x| x as _)
200+
},
114201
}
115202
}
116203

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

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

131218
fn set_swap_interval(&self, _context: &Self::Context, interval: SwapInterval) -> Result<()> {
132-
let interval = match interval {
133-
SwapInterval::DontWait => 0,
134-
SwapInterval::Wait(n) => n.get(),
135-
};
136-
137-
let res = match self.display.inner.wgl_extra {
138-
Some(extra) if self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL) => unsafe {
139-
extra.SwapIntervalEXT(interval as _)
140-
},
141-
_ => {
142-
return Err(
143-
ErrorKind::NotSupported("swap control extensions are not supported").into()
144-
)
219+
match self.raw {
220+
WglSurface::Window(..) => {
221+
let extra = self
222+
.display
223+
.inner
224+
.wgl_extra
225+
.filter(|_| self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL))
226+
.ok_or(ErrorKind::NotSupported("swap control extensions are not supported"))?;
227+
228+
let interval = match interval {
229+
SwapInterval::DontWait => 0,
230+
SwapInterval::Wait(n) => n.get(),
231+
};
232+
233+
if unsafe { extra.SwapIntervalEXT(interval as _) } == 0 {
234+
Err(IoError::last_os_error().into())
235+
} else {
236+
Ok(())
237+
}
145238
},
146-
};
147-
148-
if res == 0 {
149-
Err(IoError::last_os_error().into())
150-
} else {
151-
Ok(())
239+
_ => Err(ErrorKind::NotSupported("swap control not supported for surface").into()),
152240
}
153241
}
154242

@@ -173,15 +261,17 @@ impl<T: SurfaceTypeTrait> fmt::Debug for Surface<T> {
173261
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174262
f.debug_struct("Surface")
175263
.field("config", &self.config.inner.pixel_format_index)
176-
.field("hwnd", &self.hwnd)
177-
.field("hdc", &self.hdc)
264+
.field("raw", &self.raw)
178265
.finish()
179266
}
180267
}
181268

182269
impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
183270
fn raw_surface(&self) -> RawSurface {
184-
RawSurface::Wgl(self.hwnd as _)
271+
match self.raw {
272+
WglSurface::Window(hwnd, _) => RawSurface::Wgl(hwnd as _),
273+
WglSurface::PBuffer(hbuf, _) => RawSurface::Wgl(hbuf as _),
274+
}
185275
}
186276
}
187277

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

204294
impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}
295+
296+
/// A wrapper around WGL surfaces.
297+
#[derive(Debug)]
298+
pub enum WglSurface {
299+
/// Surface backed by a window surface.
300+
Window(HWND, HDC),
301+
/// Surface backed by a pixel buffer.
302+
PBuffer(HPBUFFEREXT, HDC),
303+
}
304+
305+
impl WglSurface {
306+
pub(crate) fn hdc(&self) -> HDC {
307+
*match self {
308+
WglSurface::Window(_, hdc) => hdc,
309+
WglSurface::PBuffer(_, hdc) => hdc,
310+
}
311+
}
312+
}

glutin/src/surface.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ pub enum RawSurface {
519519
#[cfg(glx_backend)]
520520
Glx(u64),
521521

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

glutin_wgl_sys/build.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ fn main() {
1818
let mut file = File::create(dest.join("wgl_extra_bindings.rs")).unwrap();
1919
Registry::new(Api::Wgl, (1, 0), Profile::Core, Fallbacks::All, [
2020
"WGL_ARB_context_flush_control",
21-
"WGL_ARB_create_context",
2221
"WGL_ARB_create_context_no_error",
2322
"WGL_ARB_create_context_profile",
2423
"WGL_ARB_create_context_robustness",
24+
"WGL_ARB_create_context",
2525
"WGL_ARB_extensions_string",
2626
"WGL_ARB_framebuffer_sRGB",
27+
"WGL_ARB_pbuffer",
2728
"WGL_ARB_multisample",
2829
"WGL_ARB_pixel_format",
2930
"WGL_ARB_pixel_format_float",

0 commit comments

Comments
 (0)