errors.c revision e59fc3faa504fe56a3b2702bf49a70d392faac57
1/** 2 * \file errors.c 3 * Mesa debugging and error handling functions. 4 */ 5 6/* 7 * Mesa 3-D graphics library 8 * Version: 7.1 9 * 10 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 31#include "errors.h" 32#include "enums.h" 33#include "imports.h" 34#include "context.h" 35#include "dispatch.h" 36#include "hash.h" 37#include "mtypes.h" 38#include "version.h" 39#include "hash_table.h" 40#include "glapi/glthread.h" 41 42_glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex); 43static GLuint NextDynamicID = 1; 44 45struct gl_debug_severity 46{ 47 struct simple_node link; 48 GLuint ID; 49}; 50 51static char out_of_memory[] = "Debugging error: out of memory"; 52 53static const GLenum debug_source_enums[] = { 54 GL_DEBUG_SOURCE_API, 55 GL_DEBUG_SOURCE_WINDOW_SYSTEM, 56 GL_DEBUG_SOURCE_SHADER_COMPILER, 57 GL_DEBUG_SOURCE_THIRD_PARTY, 58 GL_DEBUG_SOURCE_APPLICATION, 59 GL_DEBUG_SOURCE_OTHER, 60}; 61 62static const GLenum debug_type_enums[] = { 63 GL_DEBUG_TYPE_ERROR, 64 GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, 65 GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, 66 GL_DEBUG_TYPE_PORTABILITY, 67 GL_DEBUG_TYPE_PERFORMANCE, 68 GL_DEBUG_TYPE_OTHER, 69}; 70 71static const GLenum debug_severity_enums[] = { 72 GL_DEBUG_SEVERITY_LOW, 73 GL_DEBUG_SEVERITY_MEDIUM, 74 GL_DEBUG_SEVERITY_HIGH, 75}; 76 77static enum mesa_debug_source 78gl_enum_to_debug_source(GLenum e) 79{ 80 int i; 81 82 for (i = 0; i < Elements(debug_source_enums); i++) { 83 if (debug_source_enums[i] == e) 84 break; 85 } 86 return i; 87} 88 89static enum mesa_debug_type 90gl_enum_to_debug_type(GLenum e) 91{ 92 int i; 93 94 for (i = 0; i < Elements(debug_type_enums); i++) { 95 if (debug_type_enums[i] == e) 96 break; 97 } 98 return i; 99} 100 101static enum mesa_debug_severity 102gl_enum_to_debug_severity(GLenum e) 103{ 104 int i; 105 106 for (i = 0; i < Elements(debug_severity_enums); i++) { 107 if (debug_severity_enums[i] == e) 108 break; 109 } 110 return i; 111} 112 113/** 114 * Handles generating a GL_ARB_debug_output message ID generated by the GL or 115 * GLSL compiler. 116 * 117 * The GL API has this "ID" mechanism, where the intention is to allow a 118 * client to filter in/out messages based on source, type, and ID. Of course, 119 * building a giant enum list of all debug output messages that Mesa might 120 * generate is ridiculous, so instead we have our caller pass us a pointer to 121 * static storage where the ID should get stored. This ID will be shared 122 * across all contexts for that message (which seems like a desirable 123 * property, even if it's not expected by the spec), but note that it won't be 124 * the same between executions if messages aren't generated in the same order. 125 */ 126static void 127debug_get_id(GLuint *id) 128{ 129 if (!(*id)) { 130 _glthread_LOCK_MUTEX(DynamicIDMutex); 131 if (!(*id)) 132 *id = NextDynamicID++; 133 _glthread_UNLOCK_MUTEX(DynamicIDMutex); 134 } 135} 136 137/* 138 * We store a bitfield in the hash table, with five possible values total. 139 * 140 * The ENABLED_BIT's purpose is self-explanatory. 141 * 142 * The FOUND_BIT is needed to differentiate the value of DISABLED from 143 * the value returned by HashTableLookup() when it can't find the given key. 144 * 145 * The KNOWN_SEVERITY bit is a bit complicated: 146 * 147 * A client may call Control() with an array of IDs, then call Control() 148 * on all message IDs of a certain severity, then Insert() one of the 149 * previously specified IDs, giving us a known severity level, then call 150 * Control() on all message IDs of a certain severity level again. 151 * 152 * After the first call, those IDs will have a FOUND_BIT, but will not 153 * exist in any severity-specific list, so the second call will not 154 * impact them. This is undesirable but unavoidable given the API: 155 * The only entrypoint that gives a severity for a client-defined ID 156 * is the Insert() call. 157 * 158 * For the sake of Control(), we want to maintain the invariant 159 * that an ID will either appear in none of the three severity lists, 160 * or appear once, to minimize pointless duplication and potential surprises. 161 * 162 * Because Insert() is the only place that will learn an ID's severity, 163 * it should insert an ID into the appropriate list, but only if the ID 164 * doesn't exist in it or any other list yet. Because searching all three 165 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY. 166 */ 167enum { 168 FOUND_BIT = 1 << 0, 169 ENABLED_BIT = 1 << 1, 170 KNOWN_SEVERITY = 1 << 2, 171 172 /* HashTable reserves zero as a return value meaning 'not found' */ 173 NOT_FOUND = 0, 174 DISABLED = FOUND_BIT, 175 ENABLED = ENABLED_BIT | FOUND_BIT 176}; 177 178/** 179 * Returns the state of the given message source/type/ID tuple. 180 */ 181static GLboolean 182should_log(struct gl_context *ctx, 183 enum mesa_debug_source source, 184 enum mesa_debug_type type, 185 GLuint id, 186 enum mesa_debug_severity severity) 187{ 188 struct gl_debug_namespace *nspace = 189 &ctx->Debug.Namespaces[source][type]; 190 uintptr_t state; 191 192 /* In addition to not being able to store zero as a value, HashTable also 193 can't use zero as a key. */ 194 if (id) 195 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id); 196 else 197 state = nspace->ZeroID; 198 199 /* Only do this once for each ID. This makes sure the ID exists in, 200 at most, one list, and does not pointlessly appear multiple times. */ 201 if (!(state & KNOWN_SEVERITY)) { 202 struct gl_debug_severity *entry; 203 204 if (state == NOT_FOUND) { 205 if (ctx->Debug.Defaults[severity][source][type]) 206 state = ENABLED; 207 else 208 state = DISABLED; 209 } 210 211 entry = malloc(sizeof *entry); 212 if (!entry) 213 goto out; 214 215 state |= KNOWN_SEVERITY; 216 217 if (id) 218 _mesa_HashInsert(nspace->IDs, id, (void*)state); 219 else 220 nspace->ZeroID = state; 221 222 entry->ID = id; 223 insert_at_tail(&nspace->Severity[severity], &entry->link); 224 } 225 226out: 227 return !!(state & ENABLED_BIT); 228} 229 230/** 231 * Sets the state of the given message source/type/ID tuple. 232 */ 233static void 234set_message_state(struct gl_context *ctx, 235 enum mesa_debug_source source, 236 enum mesa_debug_type type, 237 GLuint id, GLboolean enabled) 238{ 239 struct gl_debug_namespace *nspace = 240 &ctx->Debug.Namespaces[source][type]; 241 uintptr_t state; 242 243 /* In addition to not being able to store zero as a value, HashTable also 244 can't use zero as a key. */ 245 if (id) 246 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id); 247 else 248 state = nspace->ZeroID; 249 250 if (state == NOT_FOUND) 251 state = enabled ? ENABLED : DISABLED; 252 else { 253 if (enabled) 254 state |= ENABLED_BIT; 255 else 256 state &= ~ENABLED_BIT; 257 } 258 259 if (id) 260 _mesa_HashInsert(nspace->IDs, id, (void*)state); 261 else 262 nspace->ZeroID = state; 263} 264 265/** 266 * 'buf' is not necessarily a null-terminated string. When logging, copy 267 * 'len' characters from it, store them in a new, null-terminated string, 268 * and remember the number of bytes used by that string, *including* 269 * the null terminator this time. 270 */ 271static void 272_mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source, 273 enum mesa_debug_type type, GLuint id, 274 enum mesa_debug_severity severity, GLint len, const char *buf) 275{ 276 GLint nextEmpty; 277 struct gl_debug_msg *emptySlot; 278 279 assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH); 280 281 if (!should_log(ctx, source, type, id, severity)) 282 return; 283 284 if (ctx->Debug.Callback) { 285 ctx->Debug.Callback(debug_source_enums[source], 286 debug_type_enums[type], 287 id, 288 debug_severity_enums[severity], 289 len, buf, ctx->Debug.CallbackData); 290 return; 291 } 292 293 if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES) 294 return; 295 296 nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages) 297 % MAX_DEBUG_LOGGED_MESSAGES; 298 emptySlot = &ctx->Debug.Log[nextEmpty]; 299 300 assert(!emptySlot->message && !emptySlot->length); 301 302 emptySlot->message = malloc(len+1); 303 if (emptySlot->message) { 304 (void) strncpy(emptySlot->message, buf, (size_t)len); 305 emptySlot->message[len] = '\0'; 306 307 emptySlot->length = len+1; 308 emptySlot->source = source; 309 emptySlot->type = type; 310 emptySlot->id = id; 311 emptySlot->severity = severity; 312 } else { 313 static GLuint oom_msg_id = 0; 314 debug_get_id(&oom_msg_id); 315 316 /* malloc failed! */ 317 emptySlot->message = out_of_memory; 318 emptySlot->length = strlen(out_of_memory)+1; 319 emptySlot->source = MESA_DEBUG_SOURCE_OTHER; 320 emptySlot->type = MESA_DEBUG_TYPE_ERROR; 321 emptySlot->id = oom_msg_id; 322 emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH; 323 } 324 325 if (ctx->Debug.NumMessages == 0) 326 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length; 327 328 ctx->Debug.NumMessages++; 329} 330 331/** 332 * Pop the oldest debug message out of the log. 333 * Writes the message string, including the null terminator, into 'buf', 334 * using up to 'bufSize' bytes. If 'bufSize' is too small, or 335 * if 'buf' is NULL, nothing is written. 336 * 337 * Returns the number of bytes written on success, or when 'buf' is NULL, 338 * the number that would have been written. A return value of 0 339 * indicates failure. 340 */ 341static GLsizei 342_mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type, 343 GLuint *id, GLenum *severity, GLsizei bufSize, char *buf) 344{ 345 struct gl_debug_msg *msg; 346 GLsizei length; 347 348 if (ctx->Debug.NumMessages == 0) 349 return 0; 350 351 msg = &ctx->Debug.Log[ctx->Debug.NextMsg]; 352 length = msg->length; 353 354 assert(length > 0 && length == ctx->Debug.NextMsgLength); 355 356 if (bufSize < length && buf != NULL) 357 return 0; 358 359 if (severity) 360 *severity = debug_severity_enums[msg->severity]; 361 if (source) 362 *source = debug_source_enums[msg->source]; 363 if (type) 364 *type = debug_type_enums[msg->type]; 365 if (id) 366 *id = msg->id; 367 368 if (buf) { 369 assert(msg->message[length-1] == '\0'); 370 (void) strncpy(buf, msg->message, (size_t)length); 371 } 372 373 if (msg->message != (char*)out_of_memory) 374 free(msg->message); 375 msg->message = NULL; 376 msg->length = 0; 377 378 ctx->Debug.NumMessages--; 379 ctx->Debug.NextMsg++; 380 ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES; 381 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length; 382 383 return length; 384} 385 386/** 387 * Verify that source, type, and severity are valid enums. 388 * glDebugMessageInsertARB only accepts two values for 'source', 389 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE 390 * in any parameter, so handle those cases specially. 391 */ 392static GLboolean 393validate_params(struct gl_context *ctx, unsigned caller, 394 GLenum source, GLenum type, GLenum severity) 395{ 396#define INSERT 1 397#define CONTROL 2 398 switch(source) { 399 case GL_DEBUG_SOURCE_APPLICATION_ARB: 400 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: 401 break; 402 case GL_DEBUG_SOURCE_API_ARB: 403 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: 404 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: 405 case GL_DEBUG_SOURCE_OTHER_ARB: 406 if (caller != INSERT) 407 break; 408 case GL_DONT_CARE: 409 if (caller == CONTROL) 410 break; 411 default: 412 goto error; 413 } 414 415 switch(type) { 416 case GL_DEBUG_TYPE_ERROR_ARB: 417 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: 418 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: 419 case GL_DEBUG_TYPE_PERFORMANCE_ARB: 420 case GL_DEBUG_TYPE_PORTABILITY_ARB: 421 case GL_DEBUG_TYPE_OTHER_ARB: 422 break; 423 case GL_DONT_CARE: 424 if (caller == CONTROL) 425 break; 426 default: 427 goto error; 428 } 429 430 switch(severity) { 431 case GL_DEBUG_SEVERITY_HIGH_ARB: 432 case GL_DEBUG_SEVERITY_MEDIUM_ARB: 433 case GL_DEBUG_SEVERITY_LOW_ARB: 434 break; 435 case GL_DONT_CARE: 436 if (caller == CONTROL) 437 break; 438 default: 439 goto error; 440 } 441 return GL_TRUE; 442 443error: 444 { 445 const char *callerstr; 446 if (caller == INSERT) 447 callerstr = "glDebugMessageInsertARB"; 448 else if (caller == CONTROL) 449 callerstr = "glDebugMessageControlARB"; 450 else 451 return GL_FALSE; 452 453 _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s" 454 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr, 455 source, type, severity); 456 } 457 return GL_FALSE; 458} 459 460void GLAPIENTRY 461_mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id, 462 GLenum severity, GLint length, 463 const GLcharARB* buf) 464{ 465 GET_CURRENT_CONTEXT(ctx); 466 467 if (!validate_params(ctx, INSERT, source, type, severity)) 468 return; /* GL_INVALID_ENUM */ 469 470 if (length < 0) 471 length = strlen(buf); 472 473 if (length >= MAX_DEBUG_MESSAGE_LENGTH) { 474 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB" 475 "(length=%d, which is not less than " 476 "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length, 477 MAX_DEBUG_MESSAGE_LENGTH); 478 return; 479 } 480 481 _mesa_log_msg(ctx, 482 gl_enum_to_debug_source(source), 483 gl_enum_to_debug_type(type), id, 484 gl_enum_to_debug_severity(severity), length, buf); 485} 486 487GLuint GLAPIENTRY 488_mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources, 489 GLenum* types, GLenum* ids, GLenum* severities, 490 GLsizei* lengths, GLcharARB* messageLog) 491{ 492 GET_CURRENT_CONTEXT(ctx); 493 GLuint ret; 494 495 if (!messageLog) 496 logSize = 0; 497 498 if (logSize < 0) { 499 _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB" 500 "(logSize=%d : logSize must not be negative)", logSize); 501 return 0; 502 } 503 504 for (ret = 0; ret < count; ret++) { 505 GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities, 506 logSize, messageLog); 507 if (!written) 508 break; 509 510 if (messageLog) { 511 messageLog += written; 512 logSize -= written; 513 } 514 if (lengths) { 515 *lengths = written; 516 lengths++; 517 } 518 519 if (severities) 520 severities++; 521 if (sources) 522 sources++; 523 if (types) 524 types++; 525 if (ids) 526 ids++; 527 } 528 529 return ret; 530} 531 532/** 533 * Set the state of all message IDs found in the given intersection of 534 * 'source', 'type', and 'severity'. The _COUNT enum can be used for 535 * GL_DONT_CARE (include all messages in the class). 536 * 537 * This requires both setting the state of all previously seen message 538 * IDs in the hash table, and setting the default state for all 539 * applicable combinations of source/type/severity, so that all the 540 * yet-unknown message IDs that may be used in the future will be 541 * impacted as if they were already known. 542 */ 543static void 544control_messages(struct gl_context *ctx, 545 enum mesa_debug_source source, 546 enum mesa_debug_type type, 547 enum mesa_debug_severity severity, 548 GLboolean enabled) 549{ 550 int s, t, sev, smax, tmax, sevmax; 551 552 if (source == MESA_DEBUG_SOURCE_COUNT) { 553 source = 0; 554 smax = MESA_DEBUG_SOURCE_COUNT; 555 } else { 556 smax = source+1; 557 } 558 559 if (type == MESA_DEBUG_TYPE_COUNT) { 560 type = 0; 561 tmax = MESA_DEBUG_TYPE_COUNT; 562 } else { 563 tmax = type+1; 564 } 565 566 if (severity == MESA_DEBUG_SEVERITY_COUNT) { 567 severity = 0; 568 sevmax = MESA_DEBUG_SEVERITY_COUNT; 569 } else { 570 sevmax = severity+1; 571 } 572 573 for (sev = severity; sev < sevmax; sev++) 574 for (s = source; s < smax; s++) 575 for (t = type; t < tmax; t++) { 576 struct simple_node *node; 577 struct gl_debug_severity *entry; 578 579 /* change the default for IDs we've never seen before. */ 580 ctx->Debug.Defaults[sev][s][t] = enabled; 581 582 /* Now change the state of IDs we *have* seen... */ 583 foreach(node, &ctx->Debug.Namespaces[s][t].Severity[sev]) { 584 entry = (struct gl_debug_severity *)node; 585 set_message_state(ctx, s, t, entry->ID, enabled); 586 } 587 } 588} 589 590/** 591 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY 592 * require special handling, since the IDs in them are controlled by clients, 593 * not the OpenGL implementation. 594 * 595 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all 596 * the given IDs in the namespace defined by 'esource' and 'etype' 597 * will be affected. 598 * 599 * If 'count' is zero, this sets the state of all IDs that match 600 * the combination of 'esource', 'etype', and 'eseverity'. 601 */ 602static void 603control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype, 604 GLenum eseverity, GLsizei count, const GLuint *ids, 605 GLboolean enabled) 606{ 607 GLsizei i; 608 enum mesa_debug_source source = gl_enum_to_debug_source(esource); 609 enum mesa_debug_type type = gl_enum_to_debug_type(etype); 610 enum mesa_debug_severity severity = gl_enum_to_debug_severity(eseverity); 611 612 if (count) 613 assert(severity == MESA_DEBUG_SEVERITY_COUNT 614 && type != MESA_DEBUG_TYPE_COUNT 615 && source != MESA_DEBUG_SOURCE_COUNT); 616 617 for (i = 0; i < count; i++) 618 set_message_state(ctx, source, type, ids[i], enabled); 619 620 if (count) 621 return; 622 623 control_messages(ctx, source, type, severity, enabled); 624} 625 626void GLAPIENTRY 627_mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type, 628 GLenum gl_severity, 629 GLsizei count, const GLuint *ids, 630 GLboolean enabled) 631{ 632 enum mesa_debug_source source; 633 enum mesa_debug_type type; 634 enum mesa_debug_severity severity; 635 GET_CURRENT_CONTEXT(ctx); 636 637 if (count < 0) { 638 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB" 639 "(count=%d : count must not be negative)", count); 640 return; 641 } 642 643 if (!validate_params(ctx, CONTROL, gl_source, gl_type, gl_severity)) 644 return; /* GL_INVALID_ENUM */ 645 646 if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE 647 || gl_source == GL_DONT_CARE)) { 648 _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB" 649 "(When passing an array of ids, severity must be" 650 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE."); 651 return; 652 } 653 654 source = gl_enum_to_debug_source(gl_source); 655 type = gl_enum_to_debug_type(gl_type); 656 severity = gl_enum_to_debug_severity(gl_severity); 657 658 control_app_messages(ctx, source, type, severity, count, ids, enabled); 659} 660 661void GLAPIENTRY 662_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const GLvoid *userParam) 663{ 664 GET_CURRENT_CONTEXT(ctx); 665 ctx->Debug.Callback = callback; 666 ctx->Debug.CallbackData = (void *) userParam; 667} 668 669void 670_mesa_init_errors(struct gl_context *ctx) 671{ 672 int s, t, sev; 673 674 ctx->Debug.Callback = NULL; 675 ctx->Debug.SyncOutput = GL_FALSE; 676 ctx->Debug.Log[0].length = 0; 677 ctx->Debug.NumMessages = 0; 678 ctx->Debug.NextMsg = 0; 679 ctx->Debug.NextMsgLength = 0; 680 681 /* Enable all the messages with severity HIGH or MEDIUM by default. */ 682 memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH], GL_TRUE, 683 sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH]); 684 memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE, 685 sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM]); 686 memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW], GL_FALSE, 687 sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW]); 688 689 /* Initialize state for filtering known debug messages. */ 690 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) 691 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) { 692 ctx->Debug.Namespaces[s][t].IDs = _mesa_NewHashTable(); 693 assert(ctx->Debug.Namespaces[s][t].IDs); 694 695 for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) 696 make_empty_list(&ctx->Debug.Namespaces[s][t].Severity[sev]); 697 } 698} 699 700static void 701do_nothing(GLuint key, void *data, void *userData) 702{ 703} 704 705void 706_mesa_free_errors_data(struct gl_context *ctx) 707{ 708 enum mesa_debug_type t; 709 enum mesa_debug_source s; 710 enum mesa_debug_severity sev; 711 712 /* Tear down state for filtering debug messages. */ 713 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) 714 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) { 715 _mesa_HashDeleteAll(ctx->Debug.Namespaces[s][t].IDs, do_nothing, NULL); 716 _mesa_DeleteHashTable(ctx->Debug.Namespaces[s][t].IDs); 717 for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) { 718 struct simple_node *node, *tmp; 719 struct gl_debug_severity *entry; 720 721 foreach_s(node, tmp, &ctx->Debug.Namespaces[s][t].Severity[sev]) { 722 entry = (struct gl_debug_severity *)node; 723 free(entry); 724 } 725 } 726 } 727} 728 729/**********************************************************************/ 730/** \name Diagnostics */ 731/*@{*/ 732 733static void 734output_if_debug(const char *prefixString, const char *outputString, 735 GLboolean newline) 736{ 737 static int debug = -1; 738 static FILE *fout = NULL; 739 740 /* Init the local 'debug' var once. 741 * Note: the _mesa_init_debug() function should have been called 742 * by now so MESA_DEBUG_FLAGS will be initialized. 743 */ 744 if (debug == -1) { 745 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings, 746 * etc to the named file. Otherwise, output to stderr. 747 */ 748 const char *logFile = _mesa_getenv("MESA_LOG_FILE"); 749 if (logFile) 750 fout = fopen(logFile, "w"); 751 if (!fout) 752 fout = stderr; 753#ifdef DEBUG 754 /* in debug builds, print messages unless MESA_DEBUG="silent" */ 755 if (MESA_DEBUG_FLAGS & DEBUG_SILENT) 756 debug = 0; 757 else 758 debug = 1; 759#else 760 /* in release builds, be silent unless MESA_DEBUG is set */ 761 debug = _mesa_getenv("MESA_DEBUG") != NULL; 762#endif 763 } 764 765 /* Now only print the string if we're required to do so. */ 766 if (debug) { 767 fprintf(fout, "%s: %s", prefixString, outputString); 768 if (newline) 769 fprintf(fout, "\n"); 770 fflush(fout); 771 772#if defined(_WIN32) && !defined(_WIN32_WCE) 773 /* stderr from windows applications without console is not usually 774 * visible, so communicate with the debugger instead */ 775 { 776 char buf[4096]; 777 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : ""); 778 OutputDebugStringA(buf); 779 } 780#endif 781 } 782} 783 784/** 785 * When a new type of error is recorded, print a message describing 786 * previous errors which were accumulated. 787 */ 788static void 789flush_delayed_errors( struct gl_context *ctx ) 790{ 791 char s[MAX_DEBUG_MESSAGE_LENGTH]; 792 793 if (ctx->ErrorDebugCount) { 794 _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors", 795 ctx->ErrorDebugCount, 796 _mesa_lookup_enum_by_nr(ctx->ErrorValue)); 797 798 output_if_debug("Mesa", s, GL_TRUE); 799 800 ctx->ErrorDebugCount = 0; 801 } 802} 803 804 805/** 806 * Report a warning (a recoverable error condition) to stderr if 807 * either DEBUG is defined or the MESA_DEBUG env var is set. 808 * 809 * \param ctx GL context. 810 * \param fmtString printf()-like format string. 811 */ 812void 813_mesa_warning( struct gl_context *ctx, const char *fmtString, ... ) 814{ 815 char str[MAX_DEBUG_MESSAGE_LENGTH]; 816 va_list args; 817 va_start( args, fmtString ); 818 (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 819 va_end( args ); 820 821 if (ctx) 822 flush_delayed_errors( ctx ); 823 824 output_if_debug("Mesa warning", str, GL_TRUE); 825} 826 827 828/** 829 * Report an internal implementation problem. 830 * Prints the message to stderr via fprintf(). 831 * 832 * \param ctx GL context. 833 * \param fmtString problem description string. 834 */ 835void 836_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) 837{ 838 va_list args; 839 char str[MAX_DEBUG_MESSAGE_LENGTH]; 840 static int numCalls = 0; 841 842 (void) ctx; 843 844 if (numCalls < 50) { 845 numCalls++; 846 847 va_start( args, fmtString ); 848 _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 849 va_end( args ); 850 fprintf(stderr, "Mesa %s implementation error: %s\n", 851 PACKAGE_VERSION, str); 852 fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n"); 853 } 854} 855 856static GLboolean 857should_output(struct gl_context *ctx, GLenum error, const char *fmtString) 858{ 859 static GLint debug = -1; 860 861 /* Check debug environment variable only once: 862 */ 863 if (debug == -1) { 864 const char *debugEnv = _mesa_getenv("MESA_DEBUG"); 865 866#ifdef DEBUG 867 if (debugEnv && strstr(debugEnv, "silent")) 868 debug = GL_FALSE; 869 else 870 debug = GL_TRUE; 871#else 872 if (debugEnv) 873 debug = GL_TRUE; 874 else 875 debug = GL_FALSE; 876#endif 877 } 878 879 if (debug) { 880 if (ctx->ErrorValue != error || 881 ctx->ErrorDebugFmtString != fmtString) { 882 flush_delayed_errors( ctx ); 883 ctx->ErrorDebugFmtString = fmtString; 884 ctx->ErrorDebugCount = 0; 885 return GL_TRUE; 886 } 887 ctx->ErrorDebugCount++; 888 } 889 return GL_FALSE; 890} 891 892void 893_mesa_gl_debug(struct gl_context *ctx, 894 GLuint *id, 895 enum mesa_debug_type type, 896 enum mesa_debug_severity severity, 897 const char *fmtString, ...) 898{ 899 char s[MAX_DEBUG_MESSAGE_LENGTH]; 900 int len; 901 va_list args; 902 903 debug_get_id(id); 904 905 va_start(args, fmtString); 906 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 907 va_end(args); 908 909 _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, type, 910 *id, severity, len, s); 911} 912 913 914/** 915 * Record an OpenGL state error. These usually occur when the user 916 * passes invalid parameters to a GL function. 917 * 918 * If debugging is enabled (either at compile-time via the DEBUG macro, or 919 * run-time via the MESA_DEBUG environment variable), report the error with 920 * _mesa_debug(). 921 * 922 * \param ctx the GL context. 923 * \param error the error value. 924 * \param fmtString printf() style format string, followed by optional args 925 */ 926void 927_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) 928{ 929 GLboolean do_output, do_log; 930 /* Ideally this would be set up by the caller, so that we had proper IDs 931 * per different message. 932 */ 933 static GLuint error_msg_id = 0; 934 935 debug_get_id(&error_msg_id); 936 937 do_output = should_output(ctx, error, fmtString); 938 do_log = should_log(ctx, 939 MESA_DEBUG_SOURCE_API, 940 MESA_DEBUG_TYPE_ERROR, 941 error_msg_id, 942 MESA_DEBUG_SEVERITY_HIGH); 943 944 if (do_output || do_log) { 945 char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH]; 946 int len; 947 va_list args; 948 949 va_start(args, fmtString); 950 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 951 va_end(args); 952 953 if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 954 /* Too long error message. Whoever calls _mesa_error should use 955 * shorter strings. */ 956 ASSERT(0); 957 return; 958 } 959 960 len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s", 961 _mesa_lookup_enum_by_nr(error), s); 962 if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 963 /* Same as above. */ 964 ASSERT(0); 965 return; 966 } 967 968 /* Print the error to stderr if needed. */ 969 if (do_output) { 970 output_if_debug("Mesa: User error", s2, GL_TRUE); 971 } 972 973 /* Log the error via ARB_debug_output if needed.*/ 974 if (do_log) { 975 _mesa_log_msg(ctx, 976 MESA_DEBUG_SOURCE_API, 977 MESA_DEBUG_TYPE_ERROR, 978 error_msg_id, 979 MESA_DEBUG_SEVERITY_HIGH, len, s2); 980 } 981 } 982 983 /* Set the GL context error state for glGetError. */ 984 _mesa_record_error(ctx, error); 985} 986 987 988/** 989 * Report debug information. Print error message to stderr via fprintf(). 990 * No-op if DEBUG mode not enabled. 991 * 992 * \param ctx GL context. 993 * \param fmtString printf()-style format string, followed by optional args. 994 */ 995void 996_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) 997{ 998#ifdef DEBUG 999 char s[MAX_DEBUG_MESSAGE_LENGTH]; 1000 va_list args; 1001 va_start(args, fmtString); 1002 _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 1003 va_end(args); 1004 output_if_debug("Mesa", s, GL_FALSE); 1005#endif /* DEBUG */ 1006 (void) ctx; 1007 (void) fmtString; 1008} 1009 1010 1011/** 1012 * Report debug information from the shader compiler via GL_ARB_debug_output. 1013 * 1014 * \param ctx GL context. 1015 * \param type The namespace to which this message belongs. 1016 * \param id The message ID within the given namespace. 1017 * \param msg The message to output. Need not be null-terminated. 1018 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated. 1019 */ 1020void 1021_mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint *id, 1022 const char *msg, int len ) 1023{ 1024 enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER; 1025 enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH; 1026 1027 debug_get_id(id); 1028 1029 if (len < 0) 1030 len = strlen(msg); 1031 1032 /* Truncate the message if necessary. */ 1033 if (len >= MAX_DEBUG_MESSAGE_LENGTH) 1034 len = MAX_DEBUG_MESSAGE_LENGTH - 1; 1035 1036 _mesa_log_msg(ctx, source, type, *id, severity, len, msg); 1037} 1038 1039/*@}*/ 1040