glium/debug.rs
1/*!
2
3
4*/
5
6use crate::backend::Facade;
7use crate::context::Context;
8use crate::ContextExt;
9use crate::version::Api;
10use crate::version::Version;
11use crate::gl;
12use std::rc::Rc;
13
14pub use crate::context::DebugCallbackBehavior;
15
16/// Represents a callback that can be used for the debug output feature of OpenGL.
17///
18/// The first three parameters are self-explanatory. The fourth parameter is an identifier for this
19/// message whose meaning is implementation-defined. The fifth parameter indicates whether glium
20/// is already handling any possible error condition, so you don't need to print an error. The last
21/// parameter is a message generated by the OpenGL implementation.
22pub type DebugCallback = Box<dyn FnMut(Source, MessageType, Severity, u32, bool, &str)>;
23
24/// Severity of a debug message.
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26#[repr(u32)]
27pub enum Severity {
28 /// Anything that isn't an error or performance issue.
29 Notification = gl::DEBUG_SEVERITY_NOTIFICATION,
30
31 /// Redundant state-change performance warning, or unimportant undefined behavior.
32 Low = gl::DEBUG_SEVERITY_LOW,
33
34 /// Major performance warnings, shader compilation/linking warnings,
35 /// or the use of deprecated functionality.
36 Medium = gl::DEBUG_SEVERITY_MEDIUM,
37
38 /// All OpenGL Errors, shader compilation/linking errors,
39 /// or highly-dangerous undefined behavior.
40 High = gl::DEBUG_SEVERITY_HIGH,
41}
42
43/// Source of a debug message.
44#[derive(Clone, Copy, Debug)]
45#[repr(u32)]
46pub enum Source {
47 /// Calls to the OpenGL API.
48 Api = gl::DEBUG_SOURCE_API,
49
50 /// Calls to a window-system API.
51 WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,
52
53 /// A compiler for a shading language.
54 ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,
55
56 /// An application associated with Openctxt.gl.
57 ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,
58
59 /// Explicitly generated by Glium or the application.
60 ///
61 /// This should never happen, but is included here for completeness.
62 Application = gl::DEBUG_SOURCE_APPLICATION,
63
64 ///
65 OtherSource = gl::DEBUG_SOURCE_OTHER,
66}
67
68/// Type of a debug message.
69#[derive(Clone, Copy, Debug)]
70#[repr(u32)]
71pub enum MessageType {
72 /// An error, typically from the API
73 Error = gl::DEBUG_TYPE_ERROR,
74 /// Some behavior marked deprecated has been used
75 DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
76 /// Something has invoked undefined behavior
77 UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
78 /// Some functionality the user relies upon is not portable
79 Portability = gl::DEBUG_TYPE_PORTABILITY,
80 /// Code has triggered possible performance issues
81 Performance = gl::DEBUG_TYPE_PERFORMANCE,
82 /// Command stream annotation
83 Marker = gl::DEBUG_TYPE_MARKER,
84 /// Entering a debug group
85 PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
86 /// Leaving a debug group
87 PopGroup = gl::DEBUG_TYPE_POP_GROUP,
88 /// Any other event
89 Other = gl::DEBUG_TYPE_OTHER,
90}
91
92/// Allows you to obtain the timestamp inside the OpenGL commands queue.
93///
94/// When you call functions in glium, they are not instantly executed. Instead they are
95/// added in a commands queue that the backend executes asynchronously.
96///
97/// When you call `TimestampQuery::new`, a command is added to this list asking the
98/// backend to send us the current timestamp. Thanks to this, you can know how much time
99/// it takes to execute commands.
100///
101/// ## Example
102///
103/// ```no_run
104/// # use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
105/// # fn example<T>(display: glium::Display<T>) where T: SurfaceTypeTrait + ResizeableSurface {
106/// let before = glium::debug::TimestampQuery::new(&display);
107/// // do some stuff here
108/// let after = glium::debug::TimestampQuery::new(&display);
109///
110/// match (after, before) {
111/// (Some(after), Some(before)) => {
112/// let elapsed = after.get() - before.get();
113/// println!("Time it took to do stuff: {}", elapsed);
114/// },
115/// _ => ()
116/// }
117/// # }
118/// ```
119///
120pub struct TimestampQuery {
121 context: Rc<Context>,
122 id: gl::types::GLuint,
123}
124
125impl TimestampQuery {
126 /// Creates a new `TimestampQuery`. Returns `None` if the backend doesn't support it.
127 pub fn new<F: ?Sized>(facade: &F) -> Option<TimestampQuery> where F: Facade {
128 let ctxt = facade.get_context().make_current();
129
130 let id = if ctxt.version >= &Version(Api::Gl, 3, 2) { // TODO: extension
131 unsafe {
132 let mut id = 0;
133 ctxt.gl.GenQueries(1, &mut id);
134
135 ctxt.gl.QueryCounter(id, gl::TIMESTAMP);
136
137 Some(id)
138 }
139
140 } else if ctxt.extensions.gl_ext_disjoint_timer_query {
141 unsafe {
142 let mut id = 0;
143 ctxt.gl.GenQueriesEXT(1, &mut id);
144
145 ctxt.gl.QueryCounterEXT(id, gl::TIMESTAMP);
146
147 Some(id)
148 }
149
150 } else {
151 None
152 };
153
154 id.map(|q| TimestampQuery {
155 context: facade.get_context().clone(),
156 id: q
157 })
158 }
159
160 /// Queries the counter to see if the timestamp is already available.
161 ///
162 /// It takes some time to retrieve the value, during which you can execute other
163 /// functions.
164 pub fn is_ready(&self) -> bool {
165 let ctxt = self.context.make_current();
166
167 if ctxt.version >= &Version(Api::Gl, 3, 2) { // TODO: extension
168 unsafe {
169 let mut value = 0;
170 ctxt.gl.GetQueryObjectiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
171 value != 0
172 }
173
174 } else if ctxt.extensions.gl_ext_disjoint_timer_query {
175 unsafe {
176 let mut value = 0;
177 ctxt.gl.GetQueryObjectivEXT(self.id, gl::QUERY_RESULT_AVAILABLE_EXT, &mut value);
178 value != 0
179 }
180
181 } else {
182 unreachable!();
183 }
184 }
185
186 /// Returns the value of the timestamp. Blocks until it is available.
187 ///
188 /// This function doesn't block if `is_ready` returns true.
189 pub fn get(self) -> u64 {
190 let ctxt = self.context.make_current();
191
192 if ctxt.version >= &Version(Api::Gl, 3, 2) { // TODO: extension
193 unsafe {
194 let mut value = 0;
195 ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, &mut value);
196 ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
197 value
198 }
199
200 } else if ctxt.extensions.gl_ext_disjoint_timer_query {
201 unsafe {
202 let mut value = 0;
203 ctxt.gl.GetQueryObjectui64vEXT(self.id, gl::QUERY_RESULT_EXT, &mut value);
204 ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
205 value
206 }
207
208 } else {
209 unreachable!();
210 }
211 }
212}