diff options
author | HampusM <hampus@hampusmat.com> | 2025-09-19 16:36:57 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-10-02 16:55:33 +0200 |
commit | ea1d70c8c28e3b96da6264021fa1c62e28fcd8e4 (patch) | |
tree | 62ae9b75ee84602899b51483ed26fa664df36888 /opengl-bindings/src/debug.rs | |
parent | 0008b374c7f3a9ef6b30ea31a4a8c98bce64649f (diff) |
feat: add OpenGL bindings crate
Diffstat (limited to 'opengl-bindings/src/debug.rs')
-rw-r--r-- | opengl-bindings/src/debug.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/opengl-bindings/src/debug.rs b/opengl-bindings/src/debug.rs new file mode 100644 index 0000000..a9369a4 --- /dev/null +++ b/opengl-bindings/src/debug.rs @@ -0,0 +1,161 @@ +use std::ffi::c_void; +use std::io::{stderr, Write}; +use std::mem::transmute; +use std::panic::catch_unwind; + +use util_macros::FromRepr; + +use crate::CurrentContextWithFns; + +pub fn set_debug_message_callback( + current_context: &CurrentContextWithFns<'_>, + cb: MessageCallback, +) +{ + unsafe { + current_context + .fns() + .DebugMessageCallback(Some(debug_message_cb), cb as *mut c_void); + } +} + +/// Sets debug message parameters. +/// +/// # Errors +/// Returns `Err` if `ids` contains too many ids. +pub fn set_debug_message_control( + current_context: &CurrentContextWithFns<'_>, + source: Option<MessageSource>, + ty: Option<MessageType>, + severity: Option<MessageSeverity>, + ids: &[u32], + ids_action: MessageIdsAction, +) -> Result<(), SetDebugMessageControlError> +{ + let ids_len: crate::sys::types::GLsizei = + ids.len() + .try_into() + .map_err(|_| SetDebugMessageControlError::TooManyIds { + id_cnt: ids.len(), + max_id_cnt: crate::sys::types::GLsizei::MAX as usize, + })?; + + unsafe { + current_context.fns().DebugMessageControl( + source.map_or(crate::sys::DONT_CARE, |source| source as u32), + ty.map_or(crate::sys::DONT_CARE, |ty| ty as u32), + severity.map_or(crate::sys::DONT_CARE, |severity| severity as u32), + ids_len, + ids.as_ptr(), + ids_action as u8, + ); + } + + Ok(()) +} + +#[derive(Debug, thiserror::Error)] +pub enum SetDebugMessageControlError +{ + #[error("Too many ids provided ({id_cnt}). Must be < {max_id_cnt}")] + TooManyIds + { + id_cnt: usize, max_id_cnt: usize + }, +} + +pub type MessageCallback = fn( + source: MessageSource, + ty: MessageType, + id: u32, + severity: MessageSeverity, + message: &str, +); + +#[derive(Debug, Clone, Copy)] +#[repr(u8)] // GLboolean = u8 +pub enum MessageIdsAction +{ + Enable = crate::sys::TRUE, + Disable = crate::sys::FALSE, +} + +#[derive(Debug, Clone, Copy, FromRepr)] +#[repr(u32)] // GLenum = u32 +pub enum MessageSource +{ + Api = crate::sys::DEBUG_SOURCE_API, + WindowSystem = crate::sys::DEBUG_SOURCE_WINDOW_SYSTEM, + ShaderCompiler = crate::sys::DEBUG_SOURCE_SHADER_COMPILER, + ThirdParty = crate::sys::DEBUG_SOURCE_THIRD_PARTY, + Application = crate::sys::DEBUG_SOURCE_APPLICATION, + Other = crate::sys::DEBUG_SOURCE_OTHER, +} + +#[derive(Debug, Clone, Copy, FromRepr)] +#[repr(u32)] // GLenum = u32 +pub enum MessageType +{ + DeprecatedBehavior = crate::sys::DEBUG_TYPE_DEPRECATED_BEHAVIOR, + Error = crate::sys::DEBUG_TYPE_ERROR, + Marker = crate::sys::DEBUG_TYPE_MARKER, + Other = crate::sys::DEBUG_TYPE_OTHER, + Performance = crate::sys::DEBUG_TYPE_PERFORMANCE, + PopGroup = crate::sys::DEBUG_TYPE_POP_GROUP, + PushGroup = crate::sys::DEBUG_TYPE_PUSH_GROUP, + Portability = crate::sys::DEBUG_TYPE_PORTABILITY, + UndefinedBehavior = crate::sys::DEBUG_TYPE_UNDEFINED_BEHAVIOR, +} + +#[derive(Debug, Clone, Copy, FromRepr)] +#[repr(u32)] // GLenum = u32 +pub enum MessageSeverity +{ + High = crate::sys::DEBUG_SEVERITY_HIGH, + Medium = crate::sys::DEBUG_SEVERITY_MEDIUM, + Low = crate::sys::DEBUG_SEVERITY_LOW, + Notification = crate::sys::DEBUG_SEVERITY_NOTIFICATION, +} + +extern "system" fn debug_message_cb( + source: crate::sys::types::GLenum, + ty: crate::sys::types::GLenum, + id: crate::sys::types::GLuint, + severity: crate::sys::types::GLenum, + message_length: crate::sys::types::GLsizei, + message: *const crate::sys::types::GLchar, + user_cb: *mut c_void, +) +{ + let user_cb = unsafe { transmute::<*mut c_void, MessageCallback>(user_cb) }; + + let Ok(msg_length) = usize::try_from(message_length) else { + return; + }; + + // Unwinds are catched because unwinding from Rust code into foreign code is UB. + let res = catch_unwind(|| { + let msg_source = MessageSource::from_repr(source).unwrap(); + let msg_type = MessageType::from_repr(ty).unwrap(); + let msg_severity = MessageSeverity::from_repr(severity).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, + )) + }; + + user_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!(); + } +} |