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
enum_to_index(GLenum e)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
get_message_state(struct gl_context * ctx,int source,int type,GLuint id,int severity)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
set_message_state(struct gl_context * ctx,int source,int type,GLuint id,GLboolean enabled)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
should_log(struct gl_context * ctx,GLenum source,GLenum type,GLuint id,GLenum severity)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
_mesa_log_msg(struct gl_context * ctx,GLenum source,GLenum type,GLuint id,GLenum severity,GLint len,const char * buf)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
_mesa_get_msg(struct gl_context * ctx,GLenum * source,GLenum * type,GLuint * id,GLenum * severity,GLsizei bufSize,char * buf)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
validate_params(struct gl_context * ctx,unsigned caller,GLenum source,GLenum type,GLenum severity)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
_mesa_DebugMessageInsertARB(GLenum source,GLenum type,GLuint id,GLenum severity,GLint length,const GLcharARB * buf)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
_mesa_GetDebugMessageLogARB(GLuint count,GLsizei logSize,GLenum * sources,GLenum * types,GLenum * ids,GLenum * severities,GLsizei * lengths,GLcharARB * messageLog)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
control_messages(GLboolean * array,GLuint size,GLsizei count,const GLuint * ids,GLboolean enabled)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
control_app_messages_by_group(struct gl_context * ctx,int source,int type,int severity,GLboolean enabled)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
control_app_messages(struct gl_context * ctx,GLenum esource,GLenum etype,GLenum eseverity,GLsizei count,const GLuint * ids,GLboolean enabled)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
_mesa_DebugMessageControlARB(GLenum source,GLenum type,GLenum severity,GLsizei count,const GLuint * ids,GLboolean enabled)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
_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback,const GLvoid * userParam)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
_mesa_init_errors_dispatch(struct _glapi_table * disp)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
_mesa_init_errors(struct gl_context * ctx)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
_mesa_free_errors_data(struct gl_context * ctx)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
output_if_debug(const char * prefixString,const char * outputString,GLboolean newline)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 *
error_string(GLenum error)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
flush_delayed_errors(struct gl_context * ctx)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
_mesa_warning(struct gl_context * ctx,const char * fmtString,...)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
_mesa_problem(const struct gl_context * ctx,const char * fmtString,...)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
should_output(struct gl_context * ctx,GLenum error,const char * fmtString)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
_mesa_error(struct gl_context * ctx,GLenum error,const char * fmtString,...)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
_mesa_debug(const struct gl_context * ctx,const char * fmtString,...)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
_mesa_shader_debug(struct gl_context * ctx,GLenum type,GLuint id,const char * msg,int len)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