1 /*
2 * Copyright (c) 2013 Arthur Huillet
3 *
4 *
5 * This file is part of Freedroid
6 *
7 * Freedroid is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * Freedroid is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Freedroid; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 *
22 */
23
24 /**
25 * This file contains OpenGL debug-related code.
26 * It makes use of KHR_debug if available.
27 */
28
29 #define _open_gl_debug_c
30
31 #include "system.h"
32 #include "defs.h"
33 #include "struct.h"
34 #include "global.h"
35 #include "proto.h"
36
37 // For a not yet known reason, init_opengl_debug() crashes on some Win10
38 // computers (observed on 64b systems with NVidia GPU).
39 // Further test is needed to solve that issue.
40
41 #if defined(HAVE_LIBGL) && (!defined __WIN32__)
42
43 // Copy-paste of glext.h because SDL's is outdated
44 #ifndef GL_KHR_debug
45 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
46 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
47 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244
48 #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
49 #define GL_DEBUG_SOURCE_API 0x8246
50 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
51 #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
52 #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
53 #define GL_DEBUG_SOURCE_APPLICATION 0x824A
54 #define GL_DEBUG_SOURCE_OTHER 0x824B
55 #define GL_DEBUG_TYPE_ERROR 0x824C
56 #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
57 #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
58 #define GL_DEBUG_TYPE_PORTABILITY 0x824F
59 #define GL_DEBUG_TYPE_PERFORMANCE 0x8250
60 #define GL_DEBUG_TYPE_OTHER 0x8251
61 #define GL_DEBUG_TYPE_MARKER 0x8268
62 #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
63 #define GL_DEBUG_TYPE_POP_GROUP 0x826A
64 #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
65 #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
66 #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
67 #define GL_BUFFER 0x82E0
68 #define GL_SHADER 0x82E1
69 #define GL_PROGRAM 0x82E2
70 #define GL_QUERY 0x82E3
71 #define GL_PROGRAM_PIPELINE 0x82E4
72 #define GL_SAMPLER 0x82E6
73 #define GL_DISPLAY_LIST 0x82E7
74 /* DISPLAY_LIST used in compatibility profile only */
75 #define GL_MAX_LABEL_LENGTH 0x82E8
76 #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
77 #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
78 #define GL_DEBUG_LOGGED_MESSAGES 0x9145
79 #define GL_DEBUG_SEVERITY_HIGH 0x9146
80 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147
81 #define GL_DEBUG_SEVERITY_LOW 0x9148
82 #define GL_DEBUG_OUTPUT 0x92E0
83 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
84 /* reuse GL_STACK_UNDERFLOW */
85 /* reuse GL_STACK_OVERFLOW */
86 typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
87 typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
88 typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
89 typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
90 typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
91 typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
92 typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
93 typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
94 typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
95 typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
96 typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
97 #endif
98
99 PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl;
100 PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback;
101
102 #define DBG_FLAG(f) { f, #f }
103 struct debug_flag {
104 GLenum flag_value;
105 char *flag_descr;
106 } debug_flags[] = {
107 DBG_FLAG(GL_DEBUG_OUTPUT_SYNCHRONOUS),
108 DBG_FLAG(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH),
109 DBG_FLAG(GL_DEBUG_CALLBACK_FUNCTION),
110 DBG_FLAG(GL_DEBUG_CALLBACK_USER_PARAM),
111 DBG_FLAG(GL_DEBUG_SOURCE_API),
112 DBG_FLAG(GL_DEBUG_SOURCE_WINDOW_SYSTEM),
113 DBG_FLAG(GL_DEBUG_SOURCE_SHADER_COMPILER),
114 DBG_FLAG(GL_DEBUG_SOURCE_THIRD_PARTY),
115 DBG_FLAG(GL_DEBUG_SOURCE_APPLICATION),
116 DBG_FLAG(GL_DEBUG_SOURCE_OTHER),
117 DBG_FLAG(GL_DEBUG_TYPE_ERROR),
118 DBG_FLAG(GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR),
119 DBG_FLAG(GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR),
120 DBG_FLAG(GL_DEBUG_TYPE_PORTABILITY),
121 DBG_FLAG(GL_DEBUG_TYPE_PERFORMANCE),
122 DBG_FLAG(GL_DEBUG_TYPE_OTHER),
123 DBG_FLAG(GL_DEBUG_TYPE_MARKER),
124 DBG_FLAG(GL_DEBUG_TYPE_PUSH_GROUP),
125 DBG_FLAG(GL_DEBUG_TYPE_POP_GROUP),
126 DBG_FLAG(GL_DEBUG_SEVERITY_NOTIFICATION),
127 DBG_FLAG(GL_MAX_DEBUG_GROUP_STACK_DEPTH),
128 DBG_FLAG(GL_DEBUG_GROUP_STACK_DEPTH),
129 DBG_FLAG(GL_BUFFER),
130 DBG_FLAG(GL_SHADER),
131 DBG_FLAG(GL_PROGRAM),
132 DBG_FLAG(GL_QUERY),
133 DBG_FLAG(GL_PROGRAM_PIPELINE),
134 DBG_FLAG(GL_SAMPLER),
135 DBG_FLAG(GL_DISPLAY_LIST),
136 DBG_FLAG(GL_MAX_LABEL_LENGTH),
137 DBG_FLAG(GL_MAX_DEBUG_MESSAGE_LENGTH),
138 DBG_FLAG(GL_MAX_DEBUG_LOGGED_MESSAGES),
139 DBG_FLAG(GL_DEBUG_LOGGED_MESSAGES),
140 DBG_FLAG(GL_DEBUG_SEVERITY_HIGH),
141 DBG_FLAG(GL_DEBUG_SEVERITY_MEDIUM),
142 DBG_FLAG(GL_DEBUG_SEVERITY_LOW),
143 DBG_FLAG(GL_DEBUG_OUTPUT),
144 { 0x0503, "GL_STACK_OVERFLOW" },
145 { 0x0504, "GL_STACK_UNDERFLOW" }
146 };
147 #undef DBG_FLAG
148
find_debug_flag(GLenum value)149 static struct debug_flag *find_debug_flag(GLenum value)
150 {
151 unsigned int i;
152 for (i=0; i < sizeof(debug_flags)/sizeof(debug_flags[0]); i++) {
153 if (debug_flags[i].flag_value == value)
154 return &debug_flags[i];
155 }
156 return NULL;
157 }
158
gl_debug_callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,GLvoid * userParam)159 static void gl_debug_callback(GLenum source, GLenum type, GLuint id,
160 GLenum severity, GLsizei length, const GLchar* message,
161 GLvoid* userParam)
162 {
163 // Ignore certain message IDs
164
165 if (id == 131204) {
166 // "Waste of memory: Texture 0 has mipmaps, while it's min filter is inconsistent with mipmaps."
167 // Possible nvidia bug in version 313.30, ignore it for now
168 return;
169 }
170 if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
171 // Do not display notifications
172 return;
173 }
174
175 // Report a good looking error message
176
177 struct auto_string *msg = alloc_autostr(256);
178 struct debug_flag *data = NULL;
179
180 data = find_debug_flag(source);
181 if (data) {
182 autostr_append(msg, "Source = %s,", data->flag_descr);
183 } else {
184 autostr_append(msg, "Source = 0x%x,", source);
185 }
186
187 data = find_debug_flag(type);
188 if (data) {
189 autostr_append(msg, " type = %s,", data->flag_descr);
190 } else {
191 autostr_append(msg, " type = 0x%x,", type);
192 }
193
194 autostr_append(msg, " id = %d,", id);
195
196 data = find_debug_flag(severity);
197 if (data) {
198 autostr_append(msg, " severity = %s,", data->flag_descr);
199 } else {
200 autostr_append(msg, " severity = 0x%x,", severity);
201 }
202
203 error_message(__FUNCTION__, "%s: %s", NO_REPORT, msg->value, message);
204
205 free_autostr(msg);
206 }
207
208 /**
209 * Initialize and enabled the OpenGL debug features.
210 * @return 0 if OK, 1 if debug could not be enabled
211 */
init_opengl_debug(void)212 int init_opengl_debug(void)
213 {
214 /* Check if KHR_debug is available */
215 const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
216 if (!strstr(extensions, "GL_KHR_debug")) {
217 // no debug extension available
218 // We cannot use ARB_debug_output because it doesn't allow glEnable(GL_DEBUG_OUTPUT)
219 return 1;
220 }
221
222 glDebugMessageControl = SDL_GL_GetProcAddress("glDebugMessageControl");
223 glDebugMessageCallback = SDL_GL_GetProcAddress("glDebugMessageCallback");
224
225 if (!glDebugMessageCallback || !glDebugMessageControl) {
226 error_message(__FUNCTION__, "Unable to retrieve function pointers for glDebugMessageCallback and glDebugMessageControl, but debug extension is present.", PLEASE_INFORM);
227 return 1;
228 }
229
230 glEnable(GL_DEBUG_OUTPUT);
231 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
232 glDebugMessageCallback(&gl_debug_callback, NULL);
233 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
234
235 return 0;
236 }
237
238 #else // defined(HAVE_LIBGL) && (!defined __WIN32__)
239
init_opengl_debug(void)240 int init_opengl_debug(void)
241 {
242 return 1;
243 }
244
245 #endif // defined(HAVE_LIBGL) && (!defined __WIN32__)
246
247 /**
248 * This function checks the error status of the OpenGL driver. An error
249 * will produce at least a warning message, maybe even program termination
250 * if the errors are really severe.
251 */
open_gl_check_error_status(const char * name_of_calling_function)252 void open_gl_check_error_status(const char *name_of_calling_function)
253 {
254 #ifdef HAVE_LIBGL
255 char *enum_str = "UNKNOWN";
256 int error_type = PLEASE_INFORM;
257
258 switch (glGetError()) {
259 case GL_NO_ERROR:
260 return;
261 case GL_INVALID_ENUM:
262 enum_str = "GL_INVALID_ENUM";
263 break;
264 case GL_INVALID_VALUE:
265 enum_str = "GL_INVALID_VALUE";
266 break;
267 case GL_INVALID_OPERATION:
268 enum_str = "GL_INVALID_OPERATION";
269 break;
270 case GL_STACK_OVERFLOW:
271 enum_str = "GL_STACK_OVERFLOW";
272 error_type |= IS_FATAL;
273 break;
274 case GL_STACK_UNDERFLOW:
275 enum_str = "GL_STACK_UNDERFLOW";
276 error_type |= IS_FATAL;
277 break;
278 case GL_OUT_OF_MEMORY:
279 enum_str = "GL_OUT_OF_MEMORY";
280 error_type |= IS_FATAL;
281 break;
282 }
283
284 error_message(__FUNCTION__, "Error code %s received, called by %s.", error_type, enum_str, name_of_calling_function);
285 #endif
286 }
287
288
289 #undef _open_gl_debug_c
290