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