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 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 40 41 #define MAXSTRING MAX_DEBUG_MESSAGE_LENGTH 42 43 44 struct gl_client_severity 45 { 46 struct simple_node link; 47 GLuint ID; 48 }; 49 50 static char out_of_memory[] = "Debugging error: out of memory"; 51 52 #define enum_is(e, kind1, kind2) \ 53 ((e) == GL_DEBUG_##kind1##_##kind2##_ARB || (e) == GL_DONT_CARE) 54 #define severity_is(sev, kind) enum_is(sev, SEVERITY, kind) 55 #define source_is(s, kind) enum_is(s, SOURCE, kind) 56 #define type_is(t, kind) enum_is(t, TYPE, kind) 57 58 /* Prevent define collision on Windows */ 59 #undef ERROR 60 61 enum { 62 SOURCE_APPLICATION, 63 SOURCE_THIRD_PARTY, 64 65 SOURCE_COUNT, 66 SOURCE_ANY = -1 67 }; 68 69 enum { 70 TYPE_ERROR, 71 TYPE_DEPRECATED, 72 TYPE_UNDEFINED, 73 TYPE_PORTABILITY, 74 TYPE_PERFORMANCE, 75 TYPE_OTHER, 76 77 TYPE_COUNT, 78 TYPE_ANY = -1 79 }; 80 81 enum { 82 SEVERITY_LOW, 83 SEVERITY_MEDIUM, 84 SEVERITY_HIGH, 85 86 SEVERITY_COUNT, 87 SEVERITY_ANY = -1 88 }; 89 90 static int 91 enum_to_index(GLenum e) 92 { 93 switch (e) { 94 case GL_DEBUG_SOURCE_APPLICATION_ARB: 95 return (int)SOURCE_APPLICATION; 96 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: 97 return (int)SOURCE_THIRD_PARTY; 98 99 case GL_DEBUG_TYPE_ERROR_ARB: 100 return (int)TYPE_ERROR; 101 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: 102 return (int)TYPE_DEPRECATED; 103 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: 104 return (int)TYPE_UNDEFINED; 105 case GL_DEBUG_TYPE_PERFORMANCE_ARB: 106 return (int)TYPE_PERFORMANCE; 107 case GL_DEBUG_TYPE_PORTABILITY_ARB: 108 return (int)TYPE_PORTABILITY; 109 case GL_DEBUG_TYPE_OTHER_ARB: 110 return (int)TYPE_OTHER; 111 112 case GL_DEBUG_SEVERITY_LOW_ARB: 113 return (int)SEVERITY_LOW; 114 case GL_DEBUG_SEVERITY_MEDIUM_ARB: 115 return (int)SEVERITY_MEDIUM; 116 case GL_DEBUG_SEVERITY_HIGH_ARB: 117 return (int)SEVERITY_HIGH; 118 119 case GL_DONT_CARE: 120 return (int)TYPE_ANY; 121 122 default: 123 assert(0 && "unreachable"); 124 return -2; 125 }; 126 } 127 128 129 /* 130 * We store a bitfield in the hash table, with five possible values total. 131 * 132 * The ENABLED_BIT's purpose is self-explanatory. 133 * 134 * The FOUND_BIT is needed to differentiate the value of DISABLED from 135 * the value returned by HashTableLookup() when it can't find the given key. 136 * 137 * The KNOWN_SEVERITY bit is a bit complicated: 138 * 139 * A client may call Control() with an array of IDs, then call Control() 140 * on all message IDs of a certain severity, then Insert() one of the 141 * previously specified IDs, giving us a known severity level, then call 142 * Control() on all message IDs of a certain severity level again. 143 * 144 * After the first call, those IDs will have a FOUND_BIT, but will not 145 * exist in any severity-specific list, so the second call will not 146 * impact them. This is undesirable but unavoidable given the API: 147 * The only entrypoint that gives a severity for a client-defined ID 148 * is the Insert() call. 149 * 150 * For the sake of Control(), we want to maintain the invariant 151 * that an ID will either appear in none of the three severity lists, 152 * or appear once, to minimize pointless duplication and potential surprises. 153 * 154 * Because Insert() is the only place that will learn an ID's severity, 155 * it should insert an ID into the appropriate list, but only if the ID 156 * doesn't exist in it or any other list yet. Because searching all three 157 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY. 158 */ 159 enum { 160 FOUND_BIT = 1 << 0, 161 ENABLED_BIT = 1 << 1, 162 KNOWN_SEVERITY = 1 << 2, 163 164 /* HashTable reserves zero as a return value meaning 'not found' */ 165 NOT_FOUND = 0, 166 DISABLED = FOUND_BIT, 167 ENABLED = ENABLED_BIT | FOUND_BIT 168 }; 169 170 /** 171 * Returns the state of the given message ID in a client-controlled 172 * namespace. 173 * 'source', 'type', and 'severity' are array indices like TYPE_ERROR, 174 * not GL enums. 175 */ 176 static GLboolean 177 get_message_state(struct gl_context *ctx, int source, int type, 178 GLuint id, int severity) 179 { 180 struct gl_client_namespace *nspace = 181 &ctx->Debug.ClientIDs.Namespaces[source][type]; 182 uintptr_t state; 183 184 /* In addition to not being able to store zero as a value, HashTable also 185 can't use zero as a key. */ 186 if (id) 187 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id); 188 else 189 state = nspace->ZeroID; 190 191 /* Only do this once for each ID. This makes sure the ID exists in, 192 at most, one list, and does not pointlessly appear multiple times. */ 193 if (!(state & KNOWN_SEVERITY)) { 194 struct gl_client_severity *entry; 195 196 if (state == NOT_FOUND) { 197 if (ctx->Debug.ClientIDs.Defaults[severity][source][type]) 198 state = ENABLED; 199 else 200 state = DISABLED; 201 } 202 203 entry = malloc(sizeof *entry); 204 if (!entry) 205 goto out; 206 207 state |= KNOWN_SEVERITY; 208 209 if (id) 210 _mesa_HashInsert(nspace->IDs, id, (void*)state); 211 else 212 nspace->ZeroID = state; 213 214 entry->ID = id; 215 insert_at_tail(&nspace->Severity[severity], &entry->link); 216 } 217 218 out: 219 return !!(state & ENABLED_BIT); 220 } 221 222 /** 223 * Sets the state of the given message ID in a client-controlled 224 * namespace. 225 * 'source' and 'type' are array indices like TYPE_ERROR, not GL enums. 226 */ 227 static void 228 set_message_state(struct gl_context *ctx, int source, int type, 229 GLuint id, GLboolean enabled) 230 { 231 struct gl_client_namespace *nspace = 232 &ctx->Debug.ClientIDs.Namespaces[source][type]; 233 uintptr_t state; 234 235 /* In addition to not being able to store zero as a value, HashTable also 236 can't use zero as a key. */ 237 if (id) 238 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id); 239 else 240 state = nspace->ZeroID; 241 242 if (state == NOT_FOUND) 243 state = enabled ? ENABLED : DISABLED; 244 else { 245 if (enabled) 246 state |= ENABLED_BIT; 247 else 248 state &= ~ENABLED_BIT; 249 } 250 251 if (id) 252 _mesa_HashInsert(nspace->IDs, id, (void*)state); 253 else 254 nspace->ZeroID = state; 255 } 256 257 /** 258 * Whether a debugging message should be logged or not. 259 * For implementation-controlled namespaces, we keep an array 260 * of booleans per namespace, per context, recording whether 261 * each individual message is enabled or not. The message ID 262 * is an index into the namespace's array. 263 */ 264 static GLboolean 265 should_log(struct gl_context *ctx, GLenum source, GLenum type, 266 GLuint id, GLenum severity) 267 { 268 if (source == GL_DEBUG_SOURCE_APPLICATION_ARB || 269 source == GL_DEBUG_SOURCE_THIRD_PARTY_ARB) { 270 int s, t, sev; 271 s = enum_to_index(source); 272 t = enum_to_index(type); 273 sev = enum_to_index(severity); 274 275 return get_message_state(ctx, s, t, sev, id); 276 } 277 278 if (type_is(type, ERROR)) { 279 if (source_is(source, API)) 280 return ctx->Debug.ApiErrors[id]; 281 if (source_is(source, WINDOW_SYSTEM)) 282 return ctx->Debug.WinsysErrors[id]; 283 if (source_is(source, SHADER_COMPILER)) 284 return ctx->Debug.ShaderErrors[id]; 285 if (source_is(source, OTHER)) 286 return ctx->Debug.OtherErrors[id]; 287 } 288 289 return (severity != GL_DEBUG_SEVERITY_LOW_ARB); 290 } 291 292 /** 293 * 'buf' is not necessarily a null-terminated string. When logging, copy 294 * 'len' characters from it, store them in a new, null-terminated string, 295 * and remember the number of bytes used by that string, *including* 296 * the null terminator this time. 297 */ 298 static void 299 _mesa_log_msg(struct gl_context *ctx, GLenum source, GLenum type, 300 GLuint id, GLenum severity, GLint len, const char *buf) 301 { 302 GLint nextEmpty; 303 struct gl_debug_msg *emptySlot; 304 305 assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH); 306 307 if (!should_log(ctx, source, type, id, severity)) 308 return; 309 310 if (ctx->Debug.Callback) { 311 ctx->Debug.Callback(source, type, id, severity, 312 len, buf, ctx->Debug.CallbackData); 313 return; 314 } 315 316 if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES) 317 return; 318 319 nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages) 320 % MAX_DEBUG_LOGGED_MESSAGES; 321 emptySlot = &ctx->Debug.Log[nextEmpty]; 322 323 assert(!emptySlot->message && !emptySlot->length); 324 325 emptySlot->message = MALLOC(len+1); 326 if (emptySlot->message) { 327 (void) strncpy(emptySlot->message, buf, (size_t)len); 328 emptySlot->message[len] = '\0'; 329 330 emptySlot->length = len+1; 331 emptySlot->source = source; 332 emptySlot->type = type; 333 emptySlot->id = id; 334 emptySlot->severity = severity; 335 } else { 336 /* malloc failed! */ 337 emptySlot->message = out_of_memory; 338 emptySlot->length = strlen(out_of_memory)+1; 339 emptySlot->source = GL_DEBUG_SOURCE_OTHER_ARB; 340 emptySlot->type = GL_DEBUG_TYPE_ERROR_ARB; 341 emptySlot->id = OTHER_ERROR_OUT_OF_MEMORY; 342 emptySlot->severity = GL_DEBUG_SEVERITY_HIGH_ARB; 343 } 344 345 if (ctx->Debug.NumMessages == 0) 346 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length; 347 348 ctx->Debug.NumMessages++; 349 } 350 351 /** 352 * Pop the oldest debug message out of the log. 353 * Writes the message string, including the null terminator, into 'buf', 354 * using up to 'bufSize' bytes. If 'bufSize' is too small, or 355 * if 'buf' is NULL, nothing is written. 356 * 357 * Returns the number of bytes written on success, or when 'buf' is NULL, 358 * the number that would have been written. A return value of 0 359 * indicates failure. 360 */ 361 static GLsizei 362 _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type, 363 GLuint *id, GLenum *severity, GLsizei bufSize, char *buf) 364 { 365 struct gl_debug_msg *msg; 366 GLsizei length; 367 368 if (ctx->Debug.NumMessages == 0) 369 return 0; 370 371 msg = &ctx->Debug.Log[ctx->Debug.NextMsg]; 372 length = msg->length; 373 374 assert(length > 0 && length == ctx->Debug.NextMsgLength); 375 376 if (bufSize < length && buf != NULL) 377 return 0; 378 379 if (severity) 380 *severity = msg->severity; 381 if (source) 382 *source = msg->source; 383 if (type) 384 *type = msg->type; 385 if (id) 386 *id = msg->id; 387 388 if (buf) { 389 assert(msg->message[length-1] == '\0'); 390 (void) strncpy(buf, msg->message, (size_t)length); 391 } 392 393 if (msg->message != (char*)out_of_memory) 394 FREE(msg->message); 395 msg->message = NULL; 396 msg->length = 0; 397 398 ctx->Debug.NumMessages--; 399 ctx->Debug.NextMsg++; 400 ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES; 401 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length; 402 403 return length; 404 } 405 406 /** 407 * Verify that source, type, and severity are valid enums. 408 * glDebugMessageInsertARB only accepts two values for 'source', 409 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE 410 * in any parameter, so handle those cases specially. 411 */ 412 static GLboolean 413 validate_params(struct gl_context *ctx, unsigned caller, 414 GLenum source, GLenum type, GLenum severity) 415 { 416 #define INSERT 1 417 #define CONTROL 2 418 switch(source) { 419 case GL_DEBUG_SOURCE_APPLICATION_ARB: 420 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: 421 break; 422 case GL_DEBUG_SOURCE_API_ARB: 423 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: 424 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: 425 case GL_DEBUG_SOURCE_OTHER_ARB: 426 if (caller != INSERT) 427 break; 428 case GL_DONT_CARE: 429 if (caller == CONTROL) 430 break; 431 default: 432 goto error; 433 } 434 435 switch(type) { 436 case GL_DEBUG_TYPE_ERROR_ARB: 437 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: 438 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: 439 case GL_DEBUG_TYPE_PERFORMANCE_ARB: 440 case GL_DEBUG_TYPE_PORTABILITY_ARB: 441 case GL_DEBUG_TYPE_OTHER_ARB: 442 break; 443 case GL_DONT_CARE: 444 if (caller == CONTROL) 445 break; 446 default: 447 goto error; 448 } 449 450 switch(severity) { 451 case GL_DEBUG_SEVERITY_HIGH_ARB: 452 case GL_DEBUG_SEVERITY_MEDIUM_ARB: 453 case GL_DEBUG_SEVERITY_LOW_ARB: 454 break; 455 case GL_DONT_CARE: 456 if (caller == CONTROL) 457 break; 458 default: 459 goto error; 460 } 461 return GL_TRUE; 462 463 error: 464 { 465 const char *callerstr; 466 if (caller == INSERT) 467 callerstr = "glDebugMessageInsertARB"; 468 else if (caller == CONTROL) 469 callerstr = "glDebugMessageControlARB"; 470 else 471 return GL_FALSE; 472 473 _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s" 474 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr, 475 source, type, severity); 476 } 477 return GL_FALSE; 478 } 479 480 static void GLAPIENTRY 481 _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id, 482 GLenum severity, GLint length, 483 const GLcharARB* buf) 484 { 485 GET_CURRENT_CONTEXT(ctx); 486 487 if (!validate_params(ctx, INSERT, source, type, severity)) 488 return; /* GL_INVALID_ENUM */ 489 490 if (length < 0) 491 length = strlen(buf); 492 493 if (length >= MAX_DEBUG_MESSAGE_LENGTH) { 494 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB" 495 "(length=%d, which is not less than " 496 "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length, 497 MAX_DEBUG_MESSAGE_LENGTH); 498 return; 499 } 500 501 _mesa_log_msg(ctx, source, type, id, severity, length, buf); 502 } 503 504 static GLuint GLAPIENTRY 505 _mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources, 506 GLenum* types, GLenum* ids, GLenum* severities, 507 GLsizei* lengths, GLcharARB* messageLog) 508 { 509 GET_CURRENT_CONTEXT(ctx); 510 GLuint ret; 511 512 if (!messageLog) 513 logSize = 0; 514 515 if (logSize < 0) { 516 _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB" 517 "(logSize=%d : logSize must not be negative)", logSize); 518 return 0; 519 } 520 521 for (ret = 0; ret < count; ret++) { 522 GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities, 523 logSize, messageLog); 524 if (!written) 525 break; 526 527 if (messageLog) { 528 messageLog += written; 529 logSize -= written; 530 } 531 if (lengths) { 532 *lengths = written; 533 lengths++; 534 } 535 536 if (severities) 537 severities++; 538 if (sources) 539 sources++; 540 if (types) 541 types++; 542 if (ids) 543 ids++; 544 } 545 546 return ret; 547 } 548 549 /** 550 * 'array' is an array representing a particular debugging-message namespace. 551 * I.e., the set of all API errors, or the set of all Shader Compiler errors. 552 * 'size' is the size of 'array'. 'count' is the size of 'ids', an array 553 * of indices into 'array'. All the elements of 'array' at the indices 554 * listed in 'ids' will be overwritten with the value of 'enabled'. 555 * 556 * If 'count' is zero, all elements in 'array' are overwritten with the 557 * value of 'enabled'. 558 */ 559 static void 560 control_messages(GLboolean *array, GLuint size, 561 GLsizei count, const GLuint *ids, GLboolean enabled) 562 { 563 GLsizei i; 564 565 if (!count) { 566 GLuint id; 567 for (id = 0; id < size; id++) { 568 array[id] = enabled; 569 } 570 return; 571 } 572 573 for (i = 0; i < count; i++) { 574 if (ids[i] >= size) { 575 /* XXX: The spec doesn't say what to do with a non-existent ID. */ 576 continue; 577 } 578 array[ids[i]] = enabled; 579 } 580 } 581 582 /** 583 * Set the state of all message IDs found in the given intersection 584 * of 'source', 'type', and 'severity'. Note that all three of these 585 * parameters are array indices, not the corresponding GL enums. 586 * 587 * This requires both setting the state of all previously seen message 588 * IDs in the hash table, and setting the default state for all 589 * applicable combinations of source/type/severity, so that all the 590 * yet-unknown message IDs that may be used in the future will be 591 * impacted as if they were already known. 592 */ 593 static void 594 control_app_messages_by_group(struct gl_context *ctx, int source, int type, 595 int severity, GLboolean enabled) 596 { 597 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs; 598 int s, t, sev, smax, tmax, sevmax; 599 600 if (source == SOURCE_ANY) { 601 source = 0; 602 smax = SOURCE_COUNT; 603 } else { 604 smax = source+1; 605 } 606 607 if (type == TYPE_ANY) { 608 type = 0; 609 tmax = TYPE_COUNT; 610 } else { 611 tmax = type+1; 612 } 613 614 if (severity == SEVERITY_ANY) { 615 severity = 0; 616 sevmax = SEVERITY_COUNT; 617 } else { 618 sevmax = severity+1; 619 } 620 621 for (sev = severity; sev < sevmax; sev++) 622 for (s = source; s < smax; s++) 623 for (t = type; t < tmax; t++) { 624 struct simple_node *node; 625 struct gl_client_severity *entry; 626 627 /* change the default for IDs we've never seen before. */ 628 ClientIDs->Defaults[sev][s][t] = enabled; 629 630 /* Now change the state of IDs we *have* seen... */ 631 foreach(node, &ClientIDs->Namespaces[s][t].Severity[sev]) { 632 entry = (struct gl_client_severity *)node; 633 set_message_state(ctx, s, t, entry->ID, enabled); 634 } 635 } 636 } 637 638 /** 639 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY 640 * require special handling, since the IDs in them are controlled by clients, 641 * not the OpenGL implementation. 642 * 643 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all 644 * the given IDs in the namespace defined by 'esource' and 'etype' 645 * will be affected. 646 * 647 * If 'count' is zero, this sets the state of all IDs that match 648 * the combination of 'esource', 'etype', and 'eseverity'. 649 */ 650 static void 651 control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype, 652 GLenum eseverity, GLsizei count, const GLuint *ids, 653 GLboolean enabled) 654 { 655 int source, type, severity; 656 GLsizei i; 657 658 source = enum_to_index(esource); 659 type = enum_to_index(etype); 660 severity = enum_to_index(eseverity); 661 662 if (count) 663 assert(severity == SEVERITY_ANY && type != TYPE_ANY 664 && source != SOURCE_ANY); 665 666 for (i = 0; i < count; i++) 667 set_message_state(ctx, source, type, ids[i], enabled); 668 669 if (count) 670 return; 671 672 control_app_messages_by_group(ctx, source, type, severity, enabled); 673 } 674 675 static void GLAPIENTRY 676 _mesa_DebugMessageControlARB(GLenum source, GLenum type, GLenum severity, 677 GLsizei count, const GLuint *ids, 678 GLboolean enabled) 679 { 680 GET_CURRENT_CONTEXT(ctx); 681 682 if (count < 0) { 683 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB" 684 "(count=%d : count must not be negative)", count); 685 return; 686 } 687 688 if (!validate_params(ctx, CONTROL, source, type, severity)) 689 return; /* GL_INVALID_ENUM */ 690 691 if (count && (severity != GL_DONT_CARE || type == GL_DONT_CARE 692 || source == GL_DONT_CARE)) { 693 _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB" 694 "(When passing an array of ids, severity must be" 695 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE."); 696 return; 697 } 698 699 if (source_is(source, APPLICATION) || source_is(source, THIRD_PARTY)) 700 control_app_messages(ctx, source, type, severity, count, ids, enabled); 701 702 if (severity_is(severity, HIGH)) { 703 if (type_is(type, ERROR)) { 704 if (source_is(source, API)) 705 control_messages(ctx->Debug.ApiErrors, API_ERROR_COUNT, 706 count, ids, enabled); 707 if (source_is(source, WINDOW_SYSTEM)) 708 control_messages(ctx->Debug.WinsysErrors, WINSYS_ERROR_COUNT, 709 count, ids, enabled); 710 if (source_is(source, SHADER_COMPILER)) 711 control_messages(ctx->Debug.ShaderErrors, SHADER_ERROR_COUNT, 712 count, ids, enabled); 713 if (source_is(source, OTHER)) 714 control_messages(ctx->Debug.OtherErrors, OTHER_ERROR_COUNT, 715 count, ids, enabled); 716 } 717 } 718 } 719 720 static void GLAPIENTRY 721 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const GLvoid *userParam) 722 { 723 GET_CURRENT_CONTEXT(ctx); 724 ctx->Debug.Callback = callback; 725 ctx->Debug.CallbackData = (void *) userParam; 726 } 727 728 void 729 _mesa_init_errors_dispatch(struct _glapi_table *disp) 730 { 731 SET_DebugMessageCallbackARB(disp, _mesa_DebugMessageCallbackARB); 732 SET_DebugMessageControlARB(disp, _mesa_DebugMessageControlARB); 733 SET_DebugMessageInsertARB(disp, _mesa_DebugMessageInsertARB); 734 SET_GetDebugMessageLogARB(disp, _mesa_GetDebugMessageLogARB); 735 } 736 737 void 738 _mesa_init_errors(struct gl_context *ctx) 739 { 740 int s, t, sev; 741 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs; 742 743 ctx->Debug.Callback = NULL; 744 ctx->Debug.SyncOutput = GL_FALSE; 745 ctx->Debug.Log[0].length = 0; 746 ctx->Debug.NumMessages = 0; 747 ctx->Debug.NextMsg = 0; 748 ctx->Debug.NextMsgLength = 0; 749 750 /* Enable all the messages with severity HIGH or MEDIUM by default. */ 751 memset(ctx->Debug.ApiErrors, GL_TRUE, sizeof ctx->Debug.ApiErrors); 752 memset(ctx->Debug.WinsysErrors, GL_TRUE, sizeof ctx->Debug.WinsysErrors); 753 memset(ctx->Debug.ShaderErrors, GL_TRUE, sizeof ctx->Debug.ShaderErrors); 754 memset(ctx->Debug.OtherErrors, GL_TRUE, sizeof ctx->Debug.OtherErrors); 755 memset(ClientIDs->Defaults[SEVERITY_HIGH], GL_TRUE, 756 sizeof ClientIDs->Defaults[SEVERITY_HIGH]); 757 memset(ClientIDs->Defaults[SEVERITY_MEDIUM], GL_TRUE, 758 sizeof ClientIDs->Defaults[SEVERITY_MEDIUM]); 759 memset(ClientIDs->Defaults[SEVERITY_LOW], GL_FALSE, 760 sizeof ClientIDs->Defaults[SEVERITY_LOW]); 761 762 /* Initialize state for filtering client-provided debug messages. */ 763 for (s = 0; s < SOURCE_COUNT; s++) 764 for (t = 0; t < TYPE_COUNT; t++) { 765 ClientIDs->Namespaces[s][t].IDs = _mesa_NewHashTable(); 766 assert(ClientIDs->Namespaces[s][t].IDs); 767 768 for (sev = 0; sev < SEVERITY_COUNT; sev++) 769 make_empty_list(&ClientIDs->Namespaces[s][t].Severity[sev]); 770 } 771 } 772 773 void 774 _mesa_free_errors_data(struct gl_context *ctx) 775 { 776 int s, t, sev; 777 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs; 778 779 /* Tear down state for filtering client-provided debug messages. */ 780 for (s = 0; s < SOURCE_COUNT; s++) 781 for (t = 0; t < TYPE_COUNT; t++) { 782 _mesa_DeleteHashTable(ClientIDs->Namespaces[s][t].IDs); 783 for (sev = 0; sev < SEVERITY_COUNT; sev++) { 784 struct simple_node *node, *tmp; 785 struct gl_client_severity *entry; 786 787 foreach_s(node, tmp, &ClientIDs->Namespaces[s][t].Severity[sev]) { 788 entry = (struct gl_client_severity *)node; 789 FREE(entry); 790 } 791 } 792 } 793 } 794 795 /**********************************************************************/ 796 /** \name Diagnostics */ 797 /*@{*/ 798 799 static void 800 output_if_debug(const char *prefixString, const char *outputString, 801 GLboolean newline) 802 { 803 static int debug = -1; 804 static FILE *fout = NULL; 805 806 /* Init the local 'debug' var once. 807 * Note: the _mesa_init_debug() function should have been called 808 * by now so MESA_DEBUG_FLAGS will be initialized. 809 */ 810 if (debug == -1) { 811 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings, 812 * etc to the named file. Otherwise, output to stderr. 813 */ 814 const char *logFile = _mesa_getenv("MESA_LOG_FILE"); 815 if (logFile) 816 fout = fopen(logFile, "w"); 817 if (!fout) 818 fout = stderr; 819 #ifdef DEBUG 820 /* in debug builds, print messages unless MESA_DEBUG="silent" */ 821 if (MESA_DEBUG_FLAGS & DEBUG_SILENT) 822 debug = 0; 823 else 824 debug = 1; 825 #else 826 /* in release builds, be silent unless MESA_DEBUG is set */ 827 debug = _mesa_getenv("MESA_DEBUG") != NULL; 828 #endif 829 } 830 831 /* Now only print the string if we're required to do so. */ 832 if (debug) { 833 fprintf(fout, "%s: %s", prefixString, outputString); 834 if (newline) 835 fprintf(fout, "\n"); 836 fflush(fout); 837 838 #if defined(_WIN32) && !defined(_WIN32_WCE) 839 /* stderr from windows applications without console is not usually 840 * visible, so communicate with the debugger instead */ 841 { 842 char buf[4096]; 843 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : ""); 844 OutputDebugStringA(buf); 845 } 846 #endif 847 } 848 } 849 850 851 /** 852 * Return string version of GL error code. 853 */ 854 static const char * 855 error_string( GLenum error ) 856 { 857 switch (error) { 858 case GL_NO_ERROR: 859 return "GL_NO_ERROR"; 860 case GL_INVALID_VALUE: 861 return "GL_INVALID_VALUE"; 862 case GL_INVALID_ENUM: 863 return "GL_INVALID_ENUM"; 864 case GL_INVALID_OPERATION: 865 return "GL_INVALID_OPERATION"; 866 case GL_STACK_OVERFLOW: 867 return "GL_STACK_OVERFLOW"; 868 case GL_STACK_UNDERFLOW: 869 return "GL_STACK_UNDERFLOW"; 870 case GL_OUT_OF_MEMORY: 871 return "GL_OUT_OF_MEMORY"; 872 case GL_TABLE_TOO_LARGE: 873 return "GL_TABLE_TOO_LARGE"; 874 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: 875 return "GL_INVALID_FRAMEBUFFER_OPERATION"; 876 default: 877 return "unknown"; 878 } 879 } 880 881 882 /** 883 * When a new type of error is recorded, print a message describing 884 * previous errors which were accumulated. 885 */ 886 static void 887 flush_delayed_errors( struct gl_context *ctx ) 888 { 889 char s[MAXSTRING]; 890 891 if (ctx->ErrorDebugCount) { 892 _mesa_snprintf(s, MAXSTRING, "%d similar %s errors", 893 ctx->ErrorDebugCount, 894 error_string(ctx->ErrorValue)); 895 896 output_if_debug("Mesa", s, GL_TRUE); 897 898 ctx->ErrorDebugCount = 0; 899 } 900 } 901 902 903 /** 904 * Report a warning (a recoverable error condition) to stderr if 905 * either DEBUG is defined or the MESA_DEBUG env var is set. 906 * 907 * \param ctx GL context. 908 * \param fmtString printf()-like format string. 909 */ 910 void 911 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... ) 912 { 913 char str[MAXSTRING]; 914 va_list args; 915 va_start( args, fmtString ); 916 (void) _mesa_vsnprintf( str, MAXSTRING, fmtString, args ); 917 va_end( args ); 918 919 if (ctx) 920 flush_delayed_errors( ctx ); 921 922 output_if_debug("Mesa warning", str, GL_TRUE); 923 } 924 925 926 /** 927 * Report an internal implementation problem. 928 * Prints the message to stderr via fprintf(). 929 * 930 * \param ctx GL context. 931 * \param fmtString problem description string. 932 */ 933 void 934 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) 935 { 936 va_list args; 937 char str[MAXSTRING]; 938 static int numCalls = 0; 939 940 (void) ctx; 941 942 if (numCalls < 50) { 943 numCalls++; 944 945 va_start( args, fmtString ); 946 _mesa_vsnprintf( str, MAXSTRING, fmtString, args ); 947 va_end( args ); 948 fprintf(stderr, "Mesa %s implementation error: %s\n", 949 MESA_VERSION_STRING, str); 950 fprintf(stderr, "Please report at bugs.freedesktop.org\n"); 951 } 952 } 953 954 static GLboolean 955 should_output(struct gl_context *ctx, GLenum error, const char *fmtString) 956 { 957 static GLint debug = -1; 958 959 /* Check debug environment variable only once: 960 */ 961 if (debug == -1) { 962 const char *debugEnv = _mesa_getenv("MESA_DEBUG"); 963 964 #ifdef DEBUG 965 if (debugEnv && strstr(debugEnv, "silent")) 966 debug = GL_FALSE; 967 else 968 debug = GL_TRUE; 969 #else 970 if (debugEnv) 971 debug = GL_TRUE; 972 else 973 debug = GL_FALSE; 974 #endif 975 } 976 977 if (debug) { 978 if (ctx->ErrorValue != error || 979 ctx->ErrorDebugFmtString != fmtString) { 980 flush_delayed_errors( ctx ); 981 ctx->ErrorDebugFmtString = fmtString; 982 ctx->ErrorDebugCount = 0; 983 return GL_TRUE; 984 } 985 ctx->ErrorDebugCount++; 986 } 987 return GL_FALSE; 988 } 989 990 991 /** 992 * Record an OpenGL state error. These usually occur when the user 993 * passes invalid parameters to a GL function. 994 * 995 * If debugging is enabled (either at compile-time via the DEBUG macro, or 996 * run-time via the MESA_DEBUG environment variable), report the error with 997 * _mesa_debug(). 998 * 999 * \param ctx the GL context. 1000 * \param error the error value. 1001 * \param fmtString printf() style format string, followed by optional args 1002 */ 1003 void 1004 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) 1005 { 1006 GLboolean do_output, do_log; 1007 1008 do_output = should_output(ctx, error, fmtString); 1009 do_log = should_log(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB, 1010 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB); 1011 1012 if (do_output || do_log) { 1013 char s[MAXSTRING], s2[MAXSTRING]; 1014 int len; 1015 va_list args; 1016 1017 va_start(args, fmtString); 1018 len = _mesa_vsnprintf(s, MAXSTRING, fmtString, args); 1019 va_end(args); 1020 1021 if (len >= MAXSTRING) { 1022 /* Too long error message. Whoever calls _mesa_error should use 1023 * shorter strings. */ 1024 ASSERT(0); 1025 return; 1026 } 1027 1028 len = _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s); 1029 if (len >= MAXSTRING) { 1030 /* Same as above. */ 1031 ASSERT(0); 1032 return; 1033 } 1034 1035 /* Print the error to stderr if needed. */ 1036 if (do_output) { 1037 output_if_debug("Mesa: User error", s2, GL_TRUE); 1038 } 1039 1040 /* Log the error via ARB_debug_output if needed.*/ 1041 if (do_log) { 1042 _mesa_log_msg(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB, 1043 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB, len, s2); 1044 } 1045 } 1046 1047 /* Set the GL context error state for glGetError. */ 1048 _mesa_record_error(ctx, error); 1049 } 1050 1051 1052 /** 1053 * Report debug information. Print error message to stderr via fprintf(). 1054 * No-op if DEBUG mode not enabled. 1055 * 1056 * \param ctx GL context. 1057 * \param fmtString printf()-style format string, followed by optional args. 1058 */ 1059 void 1060 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) 1061 { 1062 #ifdef DEBUG 1063 char s[MAXSTRING]; 1064 va_list args; 1065 va_start(args, fmtString); 1066 _mesa_vsnprintf(s, MAXSTRING, fmtString, args); 1067 va_end(args); 1068 output_if_debug("Mesa", s, GL_FALSE); 1069 #endif /* DEBUG */ 1070 (void) ctx; 1071 (void) fmtString; 1072 } 1073 1074 1075 /** 1076 * Report debug information from the shader compiler via GL_ARB_debug_output. 1077 * 1078 * \param ctx GL context. 1079 * \param type The namespace to which this message belongs. 1080 * \param id The message ID within the given namespace. 1081 * \param msg The message to output. Need not be null-terminated. 1082 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated. 1083 */ 1084 void 1085 _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint id, 1086 const char *msg, int len ) 1087 { 1088 GLenum source = GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, 1089 severity; 1090 1091 switch (type) { 1092 case GL_DEBUG_TYPE_ERROR_ARB: 1093 assert(id < SHADER_ERROR_COUNT); 1094 severity = GL_DEBUG_SEVERITY_HIGH_ARB; 1095 break; 1096 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: 1097 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: 1098 case GL_DEBUG_TYPE_PORTABILITY_ARB: 1099 case GL_DEBUG_TYPE_PERFORMANCE_ARB: 1100 case GL_DEBUG_TYPE_OTHER_ARB: 1101 assert(0 && "other categories not implemented yet"); 1102 default: 1103 _mesa_problem(ctx, "bad enum in _mesa_shader_debug()"); 1104 return; 1105 } 1106 1107 if (len < 0) 1108 len = strlen(msg); 1109 1110 /* Truncate the message if necessary. */ 1111 if (len >= MAX_DEBUG_MESSAGE_LENGTH) 1112 len = MAX_DEBUG_MESSAGE_LENGTH - 1; 1113 1114 _mesa_log_msg(ctx, source, type, id, severity, len, msg); 1115 } 1116 1117 /*@}*/ 1118