diff options
author | HampusM <hampus@hampusmat.com> | 2023-10-15 00:06:07 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2023-10-15 00:06:07 +0200 |
commit | da329909f93597970afd169cee28ece3bee7127b (patch) | |
tree | b8ce428d458ab5e3e699334877253b10a62c8fe2 /engine/src/opengl/debug.rs | |
parent | 46f27f31e425f5eba494f499bd7a6ac8f8713c2a (diff) |
feat(engine): add logging OpenGL debug messages
Diffstat (limited to 'engine/src/opengl/debug.rs')
-rw-r--r-- | engine/src/opengl/debug.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/engine/src/opengl/debug.rs b/engine/src/opengl/debug.rs new file mode 100644 index 0000000..203590a --- /dev/null +++ b/engine/src/opengl/debug.rs @@ -0,0 +1,145 @@ +use std::ffi::c_void; +use std::io::{stderr, Write}; +use std::panic::catch_unwind; +use std::ptr::null_mut; +use std::sync::Mutex; + +use crate::opengl::util::gl_enum; + +pub type MessageCallback = fn( + source: MessageSource, + ty: MessageType, + id: u32, + severity: MessageSeverity, + message: &str, +); + +pub fn enable_debug_output() +{ + unsafe { + gl::Enable(gl::DEBUG_OUTPUT); + gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); + } +} + +pub fn set_debug_message_callback(cb: MessageCallback) +{ + *DEBUG_MESSAGE_CB.lock().unwrap() = Some(cb); + + unsafe { + gl::DebugMessageCallback(Some(debug_message_cb), null_mut()); + } +} + +pub fn set_debug_message_control( + source: Option<MessageSource>, + ty: Option<MessageType>, + severity: Option<MessageSeverity>, + ids: &[u32], + ids_action: MessageIdsAction, +) +{ + // Ids shouldn't realistically be large enough to cause a panic here + let ids_len: i32 = ids.len().try_into().unwrap(); + + unsafe { + gl::DebugMessageControl( + source.map_or(gl::DONT_CARE, |source| source as u32), + ty.map_or(gl::DONT_CARE, |ty| ty as u32), + severity.map_or(gl::DONT_CARE, |severity| severity as u32), + ids_len, + ids.as_ptr(), + ids_action as u8, + ); + } +} + +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +pub enum MessageIdsAction +{ + Enable = 1, + Disable = 0, +} + +gl_enum! { +pub enum MessageSource +{ + Api = gl::DEBUG_SOURCE_API, + WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM, + ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER, + ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY, + Application = gl::DEBUG_SOURCE_APPLICATION, + Other = gl::DEBUG_SOURCE_OTHER, +} +} + +gl_enum! { +pub enum MessageType +{ + DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR, + Error = gl::DEBUG_TYPE_ERROR, + Marker = gl::DEBUG_TYPE_MARKER, + Other = gl::DEBUG_TYPE_OTHER, + Performance = gl::DEBUG_TYPE_PERFORMANCE, + PopGroup = gl::DEBUG_TYPE_POP_GROUP, + PushGroup = gl::DEBUG_TYPE_PUSH_GROUP, + Portability = gl::DEBUG_TYPE_PORTABILITY, + UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR, +} +} + +gl_enum! { +pub enum MessageSeverity +{ + High = gl::DEBUG_SEVERITY_HIGH, + Medium = gl::DEBUG_SEVERITY_MEDIUM, + Low = gl::DEBUG_SEVERITY_LOW, + Notification = gl::DEBUG_SEVERITY_NOTIFICATION, +} +} + +static DEBUG_MESSAGE_CB: Mutex<Option<MessageCallback>> = Mutex::new(None); + +extern "system" fn debug_message_cb( + source: gl::types::GLenum, + ty: gl::types::GLenum, + id: gl::types::GLuint, + severity: gl::types::GLenum, + message_length: gl::types::GLsizei, + message: *const gl::types::GLchar, + _user_param: *mut c_void, +) +{ + // Unwinds are catched because unwinding from Rust code into foreign code is UB. + let res = catch_unwind(|| { + let cb_lock = DEBUG_MESSAGE_CB.lock().unwrap(); + + if let Some(cb) = *cb_lock { + let msg_source = MessageSource::from_gl(source).unwrap(); + let msg_type = MessageType::from_gl(ty).unwrap(); + let msg_severity = MessageSeverity::from_gl(severity).unwrap(); + + let msg_length = usize::try_from(message_length).unwrap(); + + // SAFETY: The received message should be a valid ASCII string + let message = unsafe { + std::str::from_utf8_unchecked(std::slice::from_raw_parts( + message.cast(), + msg_length, + )) + }; + + cb(msg_source, msg_type, id, msg_severity, message); + } + }); + + if res.is_err() { + // eprintln is not used since it can panic and unwinds are unwanted because + // unwinding from Rust code into foreign code is UB. + stderr() + .write_all(b"ERROR: Panic in debug message callback") + .ok(); + println!(); + } +} |