diff options
Diffstat (limited to 'source/blender/gpu/opengl/gl_debug.cc')
-rw-r--r-- | source/blender/gpu/opengl/gl_debug.cc | 130 |
1 files changed, 102 insertions, 28 deletions
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc index db99e90d0ec..4e45ff11fc7 100644 --- a/source/blender/gpu/opengl/gl_debug.cc +++ b/source/blender/gpu/opengl/gl_debug.cc @@ -30,8 +30,11 @@ #include "BKE_global.h" +#include "GPU_debug.h" #include "GPU_platform.h" +#include "CLG_log.h" + #include "glew-mx.h" #include "gl_context.hh" @@ -41,8 +44,12 @@ #include <stdio.h> +static CLG_LogRef LOG = {"gpu.debug"}; + /* Avoid too much NVidia buffer info in the output log. */ #define TRIM_NVIDIA_BUFFER_INFO 1 +/* Avoid unneeded shader statistics. */ +#define TRIM_SHADER_STATS_INFO 1 namespace blender::gpu::debug { @@ -60,8 +67,6 @@ namespace blender::gpu::debug { # define APIENTRY #endif -#define VERBOSE 1 - static void APIENTRY debug_callback(GLenum UNUSED(source), GLenum type, GLuint UNUSED(id), @@ -70,42 +75,65 @@ static void APIENTRY debug_callback(GLenum UNUSED(source), const GLchar *message, const GLvoid *UNUSED(userParm)) { - const char format[] = "GPUDebug: %s%s\033[0m\n"; + if (ELEM(type, GL_DEBUG_TYPE_PUSH_GROUP, GL_DEBUG_TYPE_POP_GROUP)) { + /* The debug layer will emit a message each time a debug group is pushed or popped. + * We use that for easy command grouping inside frame analyzer tools. */ + return; + } if (TRIM_NVIDIA_BUFFER_INFO && GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) && - STREQLEN("Buffer detailed info", message, 20)) { - /** Supress buffer infos flooding the output. */ + STRPREFIX(message, "Buffer detailed info")) { + /** Suppress buffer infos flooding the output. */ return; } + if (TRIM_SHADER_STATS_INFO && STRPREFIX(message, "Shader Stats")) { + /** Suppress buffer infos flooding the output. */ + return; + } + + const bool use_color = CLG_color_support_get(&LOG); + if (ELEM(severity, GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_NOTIFICATION)) { - if (VERBOSE) { - fprintf(stderr, format, "\033[2m", message); + if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= CLG_SEVERITY_INFO))) { + const char *format = use_color ? "\033[2m%s\033[0m" : "%s"; + CLG_logf(LOG.type, CLG_SEVERITY_INFO, "Notification", "", format, message); } } else { + char debug_groups[512] = ""; + GPU_debug_get_groups_names(sizeof(debug_groups), debug_groups); + CLG_Severity clog_severity; + switch (type) { case GL_DEBUG_TYPE_ERROR: case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - fprintf(stderr, format, "\033[31;1mError\033[39m: ", message); + clog_severity = CLG_SEVERITY_ERROR; break; case GL_DEBUG_TYPE_PORTABILITY: case GL_DEBUG_TYPE_PERFORMANCE: case GL_DEBUG_TYPE_OTHER: case GL_DEBUG_TYPE_MARKER: /* KHR has this, ARB does not */ default: - fprintf(stderr, format, "\033[33;1mWarning\033[39m: ", message); + clog_severity = CLG_SEVERITY_WARN; break; } - if (VERBOSE && severity == GL_DEBUG_SEVERITY_HIGH) { - /* Focus on error message. */ - fprintf(stderr, "\033[2m"); - BLI_system_backtrace(stderr); - fprintf(stderr, "\033[0m\n"); - fflush(stderr); + if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= clog_severity))) { + CLG_logf(LOG.type, clog_severity, debug_groups, "", "%s", message); + if (severity == GL_DEBUG_SEVERITY_HIGH) { + /* Focus on error message. */ + if (use_color) { + fprintf(stderr, "\033[2m"); + } + BLI_system_backtrace(stderr); + if (use_color) { + fprintf(stderr, "\033[0m\n"); + } + fflush(stderr); + } } } } @@ -113,8 +141,10 @@ static void APIENTRY debug_callback(GLenum UNUSED(source), #undef APIENTRY /* This function needs to be called once per context. */ -void init_gl_callbacks(void) +void init_gl_callbacks() { + CLOG_ENSURE(&LOG); + char msg[256] = ""; const char format[] = "Successfully hooked OpenGL debug callback using %s"; @@ -122,8 +152,8 @@ void init_gl_callbacks(void) SNPRINTF(msg, format, GLEW_VERSION_4_3 ? "OpenGL 4.3" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)debug_callback, NULL); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + glDebugMessageCallback((GLDEBUGPROC)debug_callback, nullptr); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, @@ -134,8 +164,8 @@ void init_gl_callbacks(void) else if (GLEW_ARB_debug_output) { SNPRINTF(msg, format, "ARB_debug_output"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallbackARB((GLDEBUGPROCARB)debug_callback, NULL); - glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + glDebugMessageCallbackARB((GLDEBUGPROCARB)debug_callback, nullptr); + glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, @@ -144,7 +174,7 @@ void init_gl_callbacks(void) msg); } else { - fprintf(stderr, "GPUDebug: Failed to hook OpenGL debug callback. Use fallback debug layer.\n"); + CLOG_STR_WARN(&LOG, "Failed to hook OpenGL debug callback. Use fallback debug layer."); init_debug_layer(); } } @@ -183,14 +213,14 @@ void check_gl_error(const char *info) default: char msg[256]; SNPRINTF(msg, "Unknown GL error: %x : %s", error, info); - debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, NULL); + debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); break; } } void check_gl_resources(const char *info) { - if (!(G.debug & G_DEBUG_GPU)) { + if (!(G.debug & G_DEBUG_GPU) || GPU_bgl_get()) { return; } @@ -200,13 +230,16 @@ void check_gl_resources(const char *info) * be big enough to feed the data range the shader awaits. */ uint16_t ubo_needed = interface->enabled_ubo_mask_; ubo_needed &= ~ctx->bound_ubo_slots; - /* NOTE: This only check binding. To be valid, the bound texture needs to * be the same format/target the shader expects. */ uint64_t tex_needed = interface->enabled_tex_mask_; tex_needed &= ~GLContext::state_manager_active_get()->bound_texture_slots(); + /* NOTE: This only check binding. To be valid, the bound image needs to + * be the same format/target the shader expects. */ + uint8_t ima_needed = interface->enabled_ima_mask_; + ima_needed &= ~GLContext::state_manager_active_get()->bound_image_slots(); - if (ubo_needed == 0 && tex_needed == 0) { + if (ubo_needed == 0 && tex_needed == 0 && ima_needed == 0) { return; } @@ -217,25 +250,38 @@ void check_gl_resources(const char *info) const char *sh_name = ctx->shader->name_get(); char msg[256]; SNPRINTF(msg, "Missing UBO bind at slot %d : %s > %s : %s", i, sh_name, ubo_name, info); - debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, NULL); + debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); } } for (int i = 0; tex_needed != 0; i++, tex_needed >>= 1) { if ((tex_needed & 1) != 0) { + /* FIXME: texture_get might return an image input instead. */ const ShaderInput *tex_input = interface->texture_get(i); const char *tex_name = interface->input_name_get(tex_input); const char *sh_name = ctx->shader->name_get(); char msg[256]; SNPRINTF(msg, "Missing Texture bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info); - debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, NULL); + debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); + } + } + + for (int i = 0; ima_needed != 0; i++, ima_needed >>= 1) { + if ((ima_needed & 1) != 0) { + /* FIXME: texture_get might return a texture input instead. */ + const ShaderInput *tex_input = interface->texture_get(i); + const char *tex_name = interface->input_name_get(tex_input); + const char *sh_name = ctx->shader->name_get(); + char msg[256]; + SNPRINTF(msg, "Missing Image bind at slot %d : %s > %s : %s", i, sh_name, tex_name, info); + debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); } } } void raise_gl_error(const char *info) { - debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, info, NULL); + debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, info, nullptr); } /** \} */ @@ -305,3 +351,31 @@ void object_label(GLenum type, GLuint object, const char *name) /** \} */ } // namespace blender::gpu::debug + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Debug Groups + * + * Useful for debugging through render-doc. This makes all the API calls grouped into "passes". + * \{ */ + +void GLContext::debug_group_begin(const char *name, int index) +{ + if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + /* Add 10 to avoid conlision with other indices from other possible callback layers. */ + index += 10; + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, index, -1, name); + } +} + +void GLContext::debug_group_end() +{ + if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + glPopDebugGroup(); + } +} + +/** \} */ + +} // namespace blender::gpu |