11use super :: { GlConfig , GlError , Profile } ;
22use crate :: x11:: XcbConnection ;
33use std:: ffi:: { c_void, CString } ;
4- use std:: os:: raw:: { c_int , c_ulong} ;
4+ use std:: os:: raw:: c_ulong;
55use std:: rc:: Rc ;
66use x11_dl:: error:: OpenError ;
7- use x11_dl:: glx;
8- use x11_dl:: glx:: Glx ;
9- use x11_dl:: xlib;
7+ use x11_dl:: glx:: { __GLXFBConfigRec, GLXContext } ;
108
119mod errors;
10+ mod glx;
11+ use glx:: Glx ;
1212
1313#[ derive( Debug ) ]
1414pub enum CreationFailedError {
15- InvalidFBConfig ,
15+ NoValidFBConfig ,
1616 NoVisual ,
1717 GetProcAddressFailed ,
1818 MakeCurrentFailed ,
@@ -33,42 +33,27 @@ impl From<OpenError> for GlError {
3333 }
3434}
3535
36- // See https://www.khronos.org/registry/OpenGL/extensions/ARB/GLX_ARB_create_context.txt
37-
38- type GlXCreateContextAttribsARB = unsafe extern "C" fn (
39- dpy : * mut xlib:: Display ,
40- fbc : glx:: GLXFBConfig ,
41- share_context : glx:: GLXContext ,
42- direct : xlib:: Bool ,
43- attribs : * const c_int ,
44- ) -> glx:: GLXContext ;
45-
46- // See https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_swap_control.txt
47-
48- type GlXSwapIntervalEXT =
49- unsafe extern "C" fn ( dpy : * mut xlib:: Display , drawable : glx:: GLXDrawable , interval : i32 ) ;
50-
51- // See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
52-
53- const GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB : i32 = 0x20B2 ;
54-
5536fn get_proc_address ( glx : & Glx , symbol : & str ) -> * const c_void {
5637 let symbol = CString :: new ( symbol) . unwrap ( ) ;
57- unsafe { ( glx. glXGetProcAddress ) ( symbol. as_ptr ( ) as * const u8 ) . unwrap ( ) as * const c_void }
38+
39+ match glx. get_proc_address ( & symbol) {
40+ Some ( ptr) => ptr. as_ptr ( ) ,
41+ None => std:: ptr:: null ( ) ,
42+ }
5843}
5944
6045pub struct GlContext {
6146 glx : Glx ,
6247 window : c_ulong ,
6348 connection : Rc < XcbConnection > ,
64- context : glx :: GLXContext ,
49+ context : GLXContext ,
6550}
6651
6752/// The frame buffer configuration along with the general OpenGL configuration to somewhat minimize
6853/// misuse.
6954pub struct FbConfig {
7055 gl_config : GlConfig ,
71- fb_config : * mut glx :: __GLXFBConfigRec ,
56+ fb_config : * mut __GLXFBConfigRec ,
7257}
7358
7459/// The configuration a window should be created with after calling
@@ -93,70 +78,21 @@ impl GlContext {
9378 let glx = Glx :: open ( ) ?;
9479
9580 let context = errors:: XErrorHandler :: handle ( & connection, |error_handler| {
96- #[ allow( non_snake_case) ]
97- let glXCreateContextAttribsARB: GlXCreateContextAttribsARB = {
98- let addr = get_proc_address ( & glx, "glXCreateContextAttribsARB" ) ;
99- if addr. is_null ( ) {
100- return Err ( GlError :: CreationFailed ( CreationFailedError :: GetProcAddressFailed ) ) ;
101- } else {
102- #[ allow( clippy:: missing_transmute_annotations) ]
103- std:: mem:: transmute ( addr)
104- }
105- } ;
106-
107- #[ allow( non_snake_case) ]
108- let glXSwapIntervalEXT: GlXSwapIntervalEXT = {
109- let addr = get_proc_address ( & glx, "glXSwapIntervalEXT" ) ;
110- if addr. is_null ( ) {
111- return Err ( GlError :: CreationFailed ( CreationFailedError :: GetProcAddressFailed ) ) ;
112- } else {
113- #[ allow( clippy:: missing_transmute_annotations) ]
114- std:: mem:: transmute ( addr)
115- }
81+ let Some ( create_context) = glx. get_glx_create_context_attribs_arb ( ) else {
82+ return Err ( GlError :: CreationFailed ( CreationFailedError :: GetProcAddressFailed ) ) ;
11683 } ;
11784
118- error_handler. check ( ) ?;
119-
120- let profile_mask = match config. gl_config . profile {
121- Profile :: Core => glx:: arb:: GLX_CONTEXT_CORE_PROFILE_BIT_ARB ,
122- Profile :: Compatibility => glx:: arb:: GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ,
85+ let Some ( swap_interval) = glx. get_glx_swap_interval_ext ( ) else {
86+ return Err ( GlError :: CreationFailed ( CreationFailedError :: GetProcAddressFailed ) ) ;
12387 } ;
12488
125- #[ rustfmt:: skip]
126- let ctx_attribs = [
127- glx:: arb:: GLX_CONTEXT_MAJOR_VERSION_ARB , config. gl_config . version . 0 as i32 ,
128- glx:: arb:: GLX_CONTEXT_MINOR_VERSION_ARB , config. gl_config . version . 1 as i32 ,
129- glx:: arb:: GLX_CONTEXT_PROFILE_MASK_ARB , profile_mask,
130- 0 ,
131- ] ;
132-
133- let context = glXCreateContextAttribsARB (
134- connection. dpy ,
135- config. fb_config ,
136- std:: ptr:: null_mut ( ) ,
137- 1 ,
138- ctx_attribs. as_ptr ( ) ,
139- ) ;
89+ let context = create_context. call ( & connection, & config, error_handler) ?;
14090
141- error_handler. check ( ) ?;
142-
143- if context. is_null ( ) {
144- return Err ( GlError :: CreationFailed ( CreationFailedError :: ContextCreationFailed ) ) ;
145- }
146-
147- let res = ( glx. glXMakeCurrent ) ( connection. dpy , window, context) ;
148- error_handler. check ( ) ?;
149- if res == 0 {
150- return Err ( GlError :: CreationFailed ( CreationFailedError :: MakeCurrentFailed ) ) ;
151- }
152-
153- glXSwapIntervalEXT ( connection. dpy , window, config. gl_config . vsync as i32 ) ;
154- error_handler. check ( ) ?;
155-
156- if ( glx. glXMakeCurrent ) ( connection. dpy , 0 , std:: ptr:: null_mut ( ) ) == 0 {
157- error_handler. check ( ) ?;
158- return Err ( GlError :: CreationFailed ( CreationFailedError :: MakeCurrentFailed ) ) ;
159- }
91+ // TODO: handle errors here leaking the context
92+ glx. with_current_context ( & connection, window, context, error_handler, || {
93+ swap_interval ( connection. dpy , window, config. gl_config . vsync as i32 ) ;
94+ error_handler. check ( )
95+ } ) ??;
16096
16197 Ok ( context)
16298 } ) ?;
@@ -173,45 +109,11 @@ impl GlContext {
173109 let glx = Glx :: open ( ) ?;
174110
175111 errors:: XErrorHandler :: handle ( conn, |error_handler| {
176- let screen = conn. screen ;
177-
178- #[ rustfmt:: skip]
179- let fb_attribs = [
180- glx:: GLX_X_RENDERABLE , 1 ,
181- glx:: GLX_X_VISUAL_TYPE , glx:: GLX_TRUE_COLOR ,
182- glx:: GLX_DRAWABLE_TYPE , glx:: GLX_WINDOW_BIT ,
183- glx:: GLX_RENDER_TYPE , glx:: GLX_RGBA_BIT ,
184- glx:: GLX_RED_SIZE , config. red_bits as i32 ,
185- glx:: GLX_GREEN_SIZE , config. green_bits as i32 ,
186- glx:: GLX_BLUE_SIZE , config. blue_bits as i32 ,
187- glx:: GLX_ALPHA_SIZE , config. alpha_bits as i32 ,
188- glx:: GLX_DEPTH_SIZE , config. depth_bits as i32 ,
189- glx:: GLX_STENCIL_SIZE , config. stencil_bits as i32 ,
190- glx:: GLX_DOUBLEBUFFER , config. double_buffer as i32 ,
191- glx:: GLX_SAMPLE_BUFFERS , config. samples . is_some ( ) as i32 ,
192- glx:: GLX_SAMPLES , config. samples . unwrap_or ( 0 ) as i32 ,
193- GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB , config. srgb as i32 ,
194- 0 ,
195- ] ;
196-
197- let mut n_configs = 0 ;
198- let fb_config = unsafe {
199- ( glx. glXChooseFBConfig ) ( conn. dpy , screen, fb_attribs. as_ptr ( ) , & mut n_configs)
200- } ;
201-
202- error_handler. check ( ) ?;
203- if n_configs <= 0 || fb_config. is_null ( ) {
204- return Err ( GlError :: CreationFailed ( CreationFailedError :: InvalidFBConfig ) ) ;
205- }
112+ let fb_config = glx. choose_best_fb_config ( conn, & config, error_handler) ?;
206113
207114 // Now that we have a matching framebuffer config, we need to know which visual matches
208115 // thsi config so the window is compatible with the OpenGL context we're about to create
209- let fb_config = unsafe { fb_config. read ( ) } ;
210- let visual = unsafe { ( glx. glXGetVisualFromFBConfig ) ( conn. dpy , fb_config) } ;
211- if visual. is_null ( ) {
212- return Err ( GlError :: CreationFailed ( CreationFailedError :: NoVisual ) ) ;
213- }
214- let visual = unsafe { visual. read ( ) } ;
116+ let visual = glx. get_visual_from_fb_config ( conn, fb_config, error_handler) ?;
215117
216118 Ok ( (
217119 FbConfig { fb_config, gl_config : config } ,
@@ -222,21 +124,15 @@ impl GlContext {
222124
223125 pub unsafe fn make_current ( & self ) {
224126 errors:: XErrorHandler :: handle ( & self . connection , |error_handler| {
225- let res = ( self . glx . glXMakeCurrent ) ( self . connection . dpy , self . window , self . context ) ;
226- error_handler. check ( ) . unwrap ( ) ;
227- if res == 0 {
228- panic ! ( "make_current failed" )
229- }
127+ self . glx
128+ . make_current ( & self . connection , self . window , self . context , error_handler)
129+ . unwrap ( ) ;
230130 } )
231131 }
232132
233133 pub unsafe fn make_not_current ( & self ) {
234134 errors:: XErrorHandler :: handle ( & self . connection , |error_handler| {
235- let res = ( self . glx . glXMakeCurrent ) ( self . connection . dpy , 0 , std:: ptr:: null_mut ( ) ) ;
236- error_handler. check ( ) . unwrap ( ) ;
237- if res == 0 {
238- panic ! ( "make_not_current failed" )
239- }
135+ self . glx . clear_current ( & self . connection , error_handler) . unwrap ( ) ;
240136 } )
241137 }
242138
@@ -245,12 +141,9 @@ impl GlContext {
245141 }
246142
247143 pub fn swap_buffers ( & self ) {
248- unsafe {
249- errors:: XErrorHandler :: handle ( & self . connection , |error_handler| {
250- ( self . glx . glXSwapBuffers ) ( self . connection . dpy , self . window ) ;
251- error_handler. check ( ) . unwrap ( ) ;
252- } )
253- }
144+ errors:: XErrorHandler :: handle ( & self . connection , |error_handler| {
145+ self . glx . swap_buffers ( & self . connection , self . window , error_handler) . unwrap ( )
146+ } )
254147 }
255148}
256149
0 commit comments