Merge branch 'blender2.7'
[blender.git] / source / blender / gpu / intern / gpu_debug.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel, Jason Wilkins, Mike Erwin.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file source/blender/gpu/intern/gpu_debug.c
29  *  \ingroup gpu
30  */
31
32 #include "BLI_compiler_attrs.h"
33 #include "BLI_utildefines.h"
34 #include "BLI_sys_types.h"
35 #include "BLI_system.h"
36
37 #include "BKE_global.h"
38
39 #include "GPU_glew.h"
40 #include "GPU_debug.h"
41 #include "intern/gpu_private.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #ifndef __APPLE__ /* only non-Apple systems implement OpenGL debug callbacks */
48
49 /* control whether we use older AMD_debug_output extension
50  * some supported GPU + OS combos do not have the newer extensions */
51 #  define LEGACY_DEBUG 1
52
53 /* Debug callbacks need the same calling convention as OpenGL functions. */
54 #  if defined(_WIN32)
55 #    define APIENTRY __stdcall
56 #  else
57 #    define APIENTRY
58 #  endif
59
60
61 static const char *source_name(GLenum source)
62 {
63         switch (source) {
64                 case GL_DEBUG_SOURCE_API: return "API";
65                 case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "window system";
66                 case GL_DEBUG_SOURCE_SHADER_COMPILER: return "shader compiler";
67                 case GL_DEBUG_SOURCE_THIRD_PARTY: return "3rd party";
68                 case GL_DEBUG_SOURCE_APPLICATION: return "application";
69                 case GL_DEBUG_SOURCE_OTHER: return "other";
70                 default: return "???";
71         }
72 }
73
74 static const char *message_type_name(GLenum message)
75 {
76         switch (message) {
77                 case GL_DEBUG_TYPE_ERROR: return "error";
78                 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "deprecated behavior";
79                 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "undefined behavior";
80                 case GL_DEBUG_TYPE_PORTABILITY: return "portability";
81                 case GL_DEBUG_TYPE_PERFORMANCE: return "performance";
82                 case GL_DEBUG_TYPE_OTHER: return "other";
83                 case GL_DEBUG_TYPE_MARKER: return "marker"; /* KHR has this, ARB does not */
84                 default: return "???";
85         }
86 }
87
88 static void APIENTRY gpu_debug_proc(
89         GLenum source, GLenum type, GLuint UNUSED(id),
90         GLenum severity, GLsizei UNUSED(length),
91         const GLchar *message, const GLvoid *UNUSED(userParm))
92 {
93         bool backtrace = false;
94
95         switch (severity) {
96                 case GL_DEBUG_SEVERITY_HIGH:
97                         backtrace = true;
98                         ATTR_FALLTHROUGH;
99                 case GL_DEBUG_SEVERITY_MEDIUM:
100                 case GL_DEBUG_SEVERITY_LOW:
101                 case GL_DEBUG_SEVERITY_NOTIFICATION: /* KHR has this, ARB does not */
102                         fprintf(stderr, "GL %s %s: %s\n", source_name(source), message_type_name(type), message);
103         }
104
105         if (backtrace) {
106                 BLI_system_backtrace(stderr);
107                 fflush(stderr);
108         }
109 }
110
111 #  if LEGACY_DEBUG
112
113 static const char *category_name_amd(GLenum category)
114 {
115         switch (category) {
116                 case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error";
117                 case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system";
118                 case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior";
119                 case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior";
120                 case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance";
121                 case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler";
122                 case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application";
123                 case GL_DEBUG_CATEGORY_OTHER_AMD: return "other";
124                 default: return "???";
125         }
126 }
127
128 static void APIENTRY gpu_debug_proc_amd(
129         GLuint UNUSED(id), GLenum category,
130         GLenum severity, GLsizei UNUSED(length),
131         const GLchar *message,  GLvoid *UNUSED(userParm))
132 {
133         bool backtrace = false;
134
135         switch (severity) {
136                 case GL_DEBUG_SEVERITY_HIGH:
137                         backtrace = true;
138                         ATTR_FALLTHROUGH;
139                 case GL_DEBUG_SEVERITY_MEDIUM:
140                 case GL_DEBUG_SEVERITY_LOW:
141                         fprintf(stderr, "GL %s: %s\n", category_name_amd(category), message);
142         }
143
144         if (backtrace) {
145                 BLI_system_backtrace(stderr);
146                 fflush(stderr);
147         }
148 }
149 #  endif /* LEGACY_DEBUG */
150
151 #  undef APIENTRY
152 #endif /* not Apple */
153
154 void gpu_debug_init(void)
155 {
156 #ifdef __APPLE__
157         fprintf(stderr, "OpenGL debug callback is not available on Apple.\n");
158 #else /* not Apple */
159         const char success[] = "Successfully hooked OpenGL debug callback.";
160
161         if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
162                 fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension");
163                 glEnable(GL_DEBUG_OUTPUT);
164                 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
165                 glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, NULL);
166                 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
167                 GPU_string_marker(success);
168         }
169         else if (GLEW_ARB_debug_output) {
170                 fprintf(stderr, "Using ARB_debug_output extension\n");
171                 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
172                 glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, NULL);
173                 glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
174                 GPU_string_marker(success);
175         }
176 #  if LEGACY_DEBUG
177         else if (GLEW_AMD_debug_output) {
178                 fprintf(stderr, "Using AMD_debug_output extension\n");
179                 glDebugMessageCallbackAMD(gpu_debug_proc_amd, NULL);
180                 glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
181                 GPU_string_marker(success);
182         }
183 #  endif
184         else {
185                 fprintf(stderr, "Failed to hook OpenGL debug callback.\n");
186         }
187 #endif /* not Apple */
188 }
189
190
191 void gpu_debug_exit(void)
192 {
193 #ifndef __APPLE__
194         if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
195                 glDebugMessageCallback(NULL, NULL);
196         }
197         else if (GLEW_ARB_debug_output) {
198                 glDebugMessageCallbackARB(NULL, NULL);
199         }
200 #  if LEGACY_DEBUG
201         else if (GLEW_AMD_debug_output) {
202                 glDebugMessageCallbackAMD(NULL, NULL);
203         }
204 #  endif
205 #endif
206 }
207
208 void GPU_string_marker(const char *buf)
209 {
210 #ifdef __APPLE__
211         UNUSED_VARS(buf);
212 #else /* not Apple */
213         if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
214                 glDebugMessageInsert(
215                         GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
216                         GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
217         }
218         else if (GLEW_ARB_debug_output) {
219                 glDebugMessageInsertARB(
220                         GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0,
221                         GL_DEBUG_SEVERITY_LOW_ARB, -1, buf);
222         }
223 #  if LEGACY_DEBUG
224         else if (GLEW_AMD_debug_output) {
225                 glDebugMessageInsertAMD(
226                         GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0,
227                         0, buf);
228         }
229 #  endif
230 #endif /* not Apple */
231 }
232
233 void GPU_print_error_debug(const char *str)
234 {
235         if (G.debug & G_DEBUG)
236                 fprintf(stderr, "GPU: %s\n", str);
237 }