Blender  V2.93
gl_debug.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include "BLI_compiler_attrs.h"
27 #include "BLI_string.h"
28 #include "BLI_system.h"
29 #include "BLI_utildefines.h"
30 
31 #include "BKE_global.h"
32 
33 #include "GPU_debug.h"
34 #include "GPU_platform.h"
35 
36 #include "CLG_log.h"
37 
38 #include "glew-mx.h"
39 
40 #include "gl_context.hh"
41 #include "gl_uniform_buffer.hh"
42 
43 #include "gl_debug.hh"
44 
45 #include <cstdio>
46 
47 static CLG_LogRef LOG = {"gpu.debug"};
48 
49 /* Avoid too much NVidia buffer info in the output log. */
50 #define TRIM_NVIDIA_BUFFER_INFO 1
51 /* Avoid unneeded shader statistics. */
52 #define TRIM_SHADER_STATS_INFO 1
53 
55 
56 /* -------------------------------------------------------------------- */
63 /* Debug callbacks need the same calling convention as OpenGL functions. */
64 #if defined(_WIN32)
65 # define APIENTRY __stdcall
66 #else
67 # define APIENTRY
68 #endif
69 
70 static void APIENTRY debug_callback(GLenum UNUSED(source),
71  GLenum type,
72  GLuint UNUSED(id),
73  GLenum severity,
74  GLsizei UNUSED(length),
75  const GLchar *message,
76  const GLvoid *UNUSED(userParm))
77 {
78  if (ELEM(type, GL_DEBUG_TYPE_PUSH_GROUP, GL_DEBUG_TYPE_POP_GROUP)) {
79  /* The debug layer will emit a message each time a debug group is pushed or popped.
80  * We use that for easy command grouping inside frame analyzer tools. */
81  return;
82  }
83 
86  STRPREFIX(message, "Buffer detailed info")) {
88  return;
89  }
90 
91  if (TRIM_SHADER_STATS_INFO && STRPREFIX(message, "Shader Stats")) {
93  return;
94  }
95 
96  const bool use_color = CLG_color_support_get(&LOG);
97 
98  if (ELEM(severity, GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_NOTIFICATION)) {
99  if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= CLG_SEVERITY_INFO))) {
100  const char *format = use_color ? "\033[2m%s\033[0m" : "%s";
101  CLG_logf(LOG.type, CLG_SEVERITY_INFO, "Notification", "", format, message);
102  }
103  }
104  else {
105  char debug_groups[512] = "";
106  GPU_debug_get_groups_names(sizeof(debug_groups), debug_groups);
107  CLG_Severity clog_severity;
108 
109  switch (type) {
110  case GL_DEBUG_TYPE_ERROR:
111  case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
112  case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
113  clog_severity = CLG_SEVERITY_ERROR;
114  break;
115  case GL_DEBUG_TYPE_PORTABILITY:
116  case GL_DEBUG_TYPE_PERFORMANCE:
117  case GL_DEBUG_TYPE_OTHER:
118  case GL_DEBUG_TYPE_MARKER: /* KHR has this, ARB does not */
119  default:
120  clog_severity = CLG_SEVERITY_WARN;
121  break;
122  }
123 
124  if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= clog_severity))) {
125  CLG_logf(LOG.type, clog_severity, debug_groups, "", "%s", message);
126  if (severity == GL_DEBUG_SEVERITY_HIGH) {
127  /* Focus on error message. */
128  if (use_color) {
129  fprintf(stderr, "\033[2m");
130  }
131  BLI_system_backtrace(stderr);
132  if (use_color) {
133  fprintf(stderr, "\033[0m\n");
134  }
135  fflush(stderr);
136  }
137  }
138  }
139 }
140 
141 #undef APIENTRY
142 
143 /* This function needs to be called once per context. */
145 {
146  CLOG_ENSURE(&LOG);
147 
148  char msg[256] = "";
149  const char format[] = "Successfully hooked OpenGL debug callback using %s";
150 
151  if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
152  SNPRINTF(msg, format, GLEW_VERSION_4_3 ? "OpenGL 4.3" : "KHR_debug extension");
153  glEnable(GL_DEBUG_OUTPUT);
154  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
155  glDebugMessageCallback((GLDEBUGPROC)debug_callback, nullptr);
156  glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
157  glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION,
158  GL_DEBUG_TYPE_MARKER,
159  0,
160  GL_DEBUG_SEVERITY_NOTIFICATION,
161  -1,
162  msg);
163  }
164  else if (GLEW_ARB_debug_output) {
165  SNPRINTF(msg, format, "ARB_debug_output");
166  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
167  glDebugMessageCallbackARB((GLDEBUGPROCARB)debug_callback, nullptr);
168  glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
169  glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB,
170  GL_DEBUG_TYPE_OTHER_ARB,
171  0,
172  GL_DEBUG_SEVERITY_LOW_ARB,
173  -1,
174  msg);
175  }
176  else {
177  CLOG_STR_WARN(&LOG, "Failed to hook OpenGL debug callback. Use fallback debug layer.");
179  }
180 }
181 
184 /* -------------------------------------------------------------------- */
191 void check_gl_error(const char *info)
192 {
193  GLenum error = glGetError();
194 
195 #define ERROR_CASE(err) \
196  case err: { \
197  char msg[256]; \
198  SNPRINTF(msg, "%s : %s", #err, info); \
199  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, NULL); \
200  break; \
201  }
202 
203  switch (error) {
204  ERROR_CASE(GL_INVALID_ENUM)
205  ERROR_CASE(GL_INVALID_VALUE)
206  ERROR_CASE(GL_INVALID_OPERATION)
207  ERROR_CASE(GL_INVALID_FRAMEBUFFER_OPERATION)
208  ERROR_CASE(GL_OUT_OF_MEMORY)
209  ERROR_CASE(GL_STACK_UNDERFLOW)
210  ERROR_CASE(GL_STACK_OVERFLOW)
211  case GL_NO_ERROR:
212  break;
213  default:
214  char msg[256];
215  SNPRINTF(msg, "Unknown GL error: %x : %s", error, info);
216  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
217  break;
218  }
219 }
220 
221 void check_gl_resources(const char *info)
222 {
223  if (!(G.debug & G_DEBUG_GPU) || GPU_bgl_get()) {
224  return;
225  }
226 
227  GLContext *ctx = GLContext::get();
228  ShaderInterface *interface = ctx->shader->interface;
229  /* NOTE: This only check binding. To be valid, the bound ubo needs to
230  * be big enough to feed the data range the shader awaits. */
231  uint16_t ubo_needed = interface->enabled_ubo_mask_;
232  ubo_needed &= ~ctx->bound_ubo_slots;
233  /* NOTE: This only check binding. To be valid, the bound texture needs to
234  * be the same format/target the shader expects. */
235  uint64_t tex_needed = interface->enabled_tex_mask_;
236  tex_needed &= ~GLContext::state_manager_active_get()->bound_texture_slots();
237  /* NOTE: This only check binding. To be valid, the bound image needs to
238  * be the same format/target the shader expects. */
239  uint8_t ima_needed = interface->enabled_ima_mask_;
240  ima_needed &= ~GLContext::state_manager_active_get()->bound_image_slots();
241 
242  if (ubo_needed == 0 && tex_needed == 0 && ima_needed == 0) {
243  return;
244  }
245 
246  for (int i = 0; ubo_needed != 0; i++, ubo_needed >>= 1) {
247  if ((ubo_needed & 1) != 0) {
248  const ShaderInput *ubo_input = interface->ubo_get(i);
249  const char *ubo_name = interface->input_name_get(ubo_input);
250  const char *sh_name = ctx->shader->name_get();
251  char msg[256];
252  SNPRINTF(msg, "Missing UBO bind at slot %d : %s > %s : %s", i, sh_name, ubo_name, info);
253  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
254  }
255  }
256 
257  for (int i = 0; tex_needed != 0; i++, tex_needed >>= 1) {
258  if ((tex_needed & 1) != 0) {
259  /* FIXME: texture_get might return an image input instead. */
260  const ShaderInput *tex_input = interface->texture_get(i);
261  const char *tex_name = interface->input_name_get(tex_input);
262  const char *sh_name = ctx->shader->name_get();
263  char msg[256];
264  SNPRINTF(msg, "Missing Texture bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info);
265  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
266  }
267  }
268 
269  for (int i = 0; ima_needed != 0; i++, ima_needed >>= 1) {
270  if ((ima_needed & 1) != 0) {
271  /* FIXME: texture_get might return a texture input instead. */
272  const ShaderInput *tex_input = interface->texture_get(i);
273  const char *tex_name = interface->input_name_get(tex_input);
274  const char *sh_name = ctx->shader->name_get();
275  char msg[256];
276  SNPRINTF(msg, "Missing Image bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info);
277  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
278  }
279  }
280 }
281 
282 void raise_gl_error(const char *info)
283 {
284  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, info, nullptr);
285 }
286 
289 /* -------------------------------------------------------------------- */
296 static const char *to_str_prefix(GLenum type)
297 {
298  switch (type) {
299  case GL_FRAGMENT_SHADER:
300  case GL_GEOMETRY_SHADER:
301  case GL_VERTEX_SHADER:
302  case GL_SHADER:
303  case GL_PROGRAM:
304  return "SHD-";
305  case GL_SAMPLER:
306  return "SAM-";
307  case GL_TEXTURE:
308  return "TEX-";
309  case GL_FRAMEBUFFER:
310  return "FBO-";
311  case GL_VERTEX_ARRAY:
312  return "VAO-";
313  case GL_UNIFORM_BUFFER:
314  return "UBO-";
315  case GL_BUFFER:
316  return "BUF-";
317  default:
318  return "";
319  }
320 }
321 static const char *to_str_suffix(GLenum type)
322 {
323  switch (type) {
324  case GL_FRAGMENT_SHADER:
325  return "-Frag";
326  case GL_GEOMETRY_SHADER:
327  return "-Geom";
328  case GL_VERTEX_SHADER:
329  return "-Vert";
330  default:
331  return "";
332  }
333 }
334 
335 void object_label(GLenum type, GLuint object, const char *name)
336 {
337  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
338  char label[64];
339  SNPRINTF(label, "%s%s%s", to_str_prefix(type), name, to_str_suffix(type));
340  /* Small convenience for caller. */
341  if (ELEM(type, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_VERTEX_SHADER)) {
342  type = GL_SHADER;
343  }
344  if (ELEM(type, GL_UNIFORM_BUFFER)) {
345  type = GL_BUFFER;
346  }
347  glObjectLabel(type, object, -1, label);
348  }
349 }
350 
353 } // namespace blender::gpu::debug
354 
355 namespace blender::gpu {
356 
357 /* -------------------------------------------------------------------- */
363 void GLContext::debug_group_begin(const char *name, int index)
364 {
365  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
366  /* Add 10 to avoid collision with other indices from other possible callback layers. */
367  index += 10;
368  glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, index, -1, name);
369  }
370 }
371 
373 {
374  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
375  glPopDebugGroup();
376  }
377 }
378 
381 } // namespace blender::gpu
@ G_DEBUG_GPU
Definition: BKE_global.h:151
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:165
void BLI_system_backtrace(FILE *fp)
Definition: system.c:79
#define STRPREFIX(a, b)
#define UNUSED(x)
#define ELEM(...)
CLG_Severity
Definition: CLG_log.h:99
@ CLG_SEVERITY_INFO
Definition: CLG_log.h:100
@ CLG_SEVERITY_WARN
Definition: CLG_log.h:101
@ CLG_SEVERITY_ERROR
Definition: CLG_log.h:102
@ CLG_FLAG_USE
Definition: CLG_log.h:96
void void CLG_logf(CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn, const char *format,...) _CLOG_ATTR_NONNULL(1
#define CLOG_ENSURE(clg_ref)
Definition: CLG_log.h:162
#define CLOG_STR_WARN(clg_ref, str)
Definition: CLG_log.h:209
int CLG_color_support_get(CLG_LogRef *clg_ref)
Definition: clog.c:799
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
Definition: gpu_debug.cc:62
#define glEnable
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
@ GPU_DRIVER_OFFICIAL
Definition: GPU_platform.h:53
@ GPU_OS_ANY
Definition: GPU_platform.h:49
@ GPU_DEVICE_NVIDIA
Definition: GPU_platform.h:33
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
bool GPU_bgl_get(void)
Definition: gpu_state.cc:381
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
void debug_group_begin(const char *name, int index) override
Definition: gl_debug.cc:363
static GLContext * get()
Definition: gl_context.hh:118
void debug_group_end(void) override
Definition: gl_debug.cc:372
const char *const name_get(void) const
const char * label
#define ERROR_CASE(err)
#define APIENTRY
Definition: gl_debug.cc:67
#define TRIM_NVIDIA_BUFFER_INFO
Definition: gl_debug.cc:50
#define TRIM_SHADER_STATS_INFO
Definition: gl_debug.cc:52
static CLG_LogRef LOG
Definition: gl_debug.cc:47
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
format
Definition: logImageCore.h:47
static void error(const char *str)
Definition: meshlaplacian.c:65
void init_gl_callbacks()
Definition: gl_debug.cc:144
void check_gl_resources(const char *info)
Definition: gl_debug.cc:221
static void APIENTRY debug_callback(GLenum UNUSED(source), GLenum type, GLuint UNUSED(id), GLenum severity, GLsizei UNUSED(length), const GLchar *message, const GLvoid *UNUSED(userParm))
Definition: gl_debug.cc:70
void raise_gl_error(const char *info)
Definition: gl_debug.cc:282
void init_debug_layer(void)
static const char * to_str_prefix(GLenum type)
Definition: gl_debug.cc:296
void check_gl_error(const char *info)
Definition: gl_debug.cc:191
static const char * to_str_suffix(GLenum type)
Definition: gl_debug.cc:321
void object_label(GLenum type, GLuint object, const char *name)
Definition: gl_debug.cc:335
static void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, short thread)
unsigned short uint16_t
Definition: stdint.h:82
unsigned char uint8_t
Definition: stdint.h:81
unsigned __int64 uint64_t
Definition: stdint.h:93
CLG_LogType * type
Definition: CLG_log.h:120
enum CLG_LogFlag flag
Definition: CLG_log.h:115
int level
Definition: CLG_log.h:114
#define G(x, y, z)