GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 128, 0 excluded
0.0%
Functions:
0 of 24, 0 excluded
0.0%
Branches:
0 of 86, 0 excluded
0.0%

libs/render/src/render/opengl_utils.cc
Line Branch Exec Source
1 #include "render/opengl_utils.h"
2
3 #include "assert/assert.h"
4 // #include "klotter/str.h"
5 #include "dependency_glad.h"
6
7
8 namespace eu::render
9 {
10
11 #if FF_HAS(ENABLE_GL_DEBUG)
12 const char* string_from_opengl_error_enum(GLenum error_code)
13 {
14 switch (error_code)
15 {
16 case GL_INVALID_ENUM: return "INVALID_ENUM";
17 case GL_INVALID_VALUE: return "INVALID_VALUE";
18 case GL_INVALID_OPERATION: return "INVALID_OPERATION";
19 #ifdef GL_STACK_OVERFLOW
20 case GL_STACK_OVERFLOW: return "STACK_OVERFLOW";
21 #endif
22 #ifdef GL_STACK_UNDERFLOW
23 case GL_STACK_UNDERFLOW: return "STACK_UNDERFLOW";
24 #endif
25 case GL_OUT_OF_MEMORY: return "OUT_OF_MEMORY";
26 case GL_INVALID_FRAMEBUFFER_OPERATION: return "INVALID_FRAMEBUFFER_OPERATION";
27 default: return "UNKNOWN";
28 }
29 }
30
31 namespace
32 {
33 const char* string_from_debug_source(GLenum source)
34 {
35 switch (source)
36 {
37 case GL_DEBUG_SOURCE_API: return "API";
38 case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "Window System";
39 case GL_DEBUG_SOURCE_SHADER_COMPILER: return "Shader Compiler";
40 case GL_DEBUG_SOURCE_THIRD_PARTY: return "Third Party";
41 case GL_DEBUG_SOURCE_APPLICATION: return "Application";
42 case GL_DEBUG_SOURCE_OTHER: return "Other";
43 default: return "Unknown";
44 }
45 }
46
47 const char* string_from_debug_type(GLenum type)
48 {
49 switch (type)
50 {
51 case GL_DEBUG_TYPE_ERROR: return "Error";
52 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "Deprecated Behaviour";
53 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "Undefined Behaviour";
54 case GL_DEBUG_TYPE_PORTABILITY: return "Portability";
55 case GL_DEBUG_TYPE_PERFORMANCE: return "Performance";
56 case GL_DEBUG_TYPE_OTHER: return "Other";
57 default: return "Unknown";
58 }
59 }
60
61 const char* string_from_debug_severity(GLenum severity)
62 {
63 switch (severity)
64 {
65 case GL_DEBUG_SEVERITY_HIGH: return "High";
66 case GL_DEBUG_SEVERITY_MEDIUM: return "Medium";
67 case GL_DEBUG_SEVERITY_LOW: return "Low";
68 case GL_DEBUG_SEVERITY_NOTIFICATION: return "Notification";
69 default: return "Unknown";
70 }
71 }
72
73 } // namespace
74
75 void APIENTRY on_opengl_debug_output(
76 GLenum source,
77 GLenum type,
78 GLuint id,
79 GLenum severity,
80 GLsizei /*length*/,
81 const GLchar* message,
82 const GLvoid* /*userParam*/
83 )
84 {
85 switch (type)
86 {
87 // this is from ScopedDebugGroup
88 case GL_DEBUG_TYPE_PUSH_GROUP:
89 case GL_DEBUG_TYPE_POP_GROUP: return;
90 default: break;
91 }
92
93 // ignore non-significant error/warning codes
94 const auto is_important = type != GL_DEBUG_TYPE_OTHER;
95 const bool is_low = severity == GL_DEBUG_SEVERITY_LOW || severity == GL_DEBUG_SEVERITY_NOTIFICATION;
96
97 if (is_important == false && is_low)
98 {
99 /*
100 Tries to hide the following notification:
101 Buffer object 40 (bound to GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB (0),
102 GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB (1), GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB (2),
103 and GL_ARRAY_BUFFER_ARB, usage hint is GL_STREAM_DRAW) will use VIDEO memory as the source
104 for buffer object operations.
105 Buffer object 41 (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is
106 GL_STREAM_DRAW) will use VIDEO memory as the source for buffer object operations.
107 */
108 return;
109 }
110
111 // only display the first 10 notifications
112 static int error_count = 0;
113 if (is_important == false)
114 {
115 if (error_count > 10)
116 {
117 return;
118 }
119 ++error_count;
120 }
121
122 const std::string to_out = fmt::format("OpenGL #{} [src: {} | type: {} | sev: {}]: ", id, string_from_debug_source(source), string_from_debug_type(type), string_from_debug_severity(severity), message);
123
124 if (is_low)
125 {
126 LOG_INFOS(to_out);
127 }
128 else
129 {
130 LOG_ERRS(to_out.c_str());
131 }
132
133 if (is_important)
134 {
135 DIE("OpenGL error");
136 }
137 }
138
139 bool has_khr_debug()
140 {
141 return GLAD_GL_KHR_debug != 0;
142 }
143 #endif
144
145 void setup_opengl_debug()
146 {
147 #if FF_HAS(ENABLE_GL_DEBUG)
148 if (has_khr_debug())
149 {
150 LOG_INFO("Enabling OpenGL debug output (KHR_debug)");
151 glEnable(GL_DEBUG_OUTPUT);
152 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
153 glDebugMessageCallback(on_opengl_debug_output, nullptr);
154 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
155 }
156 else
157 {
158 LOG_ERR("KHR_debug not available, OpenGL debug output not enabled");
159 }
160 #endif
161 }
162
163 GLenum glenum_from_int(int i)
164 {
165 return static_cast<GLenum>(i);
166 }
167
168 GLuint gluint_from_int(int i)
169 {
170 return static_cast<GLuint>(i);
171 }
172
173 GLsizeiptr glsizeiptr_from_sizet(std::size_t t)
174 {
175 return static_cast<GLsizeiptr>(t);
176 }
177
178 GLsizei glsizei_from_sizet(std::size_t t)
179 {
180 return static_cast<GLsizei>(t);
181 }
182
183 u32 create_buffer()
184 {
185 u32 vbo = 0;
186 glGenBuffers(1, &vbo);
187 return vbo;
188 }
189
190 void destroy_buffer(u32 vbo)
191 {
192 glDeleteBuffers(1, &vbo);
193 }
194
195 u32 create_vertex_array()
196 {
197 u32 vao = 0;
198 glGenVertexArrays(1, &vao);
199 return vao;
200 }
201
202 void destroy_vertex_array(u32 vao)
203 {
204 glDeleteVertexArrays(1, &vao);
205 }
206
207 void set_gl_viewport(const Size& sz)
208 {
209 glViewport(0, 0, sz.width, sz.height);
210 }
211
212 #if FF_HAS(ENABLE_GL_DEBUG)
213 GLenum glenum_from_object_type(DebugLabelFor type)
214 {
215 switch (type)
216 {
217 case DebugLabelFor::Buffer: return GL_BUFFER;
218 case DebugLabelFor::Shader: return GL_SHADER;
219 case DebugLabelFor::Program: return GL_PROGRAM;
220 case DebugLabelFor::VertexArray: return GL_VERTEX_ARRAY;
221 case DebugLabelFor::Query: return GL_QUERY;
222 case DebugLabelFor::ProgramPipeline: return GL_PROGRAM_PIPELINE;
223 case DebugLabelFor::Sampler: return GL_SAMPLER;
224 case DebugLabelFor::Texture: return GL_TEXTURE;
225 case DebugLabelFor::RenderBuffer: return GL_RENDERBUFFER;
226 case DebugLabelFor::FrameBuffer: return GL_FRAMEBUFFER;
227 default: return GL_NONE;
228 }
229 }
230
231 void set_gl_debug_label_with_size(DebugLabelFor type, GLuint object, std::size_t size, const char* label)
232 {
233 if (! has_khr_debug())
234 {
235 return;
236 }
237
238 const auto gl_type = glenum_from_object_type(type);
239 if (gl_type == GL_NONE)
240 {
241 return;
242 }
243
244 glObjectLabel(gl_type, object, glsizei_from_sizet(size), label);
245 }
246
247 void set_gl_debug_label(DebugLabelFor type, GLuint object, const std::string& label)
248 {
249 set_gl_debug_label_with_size(type, object, label.size(), label.data());
250 }
251
252 void set_gl_debug_label(DebugLabelFor type, GLuint object, std::string_view label)
253 {
254 set_gl_debug_label_with_size(type, object, label.size(), label.data());
255 }
256
257 void push_debug_group(unsigned int id, std::size_t size, const char* label)
258 {
259 glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, id, glsizei_from_sizet(size), label);
260 }
261
262 ScopedDebugGroup::ScopedDebugGroup(const std::string& message, unsigned int id)
263 {
264 push_debug_group(id, message.size(), message.data());
265 }
266
267 ScopedDebugGroup::ScopedDebugGroup(std::string_view message, unsigned int id)
268 {
269 push_debug_group(id, message.size(), message.data());
270 }
271
272 ScopedDebugGroup::~ScopedDebugGroup()
273 {
274 glPopDebugGroup();
275 }
276 #endif
277
278 }
279