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}