1#![allow(unreachable_patterns)]
3
4use std::marker::PhantomData;
5use std::num::NonZeroU32;
6
7use raw_window_handle::RawWindowHandle;
8
9use crate::context::{PossiblyCurrentContext, PossiblyCurrentGlContext};
10use crate::display::{Display, GetGlDisplay};
11use crate::error::Result;
12use crate::private::{gl_api_dispatch, Sealed};
13
14#[cfg(cgl_backend)]
15use crate::api::cgl::surface::Surface as CglSurface;
16#[cfg(egl_backend)]
17use crate::api::egl::surface::Surface as EglSurface;
18#[cfg(glx_backend)]
19use crate::api::glx::surface::Surface as GlxSurface;
20#[cfg(wgl_backend)]
21use crate::api::wgl::surface::Surface as WglSurface;
22
23pub trait GlSurface<T: SurfaceTypeTrait>: Sealed {
25 type SurfaceType: SurfaceTypeTrait;
27 type Context: PossiblyCurrentGlContext;
29
30 fn buffer_age(&self) -> u32;
40
41 fn width(&self) -> Option<u32>;
43
44 fn height(&self) -> Option<u32>;
50
51 fn is_single_buffered(&self) -> bool;
57
58 fn swap_buffers(&self, context: &Self::Context) -> Result<()>;
61
62 fn is_current(&self, context: &Self::Context) -> bool;
64
65 fn is_current_draw(&self, context: &Self::Context) -> bool;
68
69 fn is_current_read(&self, context: &Self::Context) -> bool;
72
73 fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()>;
77
78 fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32)
91 where
92 Self::SurfaceType: ResizeableSurface;
93}
94
95pub trait SurfaceTypeTrait: Sealed {
97 fn surface_type() -> SurfaceType;
99}
100
101pub trait ResizeableSurface: Sealed {}
103
104pub trait AsRawSurface {
106 fn raw_surface(&self) -> RawSurface;
108}
109
110#[derive(Default, Debug, Clone)]
112pub struct SurfaceAttributesBuilder<T: SurfaceTypeTrait + Default> {
113 attributes: SurfaceAttributes<T>,
114}
115
116impl<T: SurfaceTypeTrait + Default> SurfaceAttributesBuilder<T> {
117 pub fn new() -> Self {
119 Default::default()
120 }
121
122 pub fn with_srgb(mut self, srgb: Option<bool>) -> Self {
130 self.attributes.srgb = srgb;
131 self
132 }
133}
134
135impl SurfaceAttributesBuilder<WindowSurface> {
136 pub fn with_single_buffer(mut self, single_buffer: bool) -> Self {
147 self.attributes.single_buffer = single_buffer;
148 self
149 }
150
151 pub fn build(
153 mut self,
154 raw_window_handle: RawWindowHandle,
155 width: NonZeroU32,
156 height: NonZeroU32,
157 ) -> SurfaceAttributes<WindowSurface> {
158 self.attributes.raw_window_handle = Some(raw_window_handle);
159 self.attributes.width = Some(width);
160 self.attributes.height = Some(height);
161 self.attributes
162 }
163}
164
165impl SurfaceAttributesBuilder<PbufferSurface> {
166 pub fn with_largest_pbuffer(mut self, largest_pbuffer: bool) -> Self {
168 self.attributes.largest_pbuffer = largest_pbuffer;
169 self
170 }
171
172 pub fn with_single_buffer(mut self, single_buffer: bool) -> Self {
175 self.attributes.single_buffer = single_buffer;
176 self
177 }
178
179 pub fn build(
181 mut self,
182 width: NonZeroU32,
183 height: NonZeroU32,
184 ) -> SurfaceAttributes<PbufferSurface> {
185 self.attributes.width = Some(width);
186 self.attributes.height = Some(height);
187 self.attributes
188 }
189}
190
191impl SurfaceAttributesBuilder<PixmapSurface> {
192 pub fn build(mut self, native_pixmap: NativePixmap) -> SurfaceAttributes<PixmapSurface> {
194 self.attributes.native_pixmap = Some(native_pixmap);
195 self.attributes
196 }
197}
198
199#[derive(Default, Debug, Clone)]
201pub struct SurfaceAttributes<T: SurfaceTypeTrait> {
202 pub(crate) srgb: Option<bool>,
203 pub(crate) single_buffer: bool,
204 pub(crate) width: Option<NonZeroU32>,
205 pub(crate) height: Option<NonZeroU32>,
206 pub(crate) largest_pbuffer: bool,
207 pub(crate) raw_window_handle: Option<RawWindowHandle>,
208 pub(crate) native_pixmap: Option<NativePixmap>,
209 _ty: PhantomData<T>,
210}
211
212#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
214pub struct WindowSurface;
215
216impl SurfaceTypeTrait for WindowSurface {
217 fn surface_type() -> SurfaceType {
218 SurfaceType::Window
219 }
220}
221
222impl ResizeableSurface for WindowSurface {}
223
224impl Sealed for WindowSurface {}
225
226#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
228pub struct PbufferSurface;
229
230impl SurfaceTypeTrait for PbufferSurface {
231 fn surface_type() -> SurfaceType {
232 SurfaceType::Pbuffer
233 }
234}
235
236impl Sealed for PbufferSurface {}
237
238#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
240pub struct PixmapSurface;
241
242impl SurfaceTypeTrait for PixmapSurface {
243 fn surface_type() -> SurfaceType {
244 SurfaceType::Pixmap
245 }
246}
247
248impl Sealed for PixmapSurface {}
249
250#[derive(Debug, Clone, Copy)]
252pub enum SurfaceType {
253 Window,
255
256 Pixmap,
258
259 Pbuffer,
261}
262
263#[derive(Debug)]
278pub enum Surface<T: SurfaceTypeTrait> {
279 #[cfg(egl_backend)]
281 Egl(EglSurface<T>),
282
283 #[cfg(glx_backend)]
285 Glx(GlxSurface<T>),
286
287 #[cfg(wgl_backend)]
289 Wgl(WglSurface<T>),
290
291 #[cfg(cgl_backend)]
293 Cgl(CglSurface<T>),
294}
295
296impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
297 type Context = PossiblyCurrentContext;
298 type SurfaceType = T;
299
300 fn buffer_age(&self) -> u32 {
301 gl_api_dispatch!(self; Self(surface) => surface.buffer_age())
302 }
303
304 fn width(&self) -> Option<u32> {
305 gl_api_dispatch!(self; Self(surface) => surface.width())
306 }
307
308 fn height(&self) -> Option<u32> {
309 gl_api_dispatch!(self; Self(surface) => surface.height())
310 }
311
312 fn is_single_buffered(&self) -> bool {
313 gl_api_dispatch!(self; Self(surface) => surface.is_single_buffered())
314 }
315
316 fn swap_buffers(&self, context: &Self::Context) -> Result<()> {
317 match (self, context) {
318 #[cfg(egl_backend)]
319 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
320 surface.swap_buffers(context)
321 },
322 #[cfg(glx_backend)]
323 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
324 surface.swap_buffers(context)
325 },
326 #[cfg(cgl_backend)]
327 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
328 surface.swap_buffers(context)
329 },
330 #[cfg(wgl_backend)]
331 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
332 surface.swap_buffers(context)
333 },
334 _ => unreachable!(),
335 }
336 }
337
338 fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()> {
339 match (self, context) {
340 #[cfg(egl_backend)]
341 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
342 surface.set_swap_interval(context, interval)
343 },
344 #[cfg(glx_backend)]
345 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
346 surface.set_swap_interval(context, interval)
347 },
348 #[cfg(cgl_backend)]
349 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
350 surface.set_swap_interval(context, interval)
351 },
352 #[cfg(wgl_backend)]
353 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
354 surface.set_swap_interval(context, interval)
355 },
356 _ => unreachable!(),
357 }
358 }
359
360 fn is_current(&self, context: &Self::Context) -> bool {
361 match (self, context) {
362 #[cfg(egl_backend)]
363 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
364 surface.is_current(context)
365 },
366 #[cfg(glx_backend)]
367 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
368 surface.is_current(context)
369 },
370 #[cfg(cgl_backend)]
371 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
372 surface.is_current(context)
373 },
374 #[cfg(wgl_backend)]
375 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
376 surface.is_current(context)
377 },
378 _ => unreachable!(),
379 }
380 }
381
382 fn is_current_draw(&self, context: &Self::Context) -> bool {
383 match (self, context) {
384 #[cfg(egl_backend)]
385 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
386 surface.is_current_draw(context)
387 },
388 #[cfg(glx_backend)]
389 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
390 surface.is_current_draw(context)
391 },
392 #[cfg(cgl_backend)]
393 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
394 surface.is_current_draw(context)
395 },
396 #[cfg(wgl_backend)]
397 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
398 surface.is_current_draw(context)
399 },
400 _ => unreachable!(),
401 }
402 }
403
404 fn is_current_read(&self, context: &Self::Context) -> bool {
405 match (self, context) {
406 #[cfg(egl_backend)]
407 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
408 surface.is_current_read(context)
409 },
410 #[cfg(glx_backend)]
411 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
412 surface.is_current_read(context)
413 },
414 #[cfg(cgl_backend)]
415 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
416 surface.is_current_read(context)
417 },
418 #[cfg(wgl_backend)]
419 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
420 surface.is_current_read(context)
421 },
422 _ => unreachable!(),
423 }
424 }
425
426 fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32)
427 where
428 Self::SurfaceType: ResizeableSurface,
429 {
430 match (self, context) {
431 #[cfg(egl_backend)]
432 (Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
433 surface.resize(context, width, height)
434 },
435 #[cfg(glx_backend)]
436 (Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
437 surface.resize(context, width, height)
438 },
439 #[cfg(cgl_backend)]
440 (Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
441 surface.resize(context, width, height)
442 },
443 #[cfg(wgl_backend)]
444 (Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
445 surface.resize(context, width, height)
446 },
447 _ => unreachable!(),
448 }
449 }
450}
451
452impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> {
453 type Target = Display;
454
455 fn display(&self) -> Self::Target {
456 gl_api_dispatch!(self; Self(surface) => surface.display(); as Display)
457 }
458}
459
460impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
461 fn raw_surface(&self) -> RawSurface {
462 gl_api_dispatch!(self; Self(surface) => surface.raw_surface())
463 }
464}
465
466impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}
467
468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
488pub enum SwapInterval {
489 DontWait,
492
493 Wait(NonZeroU32),
496}
497
498#[derive(Debug, Clone, Copy, PartialEq, Eq)]
500pub enum NativePixmap {
501 XlibPixmap(std::os::raw::c_ulong),
503
504 XcbPixmap(u32),
506
507 WindowsPixmap(isize),
509}
510
511#[derive(Debug, Clone, Copy, PartialEq, Eq)]
513pub enum RawSurface {
514 #[cfg(egl_backend)]
516 Egl(*const std::ffi::c_void),
517
518 #[cfg(glx_backend)]
520 Glx(u64),
521
522 #[cfg(wgl_backend)]
524 Wgl(*const std::ffi::c_void),
525
526 #[cfg(cgl_backend)]
528 Cgl(*const std::ffi::c_void),
529}
530
531#[repr(C)]
535#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
536pub struct Rect {
537 pub x: i32,
539 pub y: i32,
541 pub width: i32,
543 pub height: i32,
545}
546
547impl Rect {
548 pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self {
550 Self { x, y, width, height }
551 }
552}