1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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!();
}
}
|