Blender  V3.3
gl_debug.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
10 #include "BLI_compiler_attrs.h"
11 #include "BLI_string.h"
12 #include "BLI_system.h"
13 #include "BLI_utildefines.h"
14 
15 #include "BKE_global.h"
16 
17 #include "GPU_debug.h"
18 #include "GPU_platform.h"
19 
20 #include "CLG_log.h"
21 
22 #include "glew-mx.h"
23 
24 #include "gl_context.hh"
25 #include "gl_uniform_buffer.hh"
26 
27 #include "gl_debug.hh"
28 
29 #include <cstdio>
30 
31 static CLG_LogRef LOG = {"gpu.debug"};
32 
33 /* Avoid too much NVidia buffer info in the output log. */
34 #define TRIM_NVIDIA_BUFFER_INFO 1
35 /* Avoid unneeded shader statistics. */
36 #define TRIM_SHADER_STATS_INFO 1
37 
38 namespace blender::gpu::debug {
39 
40 /* -------------------------------------------------------------------- */
47 /* Debug callbacks need the same calling convention as OpenGL functions. */
48 #if defined(_WIN32)
49 # define APIENTRY __stdcall
50 #else
51 # define APIENTRY
52 #endif
53 
54 static void APIENTRY debug_callback(GLenum UNUSED(source),
55  GLenum type,
56  GLuint UNUSED(id),
57  GLenum severity,
58  GLsizei UNUSED(length),
59  const GLchar *message,
60  const GLvoid *UNUSED(userParm))
61 {
62  if (ELEM(type, GL_DEBUG_TYPE_PUSH_GROUP, GL_DEBUG_TYPE_POP_GROUP)) {
63  /* The debug layer will emit a message each time a debug group is pushed or popped.
64  * We use that for easy command grouping inside frame analyzer tools. */
65  return;
66  }
67 
68  /* NOTE: callback function can be triggered during before the platform is initialized.
69  * In this case invoking `GPU_type_matches` would fail and
70  * therefore the message is checked before the platform matching. */
71  if (TRIM_NVIDIA_BUFFER_INFO && STRPREFIX(message, "Buffer detailed info") &&
74  return;
75  }
76 
77  if (TRIM_SHADER_STATS_INFO && STRPREFIX(message, "Shader Stats")) {
79  return;
80  }
81 
82  const bool use_color = CLG_color_support_get(&LOG);
83 
84  if (ELEM(severity, GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_NOTIFICATION)) {
85  if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= CLG_SEVERITY_INFO))) {
86  const char *format = use_color ? "\033[2m%s\033[0m" : "%s";
87  CLG_logf(LOG.type, CLG_SEVERITY_INFO, "Notification", "", format, message);
88  }
89  }
90  else {
91  char debug_groups[512] = "";
92  GPU_debug_get_groups_names(sizeof(debug_groups), debug_groups);
93  CLG_Severity clog_severity;
94 
97  return;
98  }
99 
100  switch (type) {
101  case GL_DEBUG_TYPE_ERROR:
102  case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
103  case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
104  clog_severity = CLG_SEVERITY_ERROR;
105  break;
106  case GL_DEBUG_TYPE_PORTABILITY:
107  case GL_DEBUG_TYPE_PERFORMANCE:
108  case GL_DEBUG_TYPE_OTHER:
109  case GL_DEBUG_TYPE_MARKER: /* KHR has this, ARB does not */
110  default:
111  clog_severity = CLG_SEVERITY_WARN;
112  break;
113  }
114 
115  if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level <= clog_severity))) {
116  CLG_logf(LOG.type, clog_severity, debug_groups, "", "%s", message);
117  if (severity == GL_DEBUG_SEVERITY_HIGH) {
118  /* Focus on error message. */
119  if (use_color) {
120  fprintf(stderr, "\033[2m");
121  }
122  BLI_system_backtrace(stderr);
123  if (use_color) {
124  fprintf(stderr, "\033[0m\n");
125  }
126  fflush(stderr);
127  }
128  }
129  }
130 }
131 
132 #undef APIENTRY
133 
135 {
136  CLOG_ENSURE(&LOG);
137 
138  char msg[256] = "";
139  const char format[] = "Successfully hooked OpenGL debug callback using %s";
140 
141  if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
142  SNPRINTF(msg, format, GLEW_VERSION_4_3 ? "OpenGL 4.3" : "KHR_debug extension");
143  glEnable(GL_DEBUG_OUTPUT);
144  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
145  glDebugMessageCallback((GLDEBUGPROC)debug_callback, nullptr);
146  glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
147  glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION,
148  GL_DEBUG_TYPE_MARKER,
149  0,
150  GL_DEBUG_SEVERITY_NOTIFICATION,
151  -1,
152  msg);
153  }
154  else if (GLEW_ARB_debug_output) {
155  SNPRINTF(msg, format, "ARB_debug_output");
156  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
157  glDebugMessageCallbackARB((GLDEBUGPROCARB)debug_callback, nullptr);
158  glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
159  glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB,
160  GL_DEBUG_TYPE_OTHER_ARB,
161  0,
162  GL_DEBUG_SEVERITY_LOW_ARB,
163  -1,
164  msg);
165  }
166  else {
167  CLOG_STR_WARN(&LOG, "Failed to hook OpenGL debug callback. Use fallback debug layer.");
169  }
170 }
171 
174 /* -------------------------------------------------------------------- */
181 void check_gl_error(const char *info)
182 {
183  if (!(G.debug & G_DEBUG_GPU)) {
184  return;
185  }
186  GLenum error = glGetError();
187 
188 #define ERROR_CASE(err) \
189  case err: { \
190  char msg[256]; \
191  SNPRINTF(msg, "%s : %s", #err, info); \
192  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); \
193  break; \
194  }
195 
196  switch (error) {
197  ERROR_CASE(GL_INVALID_ENUM)
198  ERROR_CASE(GL_INVALID_VALUE)
199  ERROR_CASE(GL_INVALID_OPERATION)
200  ERROR_CASE(GL_INVALID_FRAMEBUFFER_OPERATION)
201  ERROR_CASE(GL_OUT_OF_MEMORY)
202  ERROR_CASE(GL_STACK_UNDERFLOW)
203  ERROR_CASE(GL_STACK_OVERFLOW)
204  case GL_NO_ERROR:
205  break;
206  default:
207  char msg[256];
208  SNPRINTF(msg, "Unknown GL error: %x : %s", error, info);
209  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
210  break;
211  }
212 }
213 
214 void check_gl_resources(const char *info)
215 {
216  if (!(G.debug & G_DEBUG_GPU) || GPU_bgl_get()) {
217  return;
218  }
219 
220  GLContext *ctx = GLContext::get();
221  ShaderInterface *interface = ctx->shader->interface;
222  /* NOTE: This only check binding. To be valid, the bound ubo needs to
223  * be big enough to feed the data range the shader awaits. */
224  uint16_t ubo_needed = interface->enabled_ubo_mask_;
225  ubo_needed &= ~ctx->bound_ubo_slots;
226  /* NOTE: This only check binding. To be valid, the bound texture needs to
227  * be the same format/target the shader expects. */
228  uint64_t tex_needed = interface->enabled_tex_mask_;
229  tex_needed &= ~GLContext::state_manager_active_get()->bound_texture_slots();
230  /* NOTE: This only check binding. To be valid, the bound image needs to
231  * be the same format/target the shader expects. */
232  uint8_t ima_needed = interface->enabled_ima_mask_;
233  ima_needed &= ~GLContext::state_manager_active_get()->bound_image_slots();
234 
235  if (ubo_needed == 0 && tex_needed == 0 && ima_needed == 0) {
236  return;
237  }
238 
239  for (int i = 0; ubo_needed != 0; i++, ubo_needed >>= 1) {
240  if ((ubo_needed & 1) != 0) {
241  const ShaderInput *ubo_input = interface->ubo_get(i);
242  const char *ubo_name = interface->input_name_get(ubo_input);
243  const char *sh_name = ctx->shader->name_get();
244  char msg[256];
245  SNPRINTF(msg, "Missing UBO bind at slot %d : %s > %s : %s", i, sh_name, ubo_name, info);
246  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
247  }
248  }
249 
250  for (int i = 0; tex_needed != 0; i++, tex_needed >>= 1) {
251  if ((tex_needed & 1) != 0) {
252  /* FIXME: texture_get might return an image input instead. */
253  const ShaderInput *tex_input = interface->texture_get(i);
254  const char *tex_name = interface->input_name_get(tex_input);
255  const char *sh_name = ctx->shader->name_get();
256  char msg[256];
257  SNPRINTF(msg, "Missing Texture bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info);
258  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
259  }
260  }
261 
262  for (int i = 0; ima_needed != 0; i++, ima_needed >>= 1) {
263  if ((ima_needed & 1) != 0) {
264  /* FIXME: texture_get might return a texture input instead. */
265  const ShaderInput *tex_input = interface->texture_get(i);
266  const char *tex_name = interface->input_name_get(tex_input);
267  const char *sh_name = ctx->shader->name_get();
268  char msg[256];
269  SNPRINTF(msg, "Missing Image bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info);
270  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr);
271  }
272  }
273 }
274 
275 void raise_gl_error(const char *info)
276 {
277  debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, info, nullptr);
278 }
279 
282 /* -------------------------------------------------------------------- */
289 static const char *to_str_prefix(GLenum type)
290 {
291  switch (type) {
292  case GL_FRAGMENT_SHADER:
293  case GL_GEOMETRY_SHADER:
294  case GL_VERTEX_SHADER:
295  case GL_SHADER:
296  case GL_PROGRAM:
297  return "SHD-";
298  case GL_SAMPLER:
299  return "SAM-";
300  case GL_TEXTURE:
301  return "TEX-";
302  case GL_FRAMEBUFFER:
303  return "FBO-";
304  case GL_VERTEX_ARRAY:
305  return "VAO-";
306  case GL_UNIFORM_BUFFER:
307  return "UBO-";
308  case GL_BUFFER:
309  return "BUF-";
310  default:
311  return "";
312  }
313 }
314 static const char *to_str_suffix(GLenum type)
315 {
316  switch (type) {
317  case GL_FRAGMENT_SHADER:
318  return "-Frag";
319  case GL_GEOMETRY_SHADER:
320  return "-Geom";
321  case GL_VERTEX_SHADER:
322  return "-Vert";
323  default:
324  return "";
325  }
326 }
327 
328 void object_label(GLenum type, GLuint object, const char *name)
329 {
330  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
331  char label[64];
332  SNPRINTF(label, "%s%s%s", to_str_prefix(type), name, to_str_suffix(type));
333  /* Small convenience for caller. */
334  switch (type) {
335  case GL_FRAGMENT_SHADER:
336  case GL_GEOMETRY_SHADER:
337  case GL_VERTEX_SHADER:
338  case GL_COMPUTE_SHADER:
339  type = GL_SHADER;
340  break;
341  case GL_UNIFORM_BUFFER:
342  case GL_SHADER_STORAGE_BUFFER:
343  case GL_ARRAY_BUFFER:
344  case GL_ELEMENT_ARRAY_BUFFER:
345  type = GL_BUFFER;
346  break;
347  default:
348  break;
349  }
350  glObjectLabel(type, object, -1, label);
351  }
352 }
353 
356 } // namespace blender::gpu::debug
357 
358 namespace blender::gpu {
359 
360 /* -------------------------------------------------------------------- */
366 void GLContext::debug_group_begin(const char *name, int index)
367 {
368  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
369  /* Add 10 to avoid collision with other indices from other possible callback layers. */
370  index += 10;
371  glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, index, -1, name);
372  }
373 }
374 
376 {
377  if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) {
378  glPopDebugGroup();
379  }
380 }
381 
384 } // namespace blender::gpu
@ G_DEBUG_GPU
Definition: BKE_global.h:193
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:485
void BLI_system_backtrace(FILE *fp)
Definition: system.c:62
#define STRPREFIX(a, b)
#define UNUSED(x)
#define ELEM(...)
CLG_Severity
Definition: CLG_log.h:85
@ CLG_SEVERITY_INFO
Definition: CLG_log.h:86
@ CLG_SEVERITY_WARN
Definition: CLG_log.h:87
@ CLG_SEVERITY_ERROR
Definition: CLG_log.h:88
@ CLG_FLAG_USE
Definition: CLG_log.h:82
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:148
#define CLOG_STR_WARN(clg_ref, str)
Definition: CLG_log.h:195
int CLG_color_support_get(CLG_LogRef *clg_ref)
Definition: clog.c:787
bool GPU_debug_group_match(const char *ref)
Definition: gpu_debug.cc:60
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
Definition: gpu_debug.cc:42
#define GPU_DEBUG_SHADER_COMPILATION_GROUP
Definition: GPU_debug.h:18
#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:44
@ GPU_OS_ANY
Definition: GPU_platform.h:40
@ GPU_DEVICE_NVIDIA
Definition: GPU_platform.h:24
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
bool GPU_bgl_get(void)
Definition: gpu_state.cc:360
void debug_group_begin(const char *name, int index) override
Definition: gl_debug.cc:366
void debug_group_end() override
Definition: gl_debug.cc:375
static GLContext * get()
Definition: gl_context.hh:117
const char *const name_get() const
const char * label
#define ERROR_CASE(err)
#define APIENTRY
Definition: gl_debug.cc:51
#define TRIM_NVIDIA_BUFFER_INFO
Definition: gl_debug.cc:34
#define TRIM_SHADER_STATS_INFO
Definition: gl_debug.cc:36
static CLG_LogRef LOG
Definition: gl_debug.cc:31
format
Definition: logImageCore.h:38
#define G(x, y, z)
static void error(const char *str)
Definition: meshlaplacian.c:51
void init_gl_callbacks()
Definition: gl_debug.cc:134
void check_gl_resources(const char *info)
Definition: gl_debug.cc:214
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:54
void raise_gl_error(const char *info)
Definition: gl_debug.cc:275
static const char * to_str_prefix(GLenum type)
Definition: gl_debug.cc:289
void check_gl_error(const char *info)
Definition: gl_debug.cc:181
static const char * to_str_suffix(GLenum type)
Definition: gl_debug.cc:314
void object_label(GLenum type, GLuint object, const char *name)
Definition: gl_debug.cc:328
CLG_LogRef LOG
Definition: mtl_debug.mm:28
T length(const vec_base< T, Size > &a)
static void tex_input(float *out, int num, bNodeStack *in, TexParams *params, short thread)
unsigned short uint16_t
Definition: stdint.h:79
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
CLG_LogType * type
Definition: CLG_log.h:106
enum CLG_LogFlag flag
Definition: CLG_log.h:101
int level
Definition: CLG_log.h:100