1use crate::gl;
4
5use std::collections::HashMap;
6use std::mem;
7use std::ptr;
8use std::str;
9use std::borrow::Cow;
10use std::cell::{Cell, RefCell, RefMut};
11use std::marker::PhantomData;
12use std::ffi::CStr;
13use std::rc::Rc;
14use std::os::raw;
15use std::hash::BuildHasherDefault;
16
17use fnv::FnvHasher;
18
19use crate::IncompatibleOpenGl;
20use crate::SwapBuffersError;
21use crate::CapabilitiesSource;
22use crate::ContextExt;
23use crate::backend::Backend;
24use crate::version;
25use crate::version::Api;
26use crate::version::Version;
27
28use crate::debug;
29use crate::fbo;
30use crate::ops;
31use crate::sampler_object;
32use crate::texture;
33use crate::uniforms;
34use crate::vertex_array_object;
35
36pub use self::capabilities::{ReleaseBehavior, Capabilities, Profile};
37pub use self::extensions::ExtensionsList;
38pub use self::state::GlState;
39pub use self::uuid::UuidError;
40
41mod capabilities;
42mod extensions;
43mod state;
44mod uuid;
45
46pub struct Context {
49 gl: gl::Gl,
51
52 state: RefCell<GlState>,
55
56 version: Version,
58
59 extensions: ExtensionsList,
61
62 capabilities: Capabilities,
65
66 backend: RefCell<Box<dyn Backend>>,
69
70 check_current_context: bool,
73
74 debug_callback: Option<debug::DebugCallback>,
76
77 report_debug_output_errors: Cell<bool>,
81
82 framebuffer_objects: Option<fbo::FramebuffersContainer>,
86
87 vertex_array_objects: vertex_array_object::VertexAttributesSystem,
89
90 samplers: RefCell<HashMap<uniforms::SamplerBehavior, sampler_object::SamplerObject, BuildHasherDefault<FnvHasher>>>,
92
93 resident_texture_handles: RefCell<Vec<gl::types::GLuint64>>,
96
97 resident_image_handles: RefCell<Vec<(gl::types::GLuint64, gl::types::GLenum)>>,
100}
101
102pub struct CommandContext<'a> {
104 pub gl: &'a gl::Gl,
106
107 pub state: RefMut<'a, GlState>,
110
111 pub version: &'a Version,
113
114 pub extensions: &'a ExtensionsList,
116
117 pub capabilities: &'a Capabilities,
119
120 pub report_debug_output_errors: &'a Cell<bool>,
123
124 pub vertex_array_objects: &'a vertex_array_object::VertexAttributesSystem,
126
127 pub framebuffer_objects: &'a fbo::FramebuffersContainer,
129
130 pub samplers: RefMut<'a, HashMap<uniforms::SamplerBehavior, sampler_object::SamplerObject, BuildHasherDefault<FnvHasher>>>,
132
133 pub resident_texture_handles: RefMut<'a, Vec<gl::types::GLuint64>>,
135
136 pub resident_image_handles: RefMut<'a, Vec<(gl::types::GLuint64, gl::types::GLenum)>>,
138
139 marker: PhantomData<*mut u8>,
143}
144
145impl Context {
146 pub unsafe fn new<B>(
159 backend: B,
160 check_current_context: bool,
161 callback_behavior: DebugCallbackBehavior,
162 ) -> Result<Rc<Context>, IncompatibleOpenGl>
163 where B: Backend + 'static
164 {
165 backend.make_current();
166
167 let gl = gl::Gl::load_with(|symbol| backend.get_proc_address(symbol) as *const _);
168 let gl_state: RefCell<GlState> = RefCell::new(Default::default());
169
170 let version = version::get_gl_version(&gl);
171 let extensions = extensions::get_extensions(&gl, &version);
172 check_gl_compatibility(&version, &extensions)?;
173
174 let capabilities = capabilities::get_capabilities(&gl, &version, &extensions);
175 let report_debug_output_errors = Cell::new(true);
176
177 let vertex_array_objects = vertex_array_object::VertexAttributesSystem::new();
178 let framebuffer_objects = fbo::FramebuffersContainer::new();
179 let samplers = RefCell::new({
180 let mut map = HashMap::with_hasher(Default::default());
181 map.reserve(16);
182 map
183 });
184 let resident_texture_handles = RefCell::new(Vec::new());
185 let resident_image_handles = RefCell::new(Vec::new());
186
187 let (debug_callback, synchronous) = match callback_behavior {
188 DebugCallbackBehavior::Ignore => (None, false),
189 DebugCallbackBehavior::DebugMessageOnError => {
190 (Some(Box::new(default_debug_callback) as debug::DebugCallback), true)
191 },
192 DebugCallbackBehavior::PrintAll => {
193 (Some(Box::new(printall_debug_callback) as debug::DebugCallback), false)
194 },
195 DebugCallbackBehavior::Custom { callback, synchronous } => {
196 (Some(callback), synchronous)
197 },
198 };
199
200 let context = Rc::new(Context {
201 gl,
202 state: gl_state,
203 version,
204 extensions,
205 capabilities,
206 debug_callback,
207 report_debug_output_errors,
208 backend: RefCell::new(Box::new(backend)),
209 check_current_context,
210 framebuffer_objects: Some(framebuffer_objects),
211 vertex_array_objects,
212 samplers,
213 resident_texture_handles,
214 resident_image_handles,
215 });
216
217 if context.debug_callback.is_some() {
218 init_debug_callback(&context, synchronous);
219 }
220
221 {
223 let mut ctxt = context.make_current();
224 if crate::get_gl_error(&mut ctxt).is_some() {
225 eprintln!("glium has triggered an OpenGL error during initialization. Please report \
226 this error: https://github.com/glium/glium/issues");
227 }
228 if ctxt.version >= &Version(Api::Gl, 3, 2) && ctxt.extensions.gl_arb_seamless_cube_map {
232 ctxt.gl.Enable(gl::TEXTURE_CUBE_MAP_SEAMLESS);
233 }
234 }
235
236 Ok(context)
237 }
238
239 #[inline]
241 pub fn get_framebuffer_dimensions(&self) -> (u32, u32) {
242 self.backend.borrow().get_framebuffer_dimensions()
243 }
244
245 pub unsafe fn rebuild<B>(&self, new_backend: B) -> Result<(), IncompatibleOpenGl>
249 where B: Backend + 'static
250 {
251 {
254 let mut ctxt = self.make_current();
255 fbo::FramebuffersContainer::purge_all(&mut ctxt);
256 vertex_array_object::VertexAttributesSystem::purge_all(&mut ctxt);
257 }
258
259 new_backend.make_current();
260
261 *self.state.borrow_mut() = Default::default();
262 *self.backend.borrow_mut() = Box::new(new_backend);
264
265 let textures = self.resident_texture_handles.borrow();
267 for &texture in textures.iter() {
268 self.gl.MakeTextureHandleResidentARB(texture);
269 }
270
271 let images = self.resident_image_handles.borrow();
273 for &(image, access) in images.iter() {
274 self.gl.MakeImageHandleResidentARB(image, access);
275 }
276
277 Ok(())
278 }
279
280 pub fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
282 if self.state.borrow().lost_context {
283 return Err(SwapBuffersError::ContextLost);
284 }
285
286 if self.state.borrow().draw_framebuffer != 0 || self.state.borrow().read_framebuffer != 0 {
291 let mut ctxt = self.make_current();
292
293 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
294 ctxt.extensions.gl_arb_framebuffer_object
295 {
296 unsafe { ctxt.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); }
297 ctxt.state.draw_framebuffer = 0;
298 ctxt.state.read_framebuffer = 0;
299 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
300 unsafe { ctxt.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); }
301 ctxt.state.draw_framebuffer = 0;
302 ctxt.state.read_framebuffer = 0;
303 } else if ctxt.extensions.gl_ext_framebuffer_object {
304 unsafe { ctxt.gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, 0); }
305 ctxt.state.draw_framebuffer = 0;
306 ctxt.state.read_framebuffer = 0;
307 } else {
308 unreachable!();
309 }
310 }
311
312 let backend = self.backend.borrow();
313 if self.check_current_context && !backend.is_current() {
314 unsafe { backend.make_current() };
315 }
316
317 let err = backend.swap_buffers();
319 if let Err(SwapBuffersError::ContextLost) = err {
320 self.state.borrow_mut().lost_context = true;
321 }
322 err
323 }
324
325 #[inline]
327 #[deprecated(note = "use `get_opengl_version` instead.")]
328 pub fn get_version(&self) -> &Version {
329 &self.version
330 }
331
332 #[inline]
334 pub fn get_opengl_version(&self) -> &Version {
335 &self.version
336 }
337
338 #[inline]
340 pub fn get_supported_glsl_version(&self) -> Version {
341 version::get_supported_glsl_version(self.get_opengl_version())
342 }
343
344 #[inline]
346 pub fn is_glsl_version_supported(&self, version: &Version) -> bool {
347 self.capabilities().supported_glsl_versions.iter().any(|v| v == version)
348 }
349
350 #[inline]
354 pub fn get_opengl_version_string(&self) -> &str {
355 &self.capabilities().version
356 }
357
358 #[inline]
360 pub fn get_opengl_vendor_string(&self) -> &str {
361 &self.capabilities().vendor
362 }
363
364 #[inline]
368 pub fn get_opengl_renderer_string(&self) -> &str {
369 &self.capabilities().renderer
370 }
371
372 #[inline]
376 pub fn is_debug(&self) -> bool {
377 self.capabilities().debug
378 }
379
380 #[inline]
384 pub fn is_forward_compatible(&self) -> bool {
385 self.capabilities().forward_compatible
386 }
387
388 pub fn get_opengl_profile(&self) -> Option<Profile> {
392 self.capabilities().profile
393 }
394
395 #[inline]
400 pub fn is_robust(&self) -> bool {
401 self.capabilities().robustness
402 }
403
404 #[inline]
406 pub fn is_context_loss_possible(&self) -> bool {
407 self.capabilities().can_lose_context
408 }
409
410 pub fn is_context_lost(&self) -> bool {
418 if self.state.borrow().lost_context {
419 return true;
420 }
421
422 let mut ctxt = self.make_current();
423
424 let lost = if ctxt.version >= &Version(Api::Gl, 4, 5) ||
425 ctxt.version >= &Version(Api::GlEs, 3, 2) ||
426 ctxt.extensions.gl_khr_robustness
427 {
428 unsafe { ctxt.gl.GetGraphicsResetStatus() != gl::NO_ERROR }
429 } else if ctxt.extensions.gl_ext_robustness {
430 unsafe { ctxt.gl.GetGraphicsResetStatusEXT() != gl::NO_ERROR }
431 } else if ctxt.extensions.gl_arb_robustness {
432 unsafe { ctxt.gl.GetGraphicsResetStatusARB() != gl::NO_ERROR }
433 } else {
434 false
435 };
436
437 if lost { ctxt.state.lost_context = true; }
438 lost
439 }
440
441 #[inline]
446 pub fn get_release_behavior(&self) -> ReleaseBehavior {
447 self.capabilities().release_behavior
448 }
449
450 #[inline]
453 pub fn get_max_anisotropy_support(&self) -> Option<u16> {
454 self.capabilities().max_texture_max_anisotropy.map(|v| v as u16)
455 }
456
457 #[inline]
461 pub fn get_max_viewport_dimensions(&self) -> (u32, u32) {
462 let d = self.capabilities().max_viewport_dims;
463 (d.0 as u32, d.1 as u32)
464 }
465
466 pub fn release_shader_compiler(&self) {
470 unsafe {
471 let ctxt = self.make_current();
472
473 if (ctxt.version >= &Version(Api::GlEs, 2, 0) ||
474 ctxt.version >= &Version(Api::Gl, 4, 1)) && !ctxt.capabilities.supported_glsl_versions.is_empty() {
475 ctxt.gl.ReleaseShaderCompiler();
476 }
477 }
478 }
479
480 pub fn get_free_video_memory(&self) -> Option<usize> {
484 unsafe {
485 let ctxt = self.make_current();
486
487 let mut value: [gl::types::GLint; 4] = [0; 4];
488
489 if ctxt.extensions.gl_nvx_gpu_memory_info {
490 ctxt.gl.GetIntegerv(gl::GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX,
491 &mut value[0]);
492 Some(value[0] as usize * 1024)
493
494 } else if ctxt.extensions.gl_ati_meminfo {
495 ctxt.gl.GetIntegerv(gl::TEXTURE_FREE_MEMORY_ATI, &mut value[0]);
496 Some(value[0] as usize * 1024)
497
498 } else {
499 None
500 }
501 }
502 }
503
504 pub fn read_front_buffer<T>(&self) -> Result<T, ops::ReadError>
519 where T: texture::Texture2dDataSink<(u8, u8, u8, u8)>
520 {
521 let mut ctxt = self.make_current();
522 let dimensions = self.get_framebuffer_dimensions();
523 let rect = crate::Rect { left: 0, bottom: 0, width: dimensions.0, height: dimensions.1 };
524
525 let mut data = Vec::with_capacity(0);
526 ops::read(&mut ctxt, ops::Source::DefaultFramebuffer(gl::FRONT_LEFT), &rect,
527 &mut data, false)?;
528 Ok(T::from_raw(Cow::Owned(data), dimensions.0, dimensions.1))
529 }
530
531 #[inline]
537 pub unsafe fn exec_in_context<'a, T, F>(&self, action: F) -> T
538 where T: Send + 'static,
539 F: FnOnce() -> T + 'a
540 {
541 let _ctxt = self.make_current();
542 action()
543 }
544
545 pub fn assert_no_error(&self, user_msg: Option<&str>) {
549 let mut ctxt = self.make_current();
550
551 match (crate::get_gl_error(&mut ctxt), user_msg) {
552 (Some(msg), None) => panic!("{}", msg),
553 (Some(msg), Some(user_msg)) => panic!("{} : {}", user_msg, msg),
554 (None, _) => ()
555 };
556 }
557
558 #[inline]
560 pub fn synchronize(&self) {
561 self.finish();
562 }
563
564 #[inline]
573 pub fn finish(&self) {
574 let ctxt = self.make_current();
575 unsafe { ctxt.gl.Finish(); }
576 }
577
578 #[inline]
588 pub fn flush(&self) {
589 let ctxt = self.make_current();
590 unsafe { ctxt.gl.Flush(); }
591 }
592
593 pub fn insert_debug_marker(&self, marker: &str) -> Result<(), ()> {
601 let ctxt = self.make_current();
602
603 if ctxt.extensions.gl_gremedy_string_marker {
604 let marker = marker.as_bytes();
605 unsafe { ctxt.gl.StringMarkerGREMEDY(marker.len() as gl::types::GLsizei,
606 marker.as_ptr() as *const _) };
607 Ok(())
608
609 } else if ctxt.extensions.gl_ext_debug_marker {
610 let marker = marker.as_bytes();
611 unsafe { ctxt.gl.InsertEventMarkerEXT(marker.len() as gl::types::GLsizei,
612 marker.as_ptr() as *const _) };
613 Ok(())
614
615 } else {
616 Err(())
617 }
618 }
619
620 #[inline]
623 pub fn debug_insert_debug_marker(&self, marker: &str) -> Result<(), ()> {
624 if cfg!(debug_assertions) {
625 self.insert_debug_marker(marker)
626 } else {
627 Ok(())
628 }
629 }
630}
631
632impl ContextExt for Context {
633 #[inline]
634 fn set_report_debug_output_errors(&self, value: bool) {
635 self.report_debug_output_errors.set(value);
636 }
637
638 fn make_current(&self) -> CommandContext<'_> {
639 if self.check_current_context {
640 let backend = self.backend.borrow();
641 if !backend.is_current() {
642 unsafe { backend.make_current() };
643 debug_assert!(backend.is_current());
644 }
645 }
646
647 CommandContext {
648 gl: &self.gl,
649 state: self.state.borrow_mut(),
650 version: &self.version,
651 extensions: &self.extensions,
652 capabilities: &self.capabilities,
653 report_debug_output_errors: &self.report_debug_output_errors,
654 vertex_array_objects: &self.vertex_array_objects,
655 framebuffer_objects: self.framebuffer_objects.as_ref().unwrap(),
656 samplers: self.samplers.borrow_mut(),
657 resident_texture_handles: self.resident_texture_handles.borrow_mut(),
658 resident_image_handles: self.resident_image_handles.borrow_mut(),
659 marker: PhantomData,
660 }
661 }
662
663 #[inline]
664 fn capabilities(&self) -> &Capabilities {
665 &self.capabilities
666 }
667}
668
669impl CapabilitiesSource for Context {
670 #[inline]
671 fn get_version(&self) -> &Version {
672 &self.version
673 }
674
675 #[inline]
676 fn get_extensions(&self) -> &ExtensionsList {
677 &self.extensions
678 }
679
680 #[inline]
681 fn get_capabilities(&self) -> &Capabilities {
682 &self.capabilities
683 }
684}
685
686impl Drop for Context {
687 fn drop(&mut self) {
688 unsafe {
689 if self.check_current_context {
692 let backend = self.backend.borrow();
693 if !backend.is_current() {
694 backend.make_current();
695 }
696 }
697
698 let mut ctxt = CommandContext {
699 gl: &self.gl,
700 state: self.state.borrow_mut(),
701 version: &self.version,
702 extensions: &self.extensions,
703 capabilities: &self.capabilities,
704 report_debug_output_errors: &self.report_debug_output_errors,
705 vertex_array_objects: &self.vertex_array_objects,
706 framebuffer_objects: self.framebuffer_objects.as_ref().unwrap(),
707 samplers: self.samplers.borrow_mut(),
708 resident_texture_handles: self.resident_texture_handles.borrow_mut(),
709 resident_image_handles: self.resident_image_handles.borrow_mut(),
710 marker: PhantomData,
711 };
712
713 fbo::FramebuffersContainer::cleanup(&mut ctxt);
714 vertex_array_object::VertexAttributesSystem::cleanup(&mut ctxt);
715
716 for (_, s) in mem::replace(&mut *ctxt.samplers, HashMap::with_hasher(Default::default())) {
717 s.destroy(&mut ctxt);
718 }
719
720 if ctxt.state.enabled_debug_output != Some(false) {
722 if ctxt.version >= &Version(Api::Gl, 4,5) || ctxt.extensions.gl_khr_debug {
723 ctxt.gl.Disable(gl::DEBUG_OUTPUT);
724 } else if ctxt.extensions.gl_arb_debug_output {
725 ctxt.gl.DebugMessageCallbackARB(None,
726 ptr::null());
727 }
728
729 ctxt.state.enabled_debug_output = Some(false);
730 ctxt.gl.Finish();
731 }
732 }
733 }
734}
735
736impl<'a> CapabilitiesSource for CommandContext<'a> {
737 #[inline]
738 fn get_version(&self) -> &Version {
739 self.version
740 }
741
742 #[inline]
743 fn get_extensions(&self) -> &ExtensionsList {
744 self.extensions
745 }
746
747 #[inline]
748 fn get_capabilities(&self) -> &Capabilities {
749 self.capabilities
750 }
751}
752
753fn check_gl_compatibility(version: &Version, extensions: &ExtensionsList)
755 -> Result<(), IncompatibleOpenGl>
756{
757 let mut result = Vec::with_capacity(0);
758
759 if !(version >= &Version(Api::Gl, 1, 5)) &&
760 !(version >= &Version(Api::GlEs, 2, 0)) &&
761 (!extensions.gl_arb_vertex_buffer_object || !extensions.gl_arb_map_buffer_range)
762 {
763 result.push("OpenGL implementation doesn't support buffer objects");
764 }
765
766 if !(version >= &Version(Api::Gl, 2, 0)) &&
767 !(version >= &Version(Api::GlEs, 2, 0)) &&
768 (!extensions.gl_arb_shader_objects ||
769 !extensions.gl_arb_vertex_shader || !extensions.gl_arb_fragment_shader)
770 {
771 result.push("OpenGL implementation doesn't support vertex/fragment shaders");
772 }
773
774 if !extensions.gl_ext_framebuffer_object && !(version >= &Version(Api::Gl, 3, 0)) &&
775 !(version >= &Version(Api::GlEs, 2, 0)) && !extensions.gl_arb_framebuffer_object
776 {
777 result.push("OpenGL implementation doesn't support framebuffers");
778 }
779
780 if !extensions.gl_ext_framebuffer_blit && !(version >= &Version(Api::Gl, 3, 0)) &&
781 !(version >= &Version(Api::GlEs, 2, 0))
782 {
783 result.push("OpenGL implementation doesn't support blitting framebuffers");
784 }
785
786 if result.len() == 0 {
787 Ok(())
788 } else {
789 Err(IncompatibleOpenGl(result.join("\n")))
790 }
791}
792
793pub enum DebugCallbackBehavior {
795 Ignore,
797
798 DebugMessageOnError,
801
802 PrintAll,
804
805 Custom {
807 callback: debug::DebugCallback,
809 synchronous: bool,
811 },
812}
813
814impl Default for DebugCallbackBehavior {
815 #[inline]
816 fn default() -> DebugCallbackBehavior {
817 if cfg!(debug_assertions) {
818 DebugCallbackBehavior::DebugMessageOnError
819 } else {
820 DebugCallbackBehavior::Ignore
821 }
822 }
823}
824
825fn default_debug_callback(_: debug::Source, ty: debug::MessageType, severity: debug::Severity,
827 _: u32, report_debug_output_errors: bool, message: &str)
828{
829 match severity {
830 debug::Severity::Medium => (),
831 debug::Severity::High => (),
832 _ => return
833 };
834
835 match ty {
836 debug::MessageType::Error => (),
837 debug::MessageType::DeprecatedBehavior => (),
838 debug::MessageType::UndefinedBehavior => (),
839 debug::MessageType::Portability => (),
840 _ => return,
841 };
842
843 if report_debug_output_errors {
844 eprint!("Debug message with high or medium severity: `{}`.\n\
845 Please report this error: https://github.com/glium/glium/issues\n\
846 Backtrace:",
847 message);
848
849 let mut frame_id = 1;
850 backtrace::trace(|frame| {
851 let ip = frame.ip();
852 print!("\n{:>#4} - {:p}", frame_id, ip);
853
854 backtrace::resolve(ip, |symbol| {
855 let name = symbol.name()
856 .map(|n| n.as_str().unwrap_or("<not-utf8>"))
857 .unwrap_or("<unknown>");
858 let filename = symbol.filename()
859 .map(|p| p.to_str().unwrap_or("<not-utf8>"))
860 .unwrap_or("<unknown>");
861 let line = symbol.lineno().map(|l| l.to_string())
862 .unwrap_or_else(|| "??".to_owned());
863
864 print!("\n {} at {}:{}", name, filename, line);
865 });
866
867 frame_id += 1;
868 true
869 });
870
871 eprintln!("\n");
872 }
873}
874
875fn printall_debug_callback(source: debug::Source, ty: debug::MessageType, severity: debug::Severity,
877 id: u32, _: bool, message: &str)
878{
879 eprintln!("Source: {src:?}\t\tSeverity: {sev:?}\t\tType: {ty:?}\t\tId: {id}\n{msg}",
880 src = source, sev = severity, ty = ty, id = id, msg = message);
881}
882
883fn init_debug_callback(context: &Rc<Context>, synchronous: bool) {
886 extern "system" fn callback_wrapper(source: gl::types::GLenum, ty: gl::types::GLenum,
888 id: gl::types::GLuint, severity: gl::types::GLenum,
889 _length: gl::types::GLsizei,
890 message: *const gl::types::GLchar,
891 user_param: *mut raw::c_void)
892 {
893 let user_param = user_param as *const Context;
898 let user_param: &mut Context = unsafe { mem::transmute(user_param) };
899
900 let message = unsafe {
901 String::from_utf8(CStr::from_ptr(message).to_bytes().to_vec()).unwrap()
902 };
903
904 let severity = match severity {
905 gl::DEBUG_SEVERITY_NOTIFICATION => debug::Severity::Notification,
906 gl::DEBUG_SEVERITY_LOW => debug::Severity::Low,
907 gl::DEBUG_SEVERITY_MEDIUM => debug::Severity::Medium,
908 gl::DEBUG_SEVERITY_HIGH => debug::Severity::High,
909 _ => return, };
911
912 let source = match source {
913 gl::DEBUG_SOURCE_API => debug::Source::Api,
914 gl::DEBUG_SOURCE_WINDOW_SYSTEM => debug::Source::WindowSystem,
915 gl::DEBUG_SOURCE_SHADER_COMPILER => debug::Source::ShaderCompiler,
916 gl::DEBUG_SOURCE_THIRD_PARTY => debug::Source::ThirdParty,
917 gl::DEBUG_SOURCE_APPLICATION => debug::Source::Application,
918 gl::DEBUG_SOURCE_OTHER => debug::Source::OtherSource,
919 _ => return, };
921
922 let ty = match ty {
923 gl::DEBUG_TYPE_ERROR => debug::MessageType::Error,
924 gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => debug::MessageType::DeprecatedBehavior,
925 gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => debug::MessageType::UndefinedBehavior,
926 gl::DEBUG_TYPE_PORTABILITY => debug::MessageType::Portability,
927 gl::DEBUG_TYPE_PERFORMANCE => debug::MessageType::Performance,
928 gl::DEBUG_TYPE_MARKER => debug::MessageType::Marker,
929 gl::DEBUG_TYPE_PUSH_GROUP => debug::MessageType::PushGroup,
930 gl::DEBUG_TYPE_POP_GROUP => debug::MessageType::PopGroup,
931 gl::DEBUG_TYPE_OTHER => debug::MessageType::Other,
932 _ => return, };
934
935 if let Some(callback) = user_param.debug_callback.as_mut() {
936 callback(source, ty, severity, id, user_param.report_debug_output_errors.get(),
938 &message);
939 }
940 }
941
942 struct ContextRawPtr(*const Context);
943 unsafe impl Send for ContextRawPtr {}
944 let context_raw_ptr = ContextRawPtr(&**context);
945
946 unsafe {
947 let mut ctxt = context.make_current();
948
949 if ctxt.version >= &Version(Api::Gl, 4,5) || ctxt.version >= &Version(Api::GlEs, 3, 2) ||
950 ctxt.extensions.gl_khr_debug || ctxt.extensions.gl_arb_debug_output
951 {
952 if synchronous && !ctxt.state.enabled_debug_output_synchronous {
953 ctxt.gl.Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
954 ctxt.state.enabled_debug_output_synchronous = true;
955 }
956
957 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
958 ctxt.version >= &Version(Api::GlEs, 3, 2) ||
959 (ctxt.version >= &Version(Api::Gl, 1, 0) && ctxt.extensions.gl_khr_debug)
960 {
961 ctxt.gl.DebugMessageCallback(Some(callback_wrapper), context_raw_ptr.0
962 as *const _);
963 ctxt.gl.DebugMessageControl(gl::DONT_CARE, gl::DONT_CARE, gl::DONT_CARE, 0,
964 ptr::null(), gl::TRUE);
965
966 if ctxt.state.enabled_debug_output != Some(true) {
967 ctxt.gl.Enable(gl::DEBUG_OUTPUT);
968 ctxt.state.enabled_debug_output = Some(true);
969 }
970
971 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) &&
972 ctxt.extensions.gl_khr_debug
973 {
974 ctxt.gl.DebugMessageCallbackKHR(Some(callback_wrapper), context_raw_ptr.0
975 as *const _);
976 ctxt.gl.DebugMessageControlKHR(gl::DONT_CARE, gl::DONT_CARE, gl::DONT_CARE, 0,
977 ptr::null(), gl::TRUE);
978
979 if ctxt.state.enabled_debug_output != Some(true) {
980 ctxt.gl.Enable(gl::DEBUG_OUTPUT);
981 ctxt.state.enabled_debug_output = Some(true);
982 }
983
984 } else {
985 ctxt.gl.DebugMessageCallbackARB(Some(callback_wrapper), context_raw_ptr.0
986 as *const _);
987 ctxt.gl.DebugMessageControlARB(gl::DONT_CARE, gl::DONT_CARE, gl::DONT_CARE,
988 0, ptr::null(), gl::TRUE);
989
990 ctxt.state.enabled_debug_output = Some(true);
991 }
992 }
993 }
994}