@@ -25,60 +25,61 @@ use super::wgl_ext;
25
25
pub unsafe fn create_offscreen ( shared_with : winapi:: HGLRC ,
26
26
settings : & WGLAttributes )
27
27
-> Result < ( winapi:: HGLRC , winapi:: HDC ) , String > {
28
-
29
- let window: winapi :: HWND = try!( create_hidden_window ( ) ) ;
30
- let hdc = user32:: GetDC ( window) ;
31
- if hdc . is_null ( ) {
28
+ let mut ctx = WGLScopedContext :: default ( ) ;
29
+ ctx . window = try!( create_hidden_window ( ) ) ;
30
+ ctx . device_ctx = user32:: GetDC ( ctx . window ) ;
31
+ if ctx . device_ctx . is_null ( ) {
32
32
return Err ( "GetDC function failed" . to_owned ( ) ) ;
33
33
}
34
34
35
- let extra = try!( load_extra_functions ( window) ) ;
35
+ let extra = try!( load_extra_functions ( ctx . window ) ) ;
36
36
37
37
let extensions = if extra. GetExtensionsStringARB . is_loaded ( ) {
38
- let data = extra. GetExtensionsStringARB ( hdc as * const _ ) ;
38
+ let data = extra. GetExtensionsStringARB ( ctx . device_ctx as * const _ ) ;
39
39
let data = CStr :: from_ptr ( data) . to_bytes ( ) . to_vec ( ) ;
40
40
String :: from_utf8 ( data) . unwrap ( )
41
-
42
41
} else if extra. GetExtensionsStringEXT . is_loaded ( ) {
43
42
let data = extra. GetExtensionsStringEXT ( ) ;
44
43
let data = CStr :: from_ptr ( data) . to_bytes ( ) . to_vec ( ) ;
45
44
String :: from_utf8 ( data) . unwrap ( )
46
-
47
45
} else {
48
46
String :: new ( )
49
47
} ;
50
48
51
-
52
49
let ( id, _) = if extensions. split ( ' ' ) . find ( |& i| i == "WGL_ARB_pixel_format" ) . is_some ( ) {
53
- try!( choose_arb_pixel_format ( & extra, & extensions, hdc , & settings. pixel_format )
54
- . map_err ( |_| "Pixel format not available" . to_owned ( ) ) )
50
+ try!( choose_arb_pixel_format ( & extra, & extensions, ctx . device_ctx , & settings. pixel_format )
51
+ . map_err ( |_| "ARB pixel format not available" . to_owned ( ) ) )
55
52
} else {
56
- try!( choose_native_pixel_format ( hdc , & settings. pixel_format )
57
- . map_err ( |_| "Pixel format not available" . to_owned ( ) ) )
53
+ try!( choose_native_pixel_format ( ctx . device_ctx , & settings. pixel_format )
54
+ . map_err ( |_| "Native pixel format not available" . to_owned ( ) ) )
58
55
} ;
59
56
60
- try!( set_pixel_format ( hdc, id) ) ;
61
-
62
- create_full_context ( settings, & extra, & extensions, hdc, shared_with)
57
+ try!( set_pixel_format ( ctx. device_ctx , id) ) ;
63
58
59
+ let result = create_full_context ( settings, & extra, & extensions, ctx. device_ctx , shared_with) ;
60
+ if result. is_ok ( ) {
61
+ ctx. dispose = false ; // Everything is ok, don't dispose the scoped ctx
62
+ }
63
+ result
64
64
}
65
65
66
66
// creates a basic context
67
67
unsafe fn create_basic_context ( hdc : winapi:: HDC ,
68
68
share : winapi:: HGLRC )
69
69
-> Result < ( winapi:: HGLRC , winapi:: HDC ) , String > {
70
- let ctx = wgl:: CreateContext ( hdc as * const c_void ) ;
71
- if ctx. is_null ( ) {
70
+ let mut ctx = WGLScopedContext :: default ( ) ;
71
+ ctx. render_ctx = wgl:: CreateContext ( hdc as * const _ ) as winapi:: HGLRC ;
72
+ if ctx. render_ctx . is_null ( ) {
72
73
return Err ( format ! ( "wglCreateContext failed: {}" , io:: Error :: last_os_error( ) ) ) ;
73
74
}
74
75
75
76
if !share. is_null ( ) {
76
- if wgl:: ShareLists ( share as * const c_void , ctx) == 0 {
77
+ if wgl:: ShareLists ( share as * const _ , ctx. render_ctx as * const _ ) == 0 {
77
78
return Err ( format ! ( "wglShareLists failed: {}" , io:: Error :: last_os_error( ) ) ) ;
78
79
}
79
80
} ;
80
-
81
- Ok ( ( ctx as winapi :: HGLRC , hdc) )
81
+ ctx . dispose = false ;
82
+ Ok ( ( ctx. render_ctx , hdc) )
82
83
}
83
84
84
85
// creates a full context: attempts to use optional ext WGL functions
@@ -90,7 +91,13 @@ unsafe fn create_full_context(settings: &WGLAttributes,
90
91
-> Result < ( winapi:: HGLRC , winapi:: HDC ) , String > {
91
92
let mut extensions = extensions. split ( ' ' ) ;
92
93
if extensions. find ( |& i| i == "WGL_ARB_create_context" ) . is_none ( ) {
93
- return create_basic_context ( hdc, share) ;
94
+ let ctx = create_basic_context ( hdc, share) ;
95
+ if let Ok ( ctx) = ctx {
96
+ if wgl:: MakeCurrent ( ctx. 1 as * const _ , ctx. 0 as * const _ ) == 0 {
97
+ return Err ( "wglMakeCurrent failed creating a basic context" . to_owned ( ) ) ;
98
+ }
99
+ }
100
+ return ctx;
94
101
}
95
102
96
103
let mut attributes = Vec :: new ( ) ;
@@ -119,26 +126,27 @@ unsafe fn create_full_context(settings: &WGLAttributes,
119
126
120
127
attributes. push ( 0 ) ;
121
128
122
- let ctx = extra. CreateContextAttribsARB ( hdc as * const c_void ,
123
- share as * const c_void ,
124
- attributes. as_ptr ( ) ) ;
129
+ let mut ctx = WGLScopedContext :: default ( ) ;
130
+ ctx. render_ctx = extra. CreateContextAttribsARB ( hdc as * const _ ,
131
+ share as * const _ ,
132
+ attributes. as_ptr ( ) ) as winapi:: HGLRC ;
125
133
126
- if ctx. is_null ( ) {
134
+ if ctx. render_ctx . is_null ( ) {
127
135
return Err ( format ! ( "wglCreateContextAttribsARB failed: {}" ,
128
136
io:: Error :: last_os_error( ) ) ) ;
129
137
}
130
138
131
- if wgl:: MakeCurrent ( hdc as * const _ , ctx as * const _ ) == 0 {
132
- return Err ( "wglMakeCurrent failed" . to_owned ( ) ) ;
139
+ if wgl:: MakeCurrent ( hdc as * const _ , ctx. render_ctx as * const _ ) == 0 {
140
+ return Err ( "wglMakeCurrent failed creating full context " . to_owned ( ) ) ;
133
141
}
134
142
// Disable or enable vsync
135
143
if extensions. find ( |& i| i == "WGL_EXT_swap_control" ) . is_some ( ) {
136
144
if extra. SwapIntervalEXT ( if settings. vsync { 1 } else { 0 } ) == 0 {
137
145
return Err ( "wglSwapIntervalEXT failed" . to_owned ( ) ) ;
138
146
}
139
147
}
140
-
141
- Ok ( ( ctx as winapi:: HGLRC , hdc) )
148
+ ctx . dispose = false ;
149
+ Ok ( ( ctx. render_ctx as winapi:: HGLRC , hdc) )
142
150
}
143
151
144
152
unsafe fn create_hidden_window ( ) -> Result < winapi:: HWND , & ' static str > {
@@ -177,6 +185,55 @@ unsafe fn create_hidden_window() -> Result<winapi::HWND, &'static str> {
177
185
Ok ( win)
178
186
}
179
187
188
+ // Helper struct used to dispose resources in error paths
189
+ struct WGLScopedContext {
190
+ pub window : winapi:: HWND ,
191
+ pub device_ctx : winapi:: HDC ,
192
+ pub render_ctx : winapi:: HGLRC ,
193
+ pub dispose : bool
194
+ }
195
+
196
+ impl Drop for WGLScopedContext {
197
+ fn drop ( & mut self ) {
198
+ unsafe {
199
+ if self . dispose {
200
+ if self . render_ctx . is_null ( ) {
201
+ wgl:: DeleteContext ( self . render_ctx as * const _ ) ;
202
+ }
203
+ if !self . device_ctx . is_null ( ) && !self . window . is_null ( ) {
204
+ user32:: ReleaseDC ( self . window , self . device_ctx ) ;
205
+ }
206
+ if !self . window . is_null ( ) {
207
+ user32:: DestroyWindow ( self . window ) ;
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ impl Default for WGLScopedContext {
215
+ #[ inline]
216
+ fn default ( ) -> WGLScopedContext {
217
+ WGLScopedContext {
218
+ window : ptr:: null_mut ( ) ,
219
+ device_ctx : ptr:: null_mut ( ) ,
220
+ render_ctx : ptr:: null_mut ( ) ,
221
+ dispose : true
222
+ }
223
+ }
224
+ }
225
+
226
+ impl WGLScopedContext {
227
+ fn new ( window : winapi:: HWND , device_ctx : winapi:: HDC , render_ctx : winapi:: HGLRC ) -> WGLScopedContext {
228
+ WGLScopedContext {
229
+ window : window,
230
+ device_ctx : device_ctx,
231
+ render_ctx : render_ctx,
232
+ dispose : true
233
+ }
234
+ }
235
+ }
236
+
180
237
// ***********
181
238
// Utilities to ease WGL context creation
182
239
// Slightly modified versions of util functions taken from Glutin
@@ -225,21 +282,6 @@ pub unsafe extern "system" fn proc_callback(window: winapi::HWND,
225
282
}
226
283
}
227
284
228
-
229
- // A simple wrapper that destroys the window when it is destroyed.
230
- struct WindowWrapper ( winapi:: HWND , winapi:: HDC ) ;
231
-
232
- impl Drop for WindowWrapper {
233
- #[ inline]
234
- fn drop ( & mut self ) {
235
- unsafe {
236
- user32:: DestroyWindow ( self . 0 ) ;
237
- }
238
- }
239
- }
240
-
241
-
242
-
243
285
#[ derive( Debug , Clone ) ]
244
286
pub struct PixelFormat {
245
287
pub hardware_accelerated : bool ,
@@ -398,21 +440,17 @@ unsafe fn choose_arb_pixel_format(extra: &wgl_ext::Wgl,
398
440
}
399
441
400
442
// Chooses a pixel formats without using WGL.
401
- //
402
443
// Gives less precise results than `enumerate_arb_pixel_formats`.
403
444
unsafe fn choose_native_pixel_format ( hdc : winapi:: HDC ,
404
445
reqs : & WGLPixelFormat )
405
446
-> Result < ( c_int , PixelFormat ) , ( ) > {
406
- // TODO: hardware acceleration is not handled
407
-
408
447
// handling non-supported stuff
409
448
if reqs. float_color_buffer {
410
449
return Err ( ( ) ) ;
411
450
}
412
451
413
452
match reqs. multisampling {
414
- Some ( 0 ) => ( ) ,
415
- None => ( ) ,
453
+ Some ( 0 ) | None => ( ) ,
416
454
Some ( _) => return Err ( ( ) ) ,
417
455
} ;
418
456
@@ -559,13 +597,13 @@ unsafe fn load_extra_functions(window: winapi::HWND) -> Result<wgl_ext::Wgl, Str
559
597
winapi:: WS_POPUP | winapi:: WS_CLIPSIBLINGS | winapi:: WS_CLIPCHILDREN ) ;
560
598
561
599
// creating a dummy invisible window
562
- let dummy_window = {
600
+ let mut dummy_window = {
563
601
// getting the rect of the real window
564
602
let rect = {
565
603
let mut placement: winapi:: WINDOWPLACEMENT = mem:: zeroed ( ) ;
566
604
placement. length = mem:: size_of :: < winapi:: WINDOWPLACEMENT > ( ) as winapi:: UINT ;
567
605
if user32:: GetWindowPlacement ( window, & mut placement) == 0 {
568
- panic ! ( ) ;
606
+ return Err ( "user32::GetWindowPlacement failed" . to_owned ( ) ) ;
569
607
}
570
608
placement. rcNormalPosition
571
609
} ;
@@ -596,35 +634,43 @@ unsafe fn load_extra_functions(window: winapi::HWND) -> Result<wgl_ext::Wgl, Str
596
634
ptr:: null_mut ( ) ) ;
597
635
598
636
if win. is_null ( ) {
599
- return Err ( format ! ( "CreateWindowEx function failed: {}" ,
600
- io:: Error :: last_os_error( ) ) ) ;
637
+ return Err ( format ! ( "CreateWindowEx function failed: {}" , io:: Error :: last_os_error( ) ) ) ;
601
638
}
602
639
603
640
let hdc = user32:: GetDC ( win) ;
641
+ let ctx = WGLScopedContext :: new ( win, hdc, ptr:: null_mut ( ) ) ;
642
+
604
643
if hdc. is_null ( ) {
605
- let err = Err ( format ! ( "GetDC function failed: {}" , io:: Error :: last_os_error( ) ) ) ;
606
- return err;
644
+ return Err ( format ! ( "GetDC function failed: {}" , io:: Error :: last_os_error( ) ) ) ;
607
645
}
608
646
609
- WindowWrapper ( win , hdc )
647
+ ctx
610
648
} ;
611
649
612
650
// getting the pixel format that we will use and setting it
613
651
{
614
- let id = try!( choose_dummy_pixel_format ( dummy_window. 1 ) ) ;
615
- try!( set_pixel_format ( dummy_window. 1 , id) ) ;
652
+ let id = try!( choose_dummy_pixel_format ( dummy_window. device_ctx ) ) ;
653
+ try!( set_pixel_format ( dummy_window. device_ctx , id) ) ;
616
654
}
617
655
618
656
// creating the dummy OpenGL context and making it current
619
- let dummy_context = try!( create_basic_context ( dummy_window. 1 , ptr:: null_mut ( ) ) ) ;
620
- let _current_context = try!( CurrentContextGuard :: make_current ( dummy_window. 1 , dummy_context. 0 ) ) ;
657
+ dummy_window. render_ctx = try!( create_basic_context ( dummy_window. device_ctx , ptr:: null_mut ( ) ) ) . 0 ;
658
+ if wgl:: MakeCurrent ( dummy_window. device_ctx as * const _ , dummy_window. render_ctx as * const _ ) == 0 {
659
+ return Err ( "WGL::MakeCurrent failed before loading extra WGL functions" . to_owned ( ) ) ;
660
+ }
621
661
622
662
// loading the extra WGL functions
623
- Ok ( wgl_ext:: Wgl :: load_with ( |addr| {
663
+ let result = wgl_ext:: Wgl :: load_with ( |addr| {
624
664
let addr = CString :: new ( addr. as_bytes ( ) ) . unwrap ( ) ;
625
665
let addr = addr. as_ptr ( ) ;
626
666
wgl:: GetProcAddress ( addr) as * const c_void
627
- } ) )
667
+ } ) ;
668
+
669
+ // Unbind the current context so WGLScopedContext can release resources properly
670
+ // wgl::DeleteContex must be called with unbound contexts
671
+ wgl:: MakeCurrent ( ptr:: null_mut ( ) , ptr:: null_mut ( ) ) ;
672
+
673
+ Ok ( result)
628
674
}
629
675
630
676
// This function chooses a pixel format that is likely to be provided by
@@ -667,45 +713,4 @@ fn choose_dummy_pixel_format(hdc: winapi::HDC) -> Result<c_int, &'static str> {
667
713
}
668
714
669
715
Ok ( pf_id)
670
- }
671
-
672
- // A guard for when you want to make the context current. Destroying the guard restores the
673
- // previously-current context.
674
- use std:: marker:: PhantomData ;
675
- pub struct CurrentContextGuard < ' a , ' b > {
676
- previous_hdc : winapi:: HDC ,
677
- previous_hglrc : winapi:: HGLRC ,
678
- marker1 : PhantomData < & ' a ( ) > ,
679
- marker2 : PhantomData < & ' b ( ) > ,
680
- }
681
-
682
- impl < ' a , ' b > CurrentContextGuard < ' a , ' b > {
683
- pub unsafe fn make_current ( hdc : winapi:: HDC ,
684
- context : winapi:: HGLRC )
685
- -> Result < CurrentContextGuard < ' a , ' b > , String > {
686
- let previous_hdc = wgl:: GetCurrentDC ( ) as winapi:: HDC ;
687
- let previous_hglrc = wgl:: GetCurrentContext ( ) as winapi:: HGLRC ;
688
-
689
- let result = wgl:: MakeCurrent ( hdc as * const _ , context as * const _ ) ;
690
- if result == 0 {
691
- return Err ( format ! ( "wglMakeCurrent function failed: {}" ,
692
- io:: Error :: last_os_error( ) ) ) ;
693
- }
694
-
695
- Ok ( CurrentContextGuard {
696
- previous_hdc : previous_hdc,
697
- previous_hglrc : previous_hglrc,
698
- marker1 : PhantomData ,
699
- marker2 : PhantomData ,
700
- } )
701
- }
702
- }
703
-
704
- impl < ' a , ' b > Drop for CurrentContextGuard < ' a , ' b > {
705
- fn drop ( & mut self ) {
706
- unsafe {
707
- wgl:: MakeCurrent ( self . previous_hdc as * const c_void ,
708
- self . previous_hglrc as * const c_void ) ;
709
- }
710
- }
711
- }
716
+ }
0 commit comments