1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Mesa 3-D graphics library 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Copyright (C) 1999-2016 Brian Paul, et al All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 12bf215546Sopenharmony_ci * 13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <stdarg.h> 27bf215546Sopenharmony_ci#include <stdio.h> 28bf215546Sopenharmony_ci#include "context.h" 29bf215546Sopenharmony_ci#include "debug_output.h" 30bf215546Sopenharmony_ci#include "enums.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "hash.h" 33bf215546Sopenharmony_ci#include "mtypes.h" 34bf215546Sopenharmony_ci#include "version.h" 35bf215546Sopenharmony_ci#include "util/hash_table.h" 36bf215546Sopenharmony_ci#include "util/list.h" 37bf215546Sopenharmony_ci#include "util/u_memory.h" 38bf215546Sopenharmony_ci#include "api_exec_decl.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "pipe/p_context.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_cistatic GLuint PrevDynamicID = 0; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci/** 46bf215546Sopenharmony_ci * A namespace element. 47bf215546Sopenharmony_ci */ 48bf215546Sopenharmony_cistruct gl_debug_element 49bf215546Sopenharmony_ci{ 50bf215546Sopenharmony_ci struct list_head link; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci GLuint ID; 53bf215546Sopenharmony_ci /* at which severity levels (mesa_debug_severity) is the message enabled */ 54bf215546Sopenharmony_ci GLbitfield State; 55bf215546Sopenharmony_ci}; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_cistruct gl_debug_namespace 59bf215546Sopenharmony_ci{ 60bf215546Sopenharmony_ci struct list_head Elements; 61bf215546Sopenharmony_ci GLbitfield DefaultState; 62bf215546Sopenharmony_ci}; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistruct gl_debug_group { 66bf215546Sopenharmony_ci struct gl_debug_namespace Namespaces[MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT]; 67bf215546Sopenharmony_ci}; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci/** 71bf215546Sopenharmony_ci * An error, warning, or other piece of debug information for an application 72bf215546Sopenharmony_ci * to consume via GL_ARB_debug_output/GL_KHR_debug. 73bf215546Sopenharmony_ci */ 74bf215546Sopenharmony_cistruct gl_debug_message 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci enum mesa_debug_source source; 77bf215546Sopenharmony_ci enum mesa_debug_type type; 78bf215546Sopenharmony_ci GLuint id; 79bf215546Sopenharmony_ci enum mesa_debug_severity severity; 80bf215546Sopenharmony_ci /* length as given by the user - if message was explicitly null terminated, 81bf215546Sopenharmony_ci * length can be negative */ 82bf215546Sopenharmony_ci GLsizei length; 83bf215546Sopenharmony_ci GLcharARB *message; 84bf215546Sopenharmony_ci}; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci/** 88bf215546Sopenharmony_ci * Debug message log. It works like a ring buffer. 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_cistruct gl_debug_log { 91bf215546Sopenharmony_ci struct gl_debug_message Messages[MAX_DEBUG_LOGGED_MESSAGES]; 92bf215546Sopenharmony_ci GLint NextMessage; 93bf215546Sopenharmony_ci GLint NumMessages; 94bf215546Sopenharmony_ci}; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_cistruct gl_debug_state 98bf215546Sopenharmony_ci{ 99bf215546Sopenharmony_ci GLDEBUGPROC Callback; 100bf215546Sopenharmony_ci const void *CallbackData; 101bf215546Sopenharmony_ci GLboolean SyncOutput; 102bf215546Sopenharmony_ci GLboolean DebugOutput; 103bf215546Sopenharmony_ci GLboolean LogToStderr; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci struct gl_debug_group *Groups[MAX_DEBUG_GROUP_STACK_DEPTH]; 106bf215546Sopenharmony_ci struct gl_debug_message GroupMessages[MAX_DEBUG_GROUP_STACK_DEPTH]; 107bf215546Sopenharmony_ci GLint CurrentGroup; // GroupStackDepth - 1 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci struct gl_debug_log Log; 110bf215546Sopenharmony_ci}; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_cistatic char out_of_memory[] = "Debugging error: out of memory"; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic const GLenum debug_source_enums[] = { 116bf215546Sopenharmony_ci GL_DEBUG_SOURCE_API, 117bf215546Sopenharmony_ci GL_DEBUG_SOURCE_WINDOW_SYSTEM, 118bf215546Sopenharmony_ci GL_DEBUG_SOURCE_SHADER_COMPILER, 119bf215546Sopenharmony_ci GL_DEBUG_SOURCE_THIRD_PARTY, 120bf215546Sopenharmony_ci GL_DEBUG_SOURCE_APPLICATION, 121bf215546Sopenharmony_ci GL_DEBUG_SOURCE_OTHER, 122bf215546Sopenharmony_ci}; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic const GLenum debug_type_enums[] = { 125bf215546Sopenharmony_ci GL_DEBUG_TYPE_ERROR, 126bf215546Sopenharmony_ci GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, 127bf215546Sopenharmony_ci GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, 128bf215546Sopenharmony_ci GL_DEBUG_TYPE_PORTABILITY, 129bf215546Sopenharmony_ci GL_DEBUG_TYPE_PERFORMANCE, 130bf215546Sopenharmony_ci GL_DEBUG_TYPE_OTHER, 131bf215546Sopenharmony_ci GL_DEBUG_TYPE_MARKER, 132bf215546Sopenharmony_ci GL_DEBUG_TYPE_PUSH_GROUP, 133bf215546Sopenharmony_ci GL_DEBUG_TYPE_POP_GROUP, 134bf215546Sopenharmony_ci}; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_cistatic const GLenum debug_severity_enums[] = { 137bf215546Sopenharmony_ci GL_DEBUG_SEVERITY_LOW, 138bf215546Sopenharmony_ci GL_DEBUG_SEVERITY_MEDIUM, 139bf215546Sopenharmony_ci GL_DEBUG_SEVERITY_HIGH, 140bf215546Sopenharmony_ci GL_DEBUG_SEVERITY_NOTIFICATION, 141bf215546Sopenharmony_ci}; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_cistatic enum mesa_debug_source 145bf215546Sopenharmony_cigl_enum_to_debug_source(GLenum e) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci unsigned i; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(debug_source_enums); i++) { 150bf215546Sopenharmony_ci if (debug_source_enums[i] == e) 151bf215546Sopenharmony_ci break; 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci return i; 154bf215546Sopenharmony_ci} 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_cistatic enum mesa_debug_type 157bf215546Sopenharmony_cigl_enum_to_debug_type(GLenum e) 158bf215546Sopenharmony_ci{ 159bf215546Sopenharmony_ci unsigned i; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(debug_type_enums); i++) { 162bf215546Sopenharmony_ci if (debug_type_enums[i] == e) 163bf215546Sopenharmony_ci break; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci return i; 166bf215546Sopenharmony_ci} 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_cistatic enum mesa_debug_severity 169bf215546Sopenharmony_cigl_enum_to_debug_severity(GLenum e) 170bf215546Sopenharmony_ci{ 171bf215546Sopenharmony_ci unsigned i; 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(debug_severity_enums); i++) { 174bf215546Sopenharmony_ci if (debug_severity_enums[i] == e) 175bf215546Sopenharmony_ci break; 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci return i; 178bf215546Sopenharmony_ci} 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci/** 182bf215546Sopenharmony_ci * Handles generating a GL_ARB_debug_output message ID generated by the GL or 183bf215546Sopenharmony_ci * GLSL compiler. 184bf215546Sopenharmony_ci * 185bf215546Sopenharmony_ci * The GL API has this "ID" mechanism, where the intention is to allow a 186bf215546Sopenharmony_ci * client to filter in/out messages based on source, type, and ID. Of course, 187bf215546Sopenharmony_ci * building a giant enum list of all debug output messages that Mesa might 188bf215546Sopenharmony_ci * generate is ridiculous, so instead we have our caller pass us a pointer to 189bf215546Sopenharmony_ci * static storage where the ID should get stored. This ID will be shared 190bf215546Sopenharmony_ci * across all contexts for that message (which seems like a desirable 191bf215546Sopenharmony_ci * property, even if it's not expected by the spec), but note that it won't be 192bf215546Sopenharmony_ci * the same between executions if messages aren't generated in the same order. 193bf215546Sopenharmony_ci */ 194bf215546Sopenharmony_civoid 195bf215546Sopenharmony_ci_mesa_debug_get_id(GLuint *id) 196bf215546Sopenharmony_ci{ 197bf215546Sopenharmony_ci if (!(*id)) { 198bf215546Sopenharmony_ci /* Don't update *id if we raced with some other thread. */ 199bf215546Sopenharmony_ci p_atomic_cmpxchg(id, 0, p_atomic_inc_return(&PrevDynamicID)); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci} 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_cistatic void 204bf215546Sopenharmony_cidebug_message_clear(struct gl_debug_message *msg) 205bf215546Sopenharmony_ci{ 206bf215546Sopenharmony_ci if (msg->message != (char*)out_of_memory) 207bf215546Sopenharmony_ci free(msg->message); 208bf215546Sopenharmony_ci msg->message = NULL; 209bf215546Sopenharmony_ci msg->length = 0; 210bf215546Sopenharmony_ci} 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_cistatic void 213bf215546Sopenharmony_cidebug_message_store(struct gl_debug_message *msg, 214bf215546Sopenharmony_ci enum mesa_debug_source source, 215bf215546Sopenharmony_ci enum mesa_debug_type type, GLuint id, 216bf215546Sopenharmony_ci enum mesa_debug_severity severity, 217bf215546Sopenharmony_ci GLsizei len, const char *buf) 218bf215546Sopenharmony_ci{ 219bf215546Sopenharmony_ci GLsizei length = len; 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci assert(!msg->message && !msg->length); 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci if (length < 0) 224bf215546Sopenharmony_ci length = strlen(buf); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci msg->message = malloc(length+1); 227bf215546Sopenharmony_ci if (msg->message) { 228bf215546Sopenharmony_ci (void) strncpy(msg->message, buf, (size_t)length); 229bf215546Sopenharmony_ci msg->message[length] = '\0'; 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci msg->length = len; 232bf215546Sopenharmony_ci msg->source = source; 233bf215546Sopenharmony_ci msg->type = type; 234bf215546Sopenharmony_ci msg->id = id; 235bf215546Sopenharmony_ci msg->severity = severity; 236bf215546Sopenharmony_ci } else { 237bf215546Sopenharmony_ci static GLuint oom_msg_id = 0; 238bf215546Sopenharmony_ci _mesa_debug_get_id(&oom_msg_id); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci /* malloc failed! */ 241bf215546Sopenharmony_ci msg->message = out_of_memory; 242bf215546Sopenharmony_ci msg->length = -1; 243bf215546Sopenharmony_ci msg->source = MESA_DEBUG_SOURCE_OTHER; 244bf215546Sopenharmony_ci msg->type = MESA_DEBUG_TYPE_ERROR; 245bf215546Sopenharmony_ci msg->id = oom_msg_id; 246bf215546Sopenharmony_ci msg->severity = MESA_DEBUG_SEVERITY_HIGH; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci} 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_cistatic void 251bf215546Sopenharmony_cidebug_namespace_init(struct gl_debug_namespace *ns) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci list_inithead(&ns->Elements); 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci /* Enable all the messages with severity HIGH or MEDIUM by default */ 256bf215546Sopenharmony_ci ns->DefaultState = (1 << MESA_DEBUG_SEVERITY_MEDIUM ) | 257bf215546Sopenharmony_ci (1 << MESA_DEBUG_SEVERITY_HIGH) | 258bf215546Sopenharmony_ci (1 << MESA_DEBUG_SEVERITY_NOTIFICATION); 259bf215546Sopenharmony_ci} 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_cistatic void 262bf215546Sopenharmony_cidebug_namespace_clear(struct gl_debug_namespace *ns) 263bf215546Sopenharmony_ci{ 264bf215546Sopenharmony_ci list_for_each_entry_safe(struct gl_debug_element, elem, &ns->Elements, link) 265bf215546Sopenharmony_ci free(elem); 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_cistatic bool 269bf215546Sopenharmony_cidebug_namespace_copy(struct gl_debug_namespace *dst, 270bf215546Sopenharmony_ci const struct gl_debug_namespace *src) 271bf215546Sopenharmony_ci{ 272bf215546Sopenharmony_ci dst->DefaultState = src->DefaultState; 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci list_inithead(&dst->Elements); 275bf215546Sopenharmony_ci list_for_each_entry(struct gl_debug_element, elem, &src->Elements, link) { 276bf215546Sopenharmony_ci struct gl_debug_element *copy; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci copy = malloc(sizeof(*copy)); 279bf215546Sopenharmony_ci if (!copy) { 280bf215546Sopenharmony_ci debug_namespace_clear(dst); 281bf215546Sopenharmony_ci return false; 282bf215546Sopenharmony_ci } 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci copy->ID = elem->ID; 285bf215546Sopenharmony_ci copy->State = elem->State; 286bf215546Sopenharmony_ci list_addtail(©->link, &dst->Elements); 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci return true; 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci/** 293bf215546Sopenharmony_ci * Set the state of \p id in the namespace. 294bf215546Sopenharmony_ci */ 295bf215546Sopenharmony_cistatic bool 296bf215546Sopenharmony_cidebug_namespace_set(struct gl_debug_namespace *ns, 297bf215546Sopenharmony_ci GLuint id, bool enabled) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci const uint32_t state = (enabled) ? 300bf215546Sopenharmony_ci ((1 << MESA_DEBUG_SEVERITY_COUNT) - 1) : 0; 301bf215546Sopenharmony_ci struct gl_debug_element *elem = NULL; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci /* find the element */ 304bf215546Sopenharmony_ci list_for_each_entry(struct gl_debug_element, tmp, &ns->Elements, link) { 305bf215546Sopenharmony_ci if (tmp->ID == id) { 306bf215546Sopenharmony_ci elem = tmp; 307bf215546Sopenharmony_ci break; 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci /* we do not need the element if it has the default state */ 312bf215546Sopenharmony_ci if (ns->DefaultState == state) { 313bf215546Sopenharmony_ci if (elem) { 314bf215546Sopenharmony_ci list_del(&elem->link); 315bf215546Sopenharmony_ci free(elem); 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci return true; 318bf215546Sopenharmony_ci } 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci if (!elem) { 321bf215546Sopenharmony_ci elem = malloc(sizeof(*elem)); 322bf215546Sopenharmony_ci if (!elem) 323bf215546Sopenharmony_ci return false; 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci elem->ID = id; 326bf215546Sopenharmony_ci list_addtail(&elem->link, &ns->Elements); 327bf215546Sopenharmony_ci } 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci elem->State = state; 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci return true; 332bf215546Sopenharmony_ci} 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci/** 335bf215546Sopenharmony_ci * Set the default state of the namespace for \p severity. When \p severity 336bf215546Sopenharmony_ci * is MESA_DEBUG_SEVERITY_COUNT, the default values for all severities are 337bf215546Sopenharmony_ci * updated. 338bf215546Sopenharmony_ci */ 339bf215546Sopenharmony_cistatic void 340bf215546Sopenharmony_cidebug_namespace_set_all(struct gl_debug_namespace *ns, 341bf215546Sopenharmony_ci enum mesa_debug_severity severity, 342bf215546Sopenharmony_ci bool enabled) 343bf215546Sopenharmony_ci{ 344bf215546Sopenharmony_ci uint32_t mask, val; 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci /* set all elements to the same state */ 347bf215546Sopenharmony_ci if (severity == MESA_DEBUG_SEVERITY_COUNT) { 348bf215546Sopenharmony_ci ns->DefaultState = (enabled) ? ((1 << severity) - 1) : 0; 349bf215546Sopenharmony_ci debug_namespace_clear(ns); 350bf215546Sopenharmony_ci list_inithead(&ns->Elements); 351bf215546Sopenharmony_ci return; 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci mask = 1 << severity; 355bf215546Sopenharmony_ci val = (enabled) ? mask : 0; 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci ns->DefaultState = (ns->DefaultState & ~mask) | val; 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci list_for_each_entry_safe(struct gl_debug_element, elem, &ns->Elements, 360bf215546Sopenharmony_ci link) { 361bf215546Sopenharmony_ci elem->State = (elem->State & ~mask) | val; 362bf215546Sopenharmony_ci if (elem->State == ns->DefaultState) { 363bf215546Sopenharmony_ci list_del(&elem->link); 364bf215546Sopenharmony_ci free(elem); 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci} 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci/** 370bf215546Sopenharmony_ci * Get the state of \p id in the namespace. 371bf215546Sopenharmony_ci */ 372bf215546Sopenharmony_cistatic bool 373bf215546Sopenharmony_cidebug_namespace_get(const struct gl_debug_namespace *ns, GLuint id, 374bf215546Sopenharmony_ci enum mesa_debug_severity severity) 375bf215546Sopenharmony_ci{ 376bf215546Sopenharmony_ci uint32_t state; 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci state = ns->DefaultState; 379bf215546Sopenharmony_ci list_for_each_entry(struct gl_debug_element, elem, &ns->Elements, link) { 380bf215546Sopenharmony_ci if (elem->ID == id) { 381bf215546Sopenharmony_ci state = elem->State; 382bf215546Sopenharmony_ci break; 383bf215546Sopenharmony_ci } 384bf215546Sopenharmony_ci } 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci return (state & (1 << severity)); 387bf215546Sopenharmony_ci} 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci/** 390bf215546Sopenharmony_ci * Allocate and initialize context debug state. 391bf215546Sopenharmony_ci */ 392bf215546Sopenharmony_cistatic struct gl_debug_state * 393bf215546Sopenharmony_cidebug_create(void) 394bf215546Sopenharmony_ci{ 395bf215546Sopenharmony_ci struct gl_debug_state *debug; 396bf215546Sopenharmony_ci int s, t; 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci debug = CALLOC_STRUCT(gl_debug_state); 399bf215546Sopenharmony_ci if (!debug) 400bf215546Sopenharmony_ci return NULL; 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci debug->Groups[0] = malloc(sizeof(*debug->Groups[0])); 403bf215546Sopenharmony_ci if (!debug->Groups[0]) { 404bf215546Sopenharmony_ci free(debug); 405bf215546Sopenharmony_ci return NULL; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci /* Initialize state for filtering known debug messages. */ 409bf215546Sopenharmony_ci for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) { 410bf215546Sopenharmony_ci for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) 411bf215546Sopenharmony_ci debug_namespace_init(&debug->Groups[0]->Namespaces[s][t]); 412bf215546Sopenharmony_ci } 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci return debug; 415bf215546Sopenharmony_ci} 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci/** 418bf215546Sopenharmony_ci * Return true if the top debug group points to the group below it. 419bf215546Sopenharmony_ci */ 420bf215546Sopenharmony_cistatic bool 421bf215546Sopenharmony_cidebug_is_group_read_only(const struct gl_debug_state *debug) 422bf215546Sopenharmony_ci{ 423bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 424bf215546Sopenharmony_ci return (gstack > 0 && debug->Groups[gstack] == debug->Groups[gstack - 1]); 425bf215546Sopenharmony_ci} 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci/** 428bf215546Sopenharmony_ci * Make the top debug group writable. 429bf215546Sopenharmony_ci */ 430bf215546Sopenharmony_cistatic bool 431bf215546Sopenharmony_cidebug_make_group_writable(struct gl_debug_state *debug) 432bf215546Sopenharmony_ci{ 433bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 434bf215546Sopenharmony_ci const struct gl_debug_group *src = debug->Groups[gstack]; 435bf215546Sopenharmony_ci struct gl_debug_group *dst; 436bf215546Sopenharmony_ci int s, t; 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci if (!debug_is_group_read_only(debug)) 439bf215546Sopenharmony_ci return true; 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci dst = malloc(sizeof(*dst)); 442bf215546Sopenharmony_ci if (!dst) 443bf215546Sopenharmony_ci return false; 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) { 446bf215546Sopenharmony_ci for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) { 447bf215546Sopenharmony_ci if (!debug_namespace_copy(&dst->Namespaces[s][t], 448bf215546Sopenharmony_ci &src->Namespaces[s][t])) { 449bf215546Sopenharmony_ci /* error path! */ 450bf215546Sopenharmony_ci for (t = t - 1; t >= 0; t--) 451bf215546Sopenharmony_ci debug_namespace_clear(&dst->Namespaces[s][t]); 452bf215546Sopenharmony_ci for (s = s - 1; s >= 0; s--) { 453bf215546Sopenharmony_ci for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) 454bf215546Sopenharmony_ci debug_namespace_clear(&dst->Namespaces[s][t]); 455bf215546Sopenharmony_ci } 456bf215546Sopenharmony_ci free(dst); 457bf215546Sopenharmony_ci return false; 458bf215546Sopenharmony_ci } 459bf215546Sopenharmony_ci } 460bf215546Sopenharmony_ci } 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci debug->Groups[gstack] = dst; 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci return true; 465bf215546Sopenharmony_ci} 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_ci/** 468bf215546Sopenharmony_ci * Free the top debug group. 469bf215546Sopenharmony_ci */ 470bf215546Sopenharmony_cistatic void 471bf215546Sopenharmony_cidebug_clear_group(struct gl_debug_state *debug) 472bf215546Sopenharmony_ci{ 473bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci if (!debug_is_group_read_only(debug)) { 476bf215546Sopenharmony_ci struct gl_debug_group *grp = debug->Groups[gstack]; 477bf215546Sopenharmony_ci int s, t; 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) { 480bf215546Sopenharmony_ci for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) 481bf215546Sopenharmony_ci debug_namespace_clear(&grp->Namespaces[s][t]); 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci free(grp); 485bf215546Sopenharmony_ci } 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci debug->Groups[gstack] = NULL; 488bf215546Sopenharmony_ci} 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci/** 491bf215546Sopenharmony_ci * Delete the oldest debug messages out of the log. 492bf215546Sopenharmony_ci */ 493bf215546Sopenharmony_cistatic void 494bf215546Sopenharmony_cidebug_delete_messages(struct gl_debug_state *debug, int count) 495bf215546Sopenharmony_ci{ 496bf215546Sopenharmony_ci struct gl_debug_log *log = &debug->Log; 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci if (count > log->NumMessages) 499bf215546Sopenharmony_ci count = log->NumMessages; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci while (count--) { 502bf215546Sopenharmony_ci struct gl_debug_message *msg = &log->Messages[log->NextMessage]; 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci debug_message_clear(msg); 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci log->NumMessages--; 507bf215546Sopenharmony_ci log->NextMessage++; 508bf215546Sopenharmony_ci log->NextMessage %= MAX_DEBUG_LOGGED_MESSAGES; 509bf215546Sopenharmony_ci } 510bf215546Sopenharmony_ci} 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci/** 513bf215546Sopenharmony_ci * Loop through debug group stack tearing down states for 514bf215546Sopenharmony_ci * filtering debug messages. Then free debug output state. 515bf215546Sopenharmony_ci */ 516bf215546Sopenharmony_cistatic void 517bf215546Sopenharmony_cidebug_destroy(struct gl_debug_state *debug) 518bf215546Sopenharmony_ci{ 519bf215546Sopenharmony_ci while (debug->CurrentGroup > 0) { 520bf215546Sopenharmony_ci debug_clear_group(debug); 521bf215546Sopenharmony_ci debug->CurrentGroup--; 522bf215546Sopenharmony_ci } 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci debug_clear_group(debug); 525bf215546Sopenharmony_ci debug_delete_messages(debug, debug->Log.NumMessages); 526bf215546Sopenharmony_ci free(debug); 527bf215546Sopenharmony_ci} 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci/** 530bf215546Sopenharmony_ci * Sets the state of the given message source/type/ID tuple. 531bf215546Sopenharmony_ci */ 532bf215546Sopenharmony_cistatic void 533bf215546Sopenharmony_cidebug_set_message_enable(struct gl_debug_state *debug, 534bf215546Sopenharmony_ci enum mesa_debug_source source, 535bf215546Sopenharmony_ci enum mesa_debug_type type, 536bf215546Sopenharmony_ci GLuint id, GLboolean enabled) 537bf215546Sopenharmony_ci{ 538bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 539bf215546Sopenharmony_ci struct gl_debug_namespace *ns; 540bf215546Sopenharmony_ci 541bf215546Sopenharmony_ci debug_make_group_writable(debug); 542bf215546Sopenharmony_ci ns = &debug->Groups[gstack]->Namespaces[source][type]; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci debug_namespace_set(ns, id, enabled); 545bf215546Sopenharmony_ci} 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci/* 548bf215546Sopenharmony_ci * Set the state of all message IDs found in the given intersection of 549bf215546Sopenharmony_ci * 'source', 'type', and 'severity'. The _COUNT enum can be used for 550bf215546Sopenharmony_ci * GL_DONT_CARE (include all messages in the class). 551bf215546Sopenharmony_ci * 552bf215546Sopenharmony_ci * This requires both setting the state of all previously seen message 553bf215546Sopenharmony_ci * IDs in the hash table, and setting the default state for all 554bf215546Sopenharmony_ci * applicable combinations of source/type/severity, so that all the 555bf215546Sopenharmony_ci * yet-unknown message IDs that may be used in the future will be 556bf215546Sopenharmony_ci * impacted as if they were already known. 557bf215546Sopenharmony_ci */ 558bf215546Sopenharmony_cistatic void 559bf215546Sopenharmony_cidebug_set_message_enable_all(struct gl_debug_state *debug, 560bf215546Sopenharmony_ci enum mesa_debug_source source, 561bf215546Sopenharmony_ci enum mesa_debug_type type, 562bf215546Sopenharmony_ci enum mesa_debug_severity severity, 563bf215546Sopenharmony_ci GLboolean enabled) 564bf215546Sopenharmony_ci{ 565bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 566bf215546Sopenharmony_ci int s, t, smax, tmax; 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci if (source == MESA_DEBUG_SOURCE_COUNT) { 569bf215546Sopenharmony_ci source = 0; 570bf215546Sopenharmony_ci smax = MESA_DEBUG_SOURCE_COUNT; 571bf215546Sopenharmony_ci } else { 572bf215546Sopenharmony_ci smax = source+1; 573bf215546Sopenharmony_ci } 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_ci if (type == MESA_DEBUG_TYPE_COUNT) { 576bf215546Sopenharmony_ci type = 0; 577bf215546Sopenharmony_ci tmax = MESA_DEBUG_TYPE_COUNT; 578bf215546Sopenharmony_ci } else { 579bf215546Sopenharmony_ci tmax = type+1; 580bf215546Sopenharmony_ci } 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci debug_make_group_writable(debug); 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci for (s = source; s < smax; s++) { 585bf215546Sopenharmony_ci for (t = type; t < tmax; t++) { 586bf215546Sopenharmony_ci struct gl_debug_namespace *nspace = 587bf215546Sopenharmony_ci &debug->Groups[gstack]->Namespaces[s][t]; 588bf215546Sopenharmony_ci debug_namespace_set_all(nspace, severity, enabled); 589bf215546Sopenharmony_ci } 590bf215546Sopenharmony_ci } 591bf215546Sopenharmony_ci} 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci/** 594bf215546Sopenharmony_ci * Returns if the given message source/type/ID tuple is enabled. 595bf215546Sopenharmony_ci */ 596bf215546Sopenharmony_cibool 597bf215546Sopenharmony_ci_mesa_debug_is_message_enabled(const struct gl_debug_state *debug, 598bf215546Sopenharmony_ci enum mesa_debug_source source, 599bf215546Sopenharmony_ci enum mesa_debug_type type, 600bf215546Sopenharmony_ci GLuint id, 601bf215546Sopenharmony_ci enum mesa_debug_severity severity) 602bf215546Sopenharmony_ci{ 603bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 604bf215546Sopenharmony_ci struct gl_debug_group *grp = debug->Groups[gstack]; 605bf215546Sopenharmony_ci struct gl_debug_namespace *nspace = &grp->Namespaces[source][type]; 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci if (!debug->DebugOutput) 608bf215546Sopenharmony_ci return false; 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci return debug_namespace_get(nspace, id, severity); 611bf215546Sopenharmony_ci} 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci/** 614bf215546Sopenharmony_ci * 'buf' is not necessarily a null-terminated string. When logging, copy 615bf215546Sopenharmony_ci * 'len' characters from it, store them in a new, null-terminated string, 616bf215546Sopenharmony_ci * and remember the number of bytes used by that string, *including* 617bf215546Sopenharmony_ci * the null terminator this time. 618bf215546Sopenharmony_ci */ 619bf215546Sopenharmony_cistatic void 620bf215546Sopenharmony_cidebug_log_message(struct gl_debug_state *debug, 621bf215546Sopenharmony_ci enum mesa_debug_source source, 622bf215546Sopenharmony_ci enum mesa_debug_type type, GLuint id, 623bf215546Sopenharmony_ci enum mesa_debug_severity severity, 624bf215546Sopenharmony_ci GLsizei len, const char *buf) 625bf215546Sopenharmony_ci{ 626bf215546Sopenharmony_ci struct gl_debug_log *log = &debug->Log; 627bf215546Sopenharmony_ci GLint nextEmpty; 628bf215546Sopenharmony_ci struct gl_debug_message *emptySlot; 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci if (debug->LogToStderr) { 631bf215546Sopenharmony_ci _mesa_log("Mesa debug output: %.*s\n", len, buf); 632bf215546Sopenharmony_ci } 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci assert(len < MAX_DEBUG_MESSAGE_LENGTH); 635bf215546Sopenharmony_ci 636bf215546Sopenharmony_ci if (log->NumMessages == MAX_DEBUG_LOGGED_MESSAGES) 637bf215546Sopenharmony_ci return; 638bf215546Sopenharmony_ci 639bf215546Sopenharmony_ci nextEmpty = (log->NextMessage + log->NumMessages) 640bf215546Sopenharmony_ci % MAX_DEBUG_LOGGED_MESSAGES; 641bf215546Sopenharmony_ci emptySlot = &log->Messages[nextEmpty]; 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_ci debug_message_store(emptySlot, source, type, 644bf215546Sopenharmony_ci id, severity, len, buf); 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ci log->NumMessages++; 647bf215546Sopenharmony_ci} 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci/** 650bf215546Sopenharmony_ci * Return the oldest debug message out of the log. 651bf215546Sopenharmony_ci */ 652bf215546Sopenharmony_cistatic const struct gl_debug_message * 653bf215546Sopenharmony_cidebug_fetch_message(const struct gl_debug_state *debug) 654bf215546Sopenharmony_ci{ 655bf215546Sopenharmony_ci const struct gl_debug_log *log = &debug->Log; 656bf215546Sopenharmony_ci 657bf215546Sopenharmony_ci return (log->NumMessages) ? &log->Messages[log->NextMessage] : NULL; 658bf215546Sopenharmony_ci} 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_cistatic struct gl_debug_message * 661bf215546Sopenharmony_cidebug_get_group_message(struct gl_debug_state *debug) 662bf215546Sopenharmony_ci{ 663bf215546Sopenharmony_ci return &debug->GroupMessages[debug->CurrentGroup]; 664bf215546Sopenharmony_ci} 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_cistatic void 667bf215546Sopenharmony_cidebug_push_group(struct gl_debug_state *debug) 668bf215546Sopenharmony_ci{ 669bf215546Sopenharmony_ci const GLint gstack = debug->CurrentGroup; 670bf215546Sopenharmony_ci 671bf215546Sopenharmony_ci /* just point to the previous stack */ 672bf215546Sopenharmony_ci debug->Groups[gstack + 1] = debug->Groups[gstack]; 673bf215546Sopenharmony_ci debug->CurrentGroup++; 674bf215546Sopenharmony_ci} 675bf215546Sopenharmony_ci 676bf215546Sopenharmony_cistatic void 677bf215546Sopenharmony_cidebug_pop_group(struct gl_debug_state *debug) 678bf215546Sopenharmony_ci{ 679bf215546Sopenharmony_ci debug_clear_group(debug); 680bf215546Sopenharmony_ci debug->CurrentGroup--; 681bf215546Sopenharmony_ci} 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_ci 684bf215546Sopenharmony_ci/** 685bf215546Sopenharmony_ci * Installed as util_debug_callback when GL_DEBUG_OUTPUT is enabled. 686bf215546Sopenharmony_ci */ 687bf215546Sopenharmony_cistatic void 688bf215546Sopenharmony_ci_debug_message(void *data, 689bf215546Sopenharmony_ci unsigned *id, 690bf215546Sopenharmony_ci enum util_debug_type ptype, 691bf215546Sopenharmony_ci const char *fmt, 692bf215546Sopenharmony_ci va_list args) 693bf215546Sopenharmony_ci{ 694bf215546Sopenharmony_ci struct gl_context *ctx = data; 695bf215546Sopenharmony_ci enum mesa_debug_source source; 696bf215546Sopenharmony_ci enum mesa_debug_type type; 697bf215546Sopenharmony_ci enum mesa_debug_severity severity; 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci switch (ptype) { 700bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_OUT_OF_MEMORY: 701bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 702bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_ERROR; 703bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_MEDIUM; 704bf215546Sopenharmony_ci break; 705bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_ERROR: 706bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 707bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_ERROR; 708bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_MEDIUM; 709bf215546Sopenharmony_ci break; 710bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_SHADER_INFO: 711bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_SHADER_COMPILER; 712bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_OTHER; 713bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_NOTIFICATION; 714bf215546Sopenharmony_ci break; 715bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_PERF_INFO: 716bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 717bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_PERFORMANCE; 718bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_NOTIFICATION; 719bf215546Sopenharmony_ci break; 720bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_INFO: 721bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 722bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_OTHER; 723bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_NOTIFICATION; 724bf215546Sopenharmony_ci break; 725bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_FALLBACK: 726bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 727bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_PERFORMANCE; 728bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_NOTIFICATION; 729bf215546Sopenharmony_ci break; 730bf215546Sopenharmony_ci case UTIL_DEBUG_TYPE_CONFORMANCE: 731bf215546Sopenharmony_ci source = MESA_DEBUG_SOURCE_API; 732bf215546Sopenharmony_ci type = MESA_DEBUG_TYPE_OTHER; 733bf215546Sopenharmony_ci severity = MESA_DEBUG_SEVERITY_NOTIFICATION; 734bf215546Sopenharmony_ci break; 735bf215546Sopenharmony_ci default: 736bf215546Sopenharmony_ci unreachable("invalid debug type"); 737bf215546Sopenharmony_ci } 738bf215546Sopenharmony_ci _mesa_gl_vdebugf(ctx, id, source, type, severity, fmt, args); 739bf215546Sopenharmony_ci} 740bf215546Sopenharmony_ci 741bf215546Sopenharmony_civoid 742bf215546Sopenharmony_ci_mesa_update_debug_callback(struct gl_context *ctx) 743bf215546Sopenharmony_ci{ 744bf215546Sopenharmony_ci struct pipe_context *pipe = ctx->pipe; 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci if (!pipe->set_debug_callback) 747bf215546Sopenharmony_ci return; 748bf215546Sopenharmony_ci 749bf215546Sopenharmony_ci if (_mesa_get_debug_state_int(ctx, GL_DEBUG_OUTPUT)) { 750bf215546Sopenharmony_ci struct util_debug_callback cb; 751bf215546Sopenharmony_ci memset(&cb, 0, sizeof(cb)); 752bf215546Sopenharmony_ci cb.async = !_mesa_get_debug_state_int(ctx, GL_DEBUG_OUTPUT_SYNCHRONOUS); 753bf215546Sopenharmony_ci cb.debug_message = _debug_message; 754bf215546Sopenharmony_ci cb.data = ctx; 755bf215546Sopenharmony_ci pipe->set_debug_callback(pipe, &cb); 756bf215546Sopenharmony_ci } else { 757bf215546Sopenharmony_ci pipe->set_debug_callback(pipe, NULL); 758bf215546Sopenharmony_ci } 759bf215546Sopenharmony_ci} 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci/** 762bf215546Sopenharmony_ci * Lock and return debug state for the context. The debug state will be 763bf215546Sopenharmony_ci * allocated and initialized upon the first call. When NULL is returned, the 764bf215546Sopenharmony_ci * debug state is not locked. 765bf215546Sopenharmony_ci */ 766bf215546Sopenharmony_cistatic struct gl_debug_state * 767bf215546Sopenharmony_ci_mesa_lock_debug_state(struct gl_context *ctx) 768bf215546Sopenharmony_ci{ 769bf215546Sopenharmony_ci simple_mtx_lock(&ctx->DebugMutex); 770bf215546Sopenharmony_ci 771bf215546Sopenharmony_ci if (!ctx->Debug) { 772bf215546Sopenharmony_ci ctx->Debug = debug_create(); 773bf215546Sopenharmony_ci if (!ctx->Debug) { 774bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(cur); 775bf215546Sopenharmony_ci simple_mtx_unlock(&ctx->DebugMutex); 776bf215546Sopenharmony_ci 777bf215546Sopenharmony_ci /* 778bf215546Sopenharmony_ci * This function may be called from other threads. When that is the 779bf215546Sopenharmony_ci * case, we cannot record this OOM error. 780bf215546Sopenharmony_ci */ 781bf215546Sopenharmony_ci if (ctx == cur) 782bf215546Sopenharmony_ci _mesa_error(ctx, GL_OUT_OF_MEMORY, "allocating debug state"); 783bf215546Sopenharmony_ci 784bf215546Sopenharmony_ci return NULL; 785bf215546Sopenharmony_ci } 786bf215546Sopenharmony_ci } 787bf215546Sopenharmony_ci 788bf215546Sopenharmony_ci return ctx->Debug; 789bf215546Sopenharmony_ci} 790bf215546Sopenharmony_ci 791bf215546Sopenharmony_cistatic void 792bf215546Sopenharmony_ci_mesa_unlock_debug_state(struct gl_context *ctx) 793bf215546Sopenharmony_ci{ 794bf215546Sopenharmony_ci simple_mtx_unlock(&ctx->DebugMutex); 795bf215546Sopenharmony_ci} 796bf215546Sopenharmony_ci 797bf215546Sopenharmony_ci/** 798bf215546Sopenharmony_ci * Set the integer debug state specified by \p pname. This can be called from 799bf215546Sopenharmony_ci * _mesa_set_enable for example. 800bf215546Sopenharmony_ci */ 801bf215546Sopenharmony_cibool 802bf215546Sopenharmony_ci_mesa_set_debug_state_int(struct gl_context *ctx, GLenum pname, GLint val) 803bf215546Sopenharmony_ci{ 804bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci if (!debug) 807bf215546Sopenharmony_ci return false; 808bf215546Sopenharmony_ci 809bf215546Sopenharmony_ci switch (pname) { 810bf215546Sopenharmony_ci case GL_DEBUG_OUTPUT: 811bf215546Sopenharmony_ci debug->DebugOutput = (val != 0); 812bf215546Sopenharmony_ci break; 813bf215546Sopenharmony_ci case GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB: 814bf215546Sopenharmony_ci debug->SyncOutput = (val != 0); 815bf215546Sopenharmony_ci break; 816bf215546Sopenharmony_ci default: 817bf215546Sopenharmony_ci assert(!"unknown debug output param"); 818bf215546Sopenharmony_ci break; 819bf215546Sopenharmony_ci } 820bf215546Sopenharmony_ci 821bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci return true; 824bf215546Sopenharmony_ci} 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci/** 827bf215546Sopenharmony_ci * Query the integer debug state specified by \p pname. This can be called 828bf215546Sopenharmony_ci * _mesa_GetIntegerv for example. 829bf215546Sopenharmony_ci */ 830bf215546Sopenharmony_ciGLint 831bf215546Sopenharmony_ci_mesa_get_debug_state_int(struct gl_context *ctx, GLenum pname) 832bf215546Sopenharmony_ci{ 833bf215546Sopenharmony_ci GLint val; 834bf215546Sopenharmony_ci 835bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 836bf215546Sopenharmony_ci if (!debug) 837bf215546Sopenharmony_ci return 0; 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci switch (pname) { 840bf215546Sopenharmony_ci case GL_DEBUG_OUTPUT: 841bf215546Sopenharmony_ci val = debug->DebugOutput; 842bf215546Sopenharmony_ci break; 843bf215546Sopenharmony_ci case GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB: 844bf215546Sopenharmony_ci val = debug->SyncOutput; 845bf215546Sopenharmony_ci break; 846bf215546Sopenharmony_ci case GL_DEBUG_LOGGED_MESSAGES: 847bf215546Sopenharmony_ci val = debug->Log.NumMessages; 848bf215546Sopenharmony_ci break; 849bf215546Sopenharmony_ci case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: 850bf215546Sopenharmony_ci val = (debug->Log.NumMessages) ? 851bf215546Sopenharmony_ci debug->Log.Messages[debug->Log.NextMessage].length + 1 : 0; 852bf215546Sopenharmony_ci break; 853bf215546Sopenharmony_ci case GL_DEBUG_GROUP_STACK_DEPTH: 854bf215546Sopenharmony_ci val = debug->CurrentGroup + 1; 855bf215546Sopenharmony_ci break; 856bf215546Sopenharmony_ci default: 857bf215546Sopenharmony_ci assert(!"unknown debug output param"); 858bf215546Sopenharmony_ci val = 0; 859bf215546Sopenharmony_ci break; 860bf215546Sopenharmony_ci } 861bf215546Sopenharmony_ci 862bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 863bf215546Sopenharmony_ci 864bf215546Sopenharmony_ci return val; 865bf215546Sopenharmony_ci} 866bf215546Sopenharmony_ci 867bf215546Sopenharmony_ci/** 868bf215546Sopenharmony_ci * Query the pointer debug state specified by \p pname. This can be called 869bf215546Sopenharmony_ci * _mesa_GetPointerv for example. 870bf215546Sopenharmony_ci */ 871bf215546Sopenharmony_civoid * 872bf215546Sopenharmony_ci_mesa_get_debug_state_ptr(struct gl_context *ctx, GLenum pname) 873bf215546Sopenharmony_ci{ 874bf215546Sopenharmony_ci void *val; 875bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 876bf215546Sopenharmony_ci 877bf215546Sopenharmony_ci if (!debug) 878bf215546Sopenharmony_ci return NULL; 879bf215546Sopenharmony_ci 880bf215546Sopenharmony_ci switch (pname) { 881bf215546Sopenharmony_ci case GL_DEBUG_CALLBACK_FUNCTION_ARB: 882bf215546Sopenharmony_ci val = (void *) debug->Callback; 883bf215546Sopenharmony_ci break; 884bf215546Sopenharmony_ci case GL_DEBUG_CALLBACK_USER_PARAM_ARB: 885bf215546Sopenharmony_ci val = (void *) debug->CallbackData; 886bf215546Sopenharmony_ci break; 887bf215546Sopenharmony_ci default: 888bf215546Sopenharmony_ci assert(!"unknown debug output param"); 889bf215546Sopenharmony_ci val = NULL; 890bf215546Sopenharmony_ci break; 891bf215546Sopenharmony_ci } 892bf215546Sopenharmony_ci 893bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 894bf215546Sopenharmony_ci 895bf215546Sopenharmony_ci return val; 896bf215546Sopenharmony_ci} 897bf215546Sopenharmony_ci 898bf215546Sopenharmony_ci/** 899bf215546Sopenharmony_ci * Insert a debug message. The mutex is assumed to be locked, and will be 900bf215546Sopenharmony_ci * unlocked by this call. 901bf215546Sopenharmony_ci */ 902bf215546Sopenharmony_cistatic void 903bf215546Sopenharmony_cilog_msg_locked_and_unlock(struct gl_context *ctx, 904bf215546Sopenharmony_ci enum mesa_debug_source source, 905bf215546Sopenharmony_ci enum mesa_debug_type type, GLuint id, 906bf215546Sopenharmony_ci enum mesa_debug_severity severity, 907bf215546Sopenharmony_ci GLint len, const char *buf) 908bf215546Sopenharmony_ci{ 909bf215546Sopenharmony_ci struct gl_debug_state *debug = ctx->Debug; 910bf215546Sopenharmony_ci 911bf215546Sopenharmony_ci if (!_mesa_debug_is_message_enabled(debug, source, type, id, severity)) { 912bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 913bf215546Sopenharmony_ci return; 914bf215546Sopenharmony_ci } 915bf215546Sopenharmony_ci 916bf215546Sopenharmony_ci if (ctx->Debug->Callback) { 917bf215546Sopenharmony_ci /* Call the user's callback function */ 918bf215546Sopenharmony_ci GLenum gl_source = debug_source_enums[source]; 919bf215546Sopenharmony_ci GLenum gl_type = debug_type_enums[type]; 920bf215546Sopenharmony_ci GLenum gl_severity = debug_severity_enums[severity]; 921bf215546Sopenharmony_ci GLDEBUGPROC callback = ctx->Debug->Callback; 922bf215546Sopenharmony_ci const void *data = ctx->Debug->CallbackData; 923bf215546Sopenharmony_ci 924bf215546Sopenharmony_ci /* 925bf215546Sopenharmony_ci * When ctx->Debug->SyncOutput is GL_FALSE, the client is prepared for 926bf215546Sopenharmony_ci * unsynchronous calls. When it is GL_TRUE, we will not spawn threads. 927bf215546Sopenharmony_ci * In either case, we can call the callback unlocked. 928bf215546Sopenharmony_ci */ 929bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 930bf215546Sopenharmony_ci callback(gl_source, gl_type, id, gl_severity, len, buf, data); 931bf215546Sopenharmony_ci } 932bf215546Sopenharmony_ci else { 933bf215546Sopenharmony_ci /* add debug message to queue */ 934bf215546Sopenharmony_ci debug_log_message(ctx->Debug, source, type, id, severity, len, buf); 935bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 936bf215546Sopenharmony_ci } 937bf215546Sopenharmony_ci} 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_ci/** 940bf215546Sopenharmony_ci * Log a client or driver debug message. 941bf215546Sopenharmony_ci */ 942bf215546Sopenharmony_civoid 943bf215546Sopenharmony_ci_mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source, 944bf215546Sopenharmony_ci enum mesa_debug_type type, GLuint id, 945bf215546Sopenharmony_ci enum mesa_debug_severity severity, GLint len, const char *buf) 946bf215546Sopenharmony_ci{ 947bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 948bf215546Sopenharmony_ci 949bf215546Sopenharmony_ci if (!debug) 950bf215546Sopenharmony_ci return; 951bf215546Sopenharmony_ci 952bf215546Sopenharmony_ci log_msg_locked_and_unlock(ctx, source, type, id, severity, len, buf); 953bf215546Sopenharmony_ci} 954bf215546Sopenharmony_ci 955bf215546Sopenharmony_ci 956bf215546Sopenharmony_ci/** 957bf215546Sopenharmony_ci * Verify that source, type, and severity are valid enums. 958bf215546Sopenharmony_ci * 959bf215546Sopenharmony_ci * The 'caller' param is used for handling values available 960bf215546Sopenharmony_ci * only in glDebugMessageInsert or glDebugMessageControl 961bf215546Sopenharmony_ci */ 962bf215546Sopenharmony_cistatic GLboolean 963bf215546Sopenharmony_civalidate_params(struct gl_context *ctx, unsigned caller, 964bf215546Sopenharmony_ci const char *callerstr, GLenum source, GLenum type, 965bf215546Sopenharmony_ci GLenum severity) 966bf215546Sopenharmony_ci{ 967bf215546Sopenharmony_ci#define INSERT 1 968bf215546Sopenharmony_ci#define CONTROL 2 969bf215546Sopenharmony_ci switch(source) { 970bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_APPLICATION_ARB: 971bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: 972bf215546Sopenharmony_ci break; 973bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_API_ARB: 974bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: 975bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: 976bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_OTHER_ARB: 977bf215546Sopenharmony_ci if (caller != INSERT) 978bf215546Sopenharmony_ci break; 979bf215546Sopenharmony_ci else 980bf215546Sopenharmony_ci goto error; 981bf215546Sopenharmony_ci case GL_DONT_CARE: 982bf215546Sopenharmony_ci if (caller == CONTROL) 983bf215546Sopenharmony_ci break; 984bf215546Sopenharmony_ci else 985bf215546Sopenharmony_ci goto error; 986bf215546Sopenharmony_ci default: 987bf215546Sopenharmony_ci goto error; 988bf215546Sopenharmony_ci } 989bf215546Sopenharmony_ci 990bf215546Sopenharmony_ci switch(type) { 991bf215546Sopenharmony_ci case GL_DEBUG_TYPE_ERROR_ARB: 992bf215546Sopenharmony_ci case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: 993bf215546Sopenharmony_ci case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: 994bf215546Sopenharmony_ci case GL_DEBUG_TYPE_PERFORMANCE_ARB: 995bf215546Sopenharmony_ci case GL_DEBUG_TYPE_PORTABILITY_ARB: 996bf215546Sopenharmony_ci case GL_DEBUG_TYPE_OTHER_ARB: 997bf215546Sopenharmony_ci case GL_DEBUG_TYPE_MARKER: 998bf215546Sopenharmony_ci case GL_DEBUG_TYPE_PUSH_GROUP: 999bf215546Sopenharmony_ci case GL_DEBUG_TYPE_POP_GROUP: 1000bf215546Sopenharmony_ci break; 1001bf215546Sopenharmony_ci case GL_DONT_CARE: 1002bf215546Sopenharmony_ci if (caller == CONTROL) 1003bf215546Sopenharmony_ci break; 1004bf215546Sopenharmony_ci else 1005bf215546Sopenharmony_ci goto error; 1006bf215546Sopenharmony_ci default: 1007bf215546Sopenharmony_ci goto error; 1008bf215546Sopenharmony_ci } 1009bf215546Sopenharmony_ci 1010bf215546Sopenharmony_ci switch(severity) { 1011bf215546Sopenharmony_ci case GL_DEBUG_SEVERITY_HIGH_ARB: 1012bf215546Sopenharmony_ci case GL_DEBUG_SEVERITY_MEDIUM_ARB: 1013bf215546Sopenharmony_ci case GL_DEBUG_SEVERITY_LOW_ARB: 1014bf215546Sopenharmony_ci case GL_DEBUG_SEVERITY_NOTIFICATION: 1015bf215546Sopenharmony_ci break; 1016bf215546Sopenharmony_ci case GL_DONT_CARE: 1017bf215546Sopenharmony_ci if (caller == CONTROL) 1018bf215546Sopenharmony_ci break; 1019bf215546Sopenharmony_ci else 1020bf215546Sopenharmony_ci goto error; 1021bf215546Sopenharmony_ci default: 1022bf215546Sopenharmony_ci goto error; 1023bf215546Sopenharmony_ci } 1024bf215546Sopenharmony_ci return GL_TRUE; 1025bf215546Sopenharmony_ci 1026bf215546Sopenharmony_cierror: 1027bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_ENUM, "bad values passed to %s" 1028bf215546Sopenharmony_ci "(source=0x%x, type=0x%x, severity=0x%x)", callerstr, 1029bf215546Sopenharmony_ci source, type, severity); 1030bf215546Sopenharmony_ci 1031bf215546Sopenharmony_ci return GL_FALSE; 1032bf215546Sopenharmony_ci} 1033bf215546Sopenharmony_ci 1034bf215546Sopenharmony_ci 1035bf215546Sopenharmony_cistatic GLboolean 1036bf215546Sopenharmony_civalidate_length(struct gl_context *ctx, const char *callerstr, GLsizei length, 1037bf215546Sopenharmony_ci const GLchar *buf) 1038bf215546Sopenharmony_ci{ 1039bf215546Sopenharmony_ci 1040bf215546Sopenharmony_ci if (length < 0) { 1041bf215546Sopenharmony_ci GLsizei len = strlen(buf); 1042bf215546Sopenharmony_ci 1043bf215546Sopenharmony_ci if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 1044bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1045bf215546Sopenharmony_ci "%s(null terminated string length=%d, is not less than " 1046bf215546Sopenharmony_ci "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, len, 1047bf215546Sopenharmony_ci MAX_DEBUG_MESSAGE_LENGTH); 1048bf215546Sopenharmony_ci return GL_FALSE; 1049bf215546Sopenharmony_ci } 1050bf215546Sopenharmony_ci } 1051bf215546Sopenharmony_ci 1052bf215546Sopenharmony_ci if (length >= MAX_DEBUG_MESSAGE_LENGTH) { 1053bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1054bf215546Sopenharmony_ci "%s(length=%d, which is not less than " 1055bf215546Sopenharmony_ci "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, length, 1056bf215546Sopenharmony_ci MAX_DEBUG_MESSAGE_LENGTH); 1057bf215546Sopenharmony_ci return GL_FALSE; 1058bf215546Sopenharmony_ci } 1059bf215546Sopenharmony_ci 1060bf215546Sopenharmony_ci return GL_TRUE; 1061bf215546Sopenharmony_ci} 1062bf215546Sopenharmony_ci 1063bf215546Sopenharmony_ci 1064bf215546Sopenharmony_civoid GLAPIENTRY 1065bf215546Sopenharmony_ci_mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id, 1066bf215546Sopenharmony_ci GLenum severity, GLint length, 1067bf215546Sopenharmony_ci const GLchar *buf) 1068bf215546Sopenharmony_ci{ 1069bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1070bf215546Sopenharmony_ci const char *callerstr; 1071bf215546Sopenharmony_ci 1072bf215546Sopenharmony_ci if (_mesa_is_desktop_gl(ctx)) 1073bf215546Sopenharmony_ci callerstr = "glDebugMessageInsert"; 1074bf215546Sopenharmony_ci else 1075bf215546Sopenharmony_ci callerstr = "glDebugMessageInsertKHR"; 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci if (!validate_params(ctx, INSERT, callerstr, source, type, severity)) 1078bf215546Sopenharmony_ci return; /* GL_INVALID_ENUM */ 1079bf215546Sopenharmony_ci 1080bf215546Sopenharmony_ci if (!validate_length(ctx, callerstr, length, buf)) 1081bf215546Sopenharmony_ci return; /* GL_INVALID_VALUE */ 1082bf215546Sopenharmony_ci 1083bf215546Sopenharmony_ci /* if length not specified, string will be null terminated: */ 1084bf215546Sopenharmony_ci if (length < 0) 1085bf215546Sopenharmony_ci length = strlen(buf); 1086bf215546Sopenharmony_ci 1087bf215546Sopenharmony_ci _mesa_log_msg(ctx, gl_enum_to_debug_source(source), 1088bf215546Sopenharmony_ci gl_enum_to_debug_type(type), id, 1089bf215546Sopenharmony_ci gl_enum_to_debug_severity(severity), 1090bf215546Sopenharmony_ci length, buf); 1091bf215546Sopenharmony_ci 1092bf215546Sopenharmony_ci if (type == GL_DEBUG_TYPE_MARKER && ctx->has_string_marker) { 1093bf215546Sopenharmony_ci ctx->pipe->emit_string_marker(ctx->pipe, buf, length); 1094bf215546Sopenharmony_ci } 1095bf215546Sopenharmony_ci} 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci 1098bf215546Sopenharmony_ciGLuint GLAPIENTRY 1099bf215546Sopenharmony_ci_mesa_GetDebugMessageLog(GLuint count, GLsizei logSize, GLenum *sources, 1100bf215546Sopenharmony_ci GLenum *types, GLenum *ids, GLenum *severities, 1101bf215546Sopenharmony_ci GLsizei *lengths, GLchar *messageLog) 1102bf215546Sopenharmony_ci{ 1103bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1104bf215546Sopenharmony_ci struct gl_debug_state *debug; 1105bf215546Sopenharmony_ci const char *callerstr; 1106bf215546Sopenharmony_ci GLuint ret; 1107bf215546Sopenharmony_ci 1108bf215546Sopenharmony_ci if (_mesa_is_desktop_gl(ctx)) 1109bf215546Sopenharmony_ci callerstr = "glGetDebugMessageLog"; 1110bf215546Sopenharmony_ci else 1111bf215546Sopenharmony_ci callerstr = "glGetDebugMessageLogKHR"; 1112bf215546Sopenharmony_ci 1113bf215546Sopenharmony_ci if (!messageLog) 1114bf215546Sopenharmony_ci logSize = 0; 1115bf215546Sopenharmony_ci 1116bf215546Sopenharmony_ci if (logSize < 0) { 1117bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1118bf215546Sopenharmony_ci "%s(logSize=%d : logSize must not be negative)", 1119bf215546Sopenharmony_ci callerstr, logSize); 1120bf215546Sopenharmony_ci return 0; 1121bf215546Sopenharmony_ci } 1122bf215546Sopenharmony_ci 1123bf215546Sopenharmony_ci debug = _mesa_lock_debug_state(ctx); 1124bf215546Sopenharmony_ci if (!debug) 1125bf215546Sopenharmony_ci return 0; 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci for (ret = 0; ret < count; ret++) { 1128bf215546Sopenharmony_ci const struct gl_debug_message *msg = debug_fetch_message(debug); 1129bf215546Sopenharmony_ci GLsizei len; 1130bf215546Sopenharmony_ci 1131bf215546Sopenharmony_ci if (!msg) 1132bf215546Sopenharmony_ci break; 1133bf215546Sopenharmony_ci 1134bf215546Sopenharmony_ci len = msg->length; 1135bf215546Sopenharmony_ci if (len < 0) 1136bf215546Sopenharmony_ci len = strlen(msg->message); 1137bf215546Sopenharmony_ci 1138bf215546Sopenharmony_ci if (logSize < len+1 && messageLog != NULL) 1139bf215546Sopenharmony_ci break; 1140bf215546Sopenharmony_ci 1141bf215546Sopenharmony_ci if (messageLog) { 1142bf215546Sopenharmony_ci assert(msg->message[len] == '\0'); 1143bf215546Sopenharmony_ci (void) strncpy(messageLog, msg->message, (size_t)len+1); 1144bf215546Sopenharmony_ci 1145bf215546Sopenharmony_ci messageLog += len+1; 1146bf215546Sopenharmony_ci logSize -= len+1; 1147bf215546Sopenharmony_ci } 1148bf215546Sopenharmony_ci 1149bf215546Sopenharmony_ci if (lengths) 1150bf215546Sopenharmony_ci *lengths++ = len+1; 1151bf215546Sopenharmony_ci if (severities) 1152bf215546Sopenharmony_ci *severities++ = debug_severity_enums[msg->severity]; 1153bf215546Sopenharmony_ci if (sources) 1154bf215546Sopenharmony_ci *sources++ = debug_source_enums[msg->source]; 1155bf215546Sopenharmony_ci if (types) 1156bf215546Sopenharmony_ci *types++ = debug_type_enums[msg->type]; 1157bf215546Sopenharmony_ci if (ids) 1158bf215546Sopenharmony_ci *ids++ = msg->id; 1159bf215546Sopenharmony_ci 1160bf215546Sopenharmony_ci debug_delete_messages(debug, 1); 1161bf215546Sopenharmony_ci } 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1164bf215546Sopenharmony_ci 1165bf215546Sopenharmony_ci return ret; 1166bf215546Sopenharmony_ci} 1167bf215546Sopenharmony_ci 1168bf215546Sopenharmony_ci 1169bf215546Sopenharmony_civoid GLAPIENTRY 1170bf215546Sopenharmony_ci_mesa_DebugMessageControl(GLenum gl_source, GLenum gl_type, 1171bf215546Sopenharmony_ci GLenum gl_severity, GLsizei count, 1172bf215546Sopenharmony_ci const GLuint *ids, GLboolean enabled) 1173bf215546Sopenharmony_ci{ 1174bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1175bf215546Sopenharmony_ci enum mesa_debug_source source = gl_enum_to_debug_source(gl_source); 1176bf215546Sopenharmony_ci enum mesa_debug_type type = gl_enum_to_debug_type(gl_type); 1177bf215546Sopenharmony_ci enum mesa_debug_severity severity = gl_enum_to_debug_severity(gl_severity); 1178bf215546Sopenharmony_ci const char *callerstr; 1179bf215546Sopenharmony_ci struct gl_debug_state *debug; 1180bf215546Sopenharmony_ci 1181bf215546Sopenharmony_ci if (_mesa_is_desktop_gl(ctx)) 1182bf215546Sopenharmony_ci callerstr = "glDebugMessageControl"; 1183bf215546Sopenharmony_ci else 1184bf215546Sopenharmony_ci callerstr = "glDebugMessageControlKHR"; 1185bf215546Sopenharmony_ci 1186bf215546Sopenharmony_ci if (count < 0) { 1187bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1188bf215546Sopenharmony_ci "%s(count=%d : count must not be negative)", callerstr, 1189bf215546Sopenharmony_ci count); 1190bf215546Sopenharmony_ci return; 1191bf215546Sopenharmony_ci } 1192bf215546Sopenharmony_ci 1193bf215546Sopenharmony_ci if (!validate_params(ctx, CONTROL, callerstr, gl_source, gl_type, 1194bf215546Sopenharmony_ci gl_severity)) 1195bf215546Sopenharmony_ci return; /* GL_INVALID_ENUM */ 1196bf215546Sopenharmony_ci 1197bf215546Sopenharmony_ci if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE 1198bf215546Sopenharmony_ci || gl_source == GL_DONT_CARE)) { 1199bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1200bf215546Sopenharmony_ci "%s(When passing an array of ids, severity must be" 1201bf215546Sopenharmony_ci " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.", 1202bf215546Sopenharmony_ci callerstr); 1203bf215546Sopenharmony_ci return; 1204bf215546Sopenharmony_ci } 1205bf215546Sopenharmony_ci 1206bf215546Sopenharmony_ci debug = _mesa_lock_debug_state(ctx); 1207bf215546Sopenharmony_ci if (!debug) 1208bf215546Sopenharmony_ci return; 1209bf215546Sopenharmony_ci 1210bf215546Sopenharmony_ci if (count) { 1211bf215546Sopenharmony_ci GLsizei i; 1212bf215546Sopenharmony_ci for (i = 0; i < count; i++) 1213bf215546Sopenharmony_ci debug_set_message_enable(debug, source, type, ids[i], enabled); 1214bf215546Sopenharmony_ci } 1215bf215546Sopenharmony_ci else { 1216bf215546Sopenharmony_ci debug_set_message_enable_all(debug, source, type, severity, enabled); 1217bf215546Sopenharmony_ci } 1218bf215546Sopenharmony_ci 1219bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1220bf215546Sopenharmony_ci} 1221bf215546Sopenharmony_ci 1222bf215546Sopenharmony_ci 1223bf215546Sopenharmony_civoid GLAPIENTRY 1224bf215546Sopenharmony_ci_mesa_DebugMessageCallback(GLDEBUGPROC callback, const void *userParam) 1225bf215546Sopenharmony_ci{ 1226bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1227bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 1228bf215546Sopenharmony_ci if (debug) { 1229bf215546Sopenharmony_ci debug->Callback = callback; 1230bf215546Sopenharmony_ci debug->CallbackData = userParam; 1231bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1232bf215546Sopenharmony_ci } 1233bf215546Sopenharmony_ci} 1234bf215546Sopenharmony_ci 1235bf215546Sopenharmony_ci 1236bf215546Sopenharmony_civoid GLAPIENTRY 1237bf215546Sopenharmony_ci_mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length, 1238bf215546Sopenharmony_ci const GLchar *message) 1239bf215546Sopenharmony_ci{ 1240bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1241bf215546Sopenharmony_ci const char *callerstr; 1242bf215546Sopenharmony_ci struct gl_debug_state *debug; 1243bf215546Sopenharmony_ci struct gl_debug_message *emptySlot; 1244bf215546Sopenharmony_ci 1245bf215546Sopenharmony_ci if (_mesa_is_desktop_gl(ctx)) 1246bf215546Sopenharmony_ci callerstr = "glPushDebugGroup"; 1247bf215546Sopenharmony_ci else 1248bf215546Sopenharmony_ci callerstr = "glPushDebugGroupKHR"; 1249bf215546Sopenharmony_ci 1250bf215546Sopenharmony_ci switch(source) { 1251bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_APPLICATION: 1252bf215546Sopenharmony_ci case GL_DEBUG_SOURCE_THIRD_PARTY: 1253bf215546Sopenharmony_ci break; 1254bf215546Sopenharmony_ci default: 1255bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_ENUM, "bad value passed to %s" 1256bf215546Sopenharmony_ci "(source=0x%x)", callerstr, source); 1257bf215546Sopenharmony_ci return; 1258bf215546Sopenharmony_ci } 1259bf215546Sopenharmony_ci 1260bf215546Sopenharmony_ci if (!validate_length(ctx, callerstr, length, message)) 1261bf215546Sopenharmony_ci return; /* GL_INVALID_VALUE */ 1262bf215546Sopenharmony_ci 1263bf215546Sopenharmony_ci if (length < 0) 1264bf215546Sopenharmony_ci length = strlen(message); 1265bf215546Sopenharmony_ci 1266bf215546Sopenharmony_ci debug = _mesa_lock_debug_state(ctx); 1267bf215546Sopenharmony_ci if (!debug) 1268bf215546Sopenharmony_ci return; 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci if (debug->CurrentGroup >= MAX_DEBUG_GROUP_STACK_DEPTH-1) { 1271bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1272bf215546Sopenharmony_ci _mesa_error(ctx, GL_STACK_OVERFLOW, "%s", callerstr); 1273bf215546Sopenharmony_ci return; 1274bf215546Sopenharmony_ci } 1275bf215546Sopenharmony_ci 1276bf215546Sopenharmony_ci /* pop reuses the message details from push so we store this */ 1277bf215546Sopenharmony_ci emptySlot = debug_get_group_message(debug); 1278bf215546Sopenharmony_ci debug_message_store(emptySlot, 1279bf215546Sopenharmony_ci gl_enum_to_debug_source(source), 1280bf215546Sopenharmony_ci gl_enum_to_debug_type(GL_DEBUG_TYPE_PUSH_GROUP), 1281bf215546Sopenharmony_ci id, 1282bf215546Sopenharmony_ci gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION), 1283bf215546Sopenharmony_ci length, message); 1284bf215546Sopenharmony_ci 1285bf215546Sopenharmony_ci debug_push_group(debug); 1286bf215546Sopenharmony_ci 1287bf215546Sopenharmony_ci log_msg_locked_and_unlock(ctx, 1288bf215546Sopenharmony_ci gl_enum_to_debug_source(source), 1289bf215546Sopenharmony_ci MESA_DEBUG_TYPE_PUSH_GROUP, id, 1290bf215546Sopenharmony_ci MESA_DEBUG_SEVERITY_NOTIFICATION, length, 1291bf215546Sopenharmony_ci message); 1292bf215546Sopenharmony_ci} 1293bf215546Sopenharmony_ci 1294bf215546Sopenharmony_ci 1295bf215546Sopenharmony_civoid GLAPIENTRY 1296bf215546Sopenharmony_ci_mesa_PopDebugGroup(void) 1297bf215546Sopenharmony_ci{ 1298bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1299bf215546Sopenharmony_ci const char *callerstr; 1300bf215546Sopenharmony_ci struct gl_debug_state *debug; 1301bf215546Sopenharmony_ci struct gl_debug_message *gdmessage, msg; 1302bf215546Sopenharmony_ci 1303bf215546Sopenharmony_ci if (_mesa_is_desktop_gl(ctx)) 1304bf215546Sopenharmony_ci callerstr = "glPopDebugGroup"; 1305bf215546Sopenharmony_ci else 1306bf215546Sopenharmony_ci callerstr = "glPopDebugGroupKHR"; 1307bf215546Sopenharmony_ci 1308bf215546Sopenharmony_ci debug = _mesa_lock_debug_state(ctx); 1309bf215546Sopenharmony_ci if (!debug) 1310bf215546Sopenharmony_ci return; 1311bf215546Sopenharmony_ci 1312bf215546Sopenharmony_ci if (debug->CurrentGroup <= 0) { 1313bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1314bf215546Sopenharmony_ci _mesa_error(ctx, GL_STACK_UNDERFLOW, "%s", callerstr); 1315bf215546Sopenharmony_ci return; 1316bf215546Sopenharmony_ci } 1317bf215546Sopenharmony_ci 1318bf215546Sopenharmony_ci debug_pop_group(debug); 1319bf215546Sopenharmony_ci 1320bf215546Sopenharmony_ci /* make a shallow copy */ 1321bf215546Sopenharmony_ci gdmessage = debug_get_group_message(debug); 1322bf215546Sopenharmony_ci msg = *gdmessage; 1323bf215546Sopenharmony_ci gdmessage->message = NULL; 1324bf215546Sopenharmony_ci gdmessage->length = 0; 1325bf215546Sopenharmony_ci 1326bf215546Sopenharmony_ci log_msg_locked_and_unlock(ctx, 1327bf215546Sopenharmony_ci msg.source, 1328bf215546Sopenharmony_ci gl_enum_to_debug_type(GL_DEBUG_TYPE_POP_GROUP), 1329bf215546Sopenharmony_ci msg.id, 1330bf215546Sopenharmony_ci gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION), 1331bf215546Sopenharmony_ci msg.length, msg.message); 1332bf215546Sopenharmony_ci 1333bf215546Sopenharmony_ci debug_message_clear(&msg); 1334bf215546Sopenharmony_ci} 1335bf215546Sopenharmony_ci 1336bf215546Sopenharmony_ci 1337bf215546Sopenharmony_civoid 1338bf215546Sopenharmony_ci_mesa_init_debug_output(struct gl_context *ctx) 1339bf215546Sopenharmony_ci{ 1340bf215546Sopenharmony_ci simple_mtx_init(&ctx->DebugMutex, mtx_plain); 1341bf215546Sopenharmony_ci 1342bf215546Sopenharmony_ci if (MESA_DEBUG_FLAGS & DEBUG_CONTEXT) { 1343bf215546Sopenharmony_ci /* If the MESA_DEBUG env is set to "context", we'll turn on the 1344bf215546Sopenharmony_ci * GL_CONTEXT_FLAG_DEBUG_BIT context flag and log debug output 1345bf215546Sopenharmony_ci * messages to stderr (or whatever MESA_LOG_FILE points at). 1346bf215546Sopenharmony_ci */ 1347bf215546Sopenharmony_ci struct gl_debug_state *debug = _mesa_lock_debug_state(ctx); 1348bf215546Sopenharmony_ci if (!debug) { 1349bf215546Sopenharmony_ci return; 1350bf215546Sopenharmony_ci } 1351bf215546Sopenharmony_ci debug->DebugOutput = GL_TRUE; 1352bf215546Sopenharmony_ci debug->LogToStderr = GL_TRUE; 1353bf215546Sopenharmony_ci ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT; 1354bf215546Sopenharmony_ci _mesa_unlock_debug_state(ctx); 1355bf215546Sopenharmony_ci } 1356bf215546Sopenharmony_ci} 1357bf215546Sopenharmony_ci 1358bf215546Sopenharmony_ci 1359bf215546Sopenharmony_civoid 1360bf215546Sopenharmony_ci_mesa_destroy_debug_output(struct gl_context *ctx) 1361bf215546Sopenharmony_ci{ 1362bf215546Sopenharmony_ci if (ctx->Debug) { 1363bf215546Sopenharmony_ci debug_destroy(ctx->Debug); 1364bf215546Sopenharmony_ci /* set to NULL just in case it is used before context is completely gone. */ 1365bf215546Sopenharmony_ci ctx->Debug = NULL; 1366bf215546Sopenharmony_ci } 1367bf215546Sopenharmony_ci 1368bf215546Sopenharmony_ci simple_mtx_destroy(&ctx->DebugMutex); 1369bf215546Sopenharmony_ci} 1370bf215546Sopenharmony_ci 1371bf215546Sopenharmony_civoid GLAPIENTRY 1372bf215546Sopenharmony_ci_mesa_StringMarkerGREMEDY(GLsizei len, const GLvoid *string) 1373bf215546Sopenharmony_ci{ 1374bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 1375bf215546Sopenharmony_ci if (ctx->Extensions.GREMEDY_string_marker) { 1376bf215546Sopenharmony_ci /* if length not specified, string will be null terminated: */ 1377bf215546Sopenharmony_ci if (len <= 0) 1378bf215546Sopenharmony_ci len = strlen(string); 1379bf215546Sopenharmony_ci ctx->pipe->emit_string_marker(ctx->pipe, string, len); 1380bf215546Sopenharmony_ci } else { 1381bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "StringMarkerGREMEDY"); 1382bf215546Sopenharmony_ci } 1383bf215546Sopenharmony_ci} 1384