gallium: expose a debug message callback settable by context owner
[mesa.git] / src / gallium / auxiliary / util / u_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright (c) 2008 VMware, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29
30 #include "pipe/p_config.h"
31
32 #include "pipe/p_compiler.h"
33 #include "util/u_debug.h"
34 #include "pipe/p_format.h"
35 #include "pipe/p_state.h"
36 #include "util/u_inlines.h"
37 #include "util/u_format.h"
38 #include "util/u_memory.h"
39 #include "util/u_string.h"
40 #include "util/u_math.h"
41 #include "util/u_tile.h"
42 #include "util/u_prim.h"
43 #include "util/u_surface.h"
44 #include <inttypes.h>
45
46 #include <stdio.h>
47 #include <limits.h> /* CHAR_BIT */
48 #include <ctype.h> /* isalnum */
49
50 #ifdef _WIN32
51 #include <windows.h>
52 #include <stdlib.h>
53 #endif
54
55
56 void _debug_vprintf(const char *format, va_list ap)
57 {
58 static char buf[4096] = {'\0'};
59 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
60 /* We buffer until we find a newline. */
61 size_t len = strlen(buf);
62 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
63 if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
64 os_log_message(buf);
65 buf[0] = '\0';
66 }
67 #else
68 util_vsnprintf(buf, sizeof(buf), format, ap);
69 os_log_message(buf);
70 #endif
71 }
72
73 void
74 _pipe_debug_message(
75 struct pipe_debug_callback *cb,
76 unsigned *id,
77 enum pipe_debug_type type,
78 const char *fmt, ...)
79 {
80 va_list args;
81 va_start(args, fmt);
82 if (cb && cb->debug_message)
83 cb->debug_message(cb->data, id, type, fmt, args);
84 va_end(args);
85 }
86
87
88 void
89 debug_disable_error_message_boxes(void)
90 {
91 #ifdef _WIN32
92 /* When Windows' error message boxes are disabled for this process (as is
93 * typically the case when running tests in an automated fashion) we disable
94 * CRT message boxes too.
95 */
96 UINT uMode = SetErrorMode(0);
97 SetErrorMode(uMode);
98 if (uMode & SEM_FAILCRITICALERRORS) {
99 /* Disable assertion failure message box.
100 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
101 */
102 _set_error_mode(_OUT_TO_STDERR);
103 #ifdef _MSC_VER
104 /* Disable abort message box.
105 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
106 */
107 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
108 #endif
109 }
110 #endif /* _WIN32 */
111 }
112
113
114 #ifdef DEBUG
115 void debug_print_blob( const char *name,
116 const void *blob,
117 unsigned size )
118 {
119 const unsigned *ublob = (const unsigned *)blob;
120 unsigned i;
121
122 debug_printf("%s (%d dwords%s)\n", name, size/4,
123 size%4 ? "... plus a few bytes" : "");
124
125 for (i = 0; i < size/4; i++) {
126 debug_printf("%d:\t%08x\n", i, ublob[i]);
127 }
128 }
129 #endif
130
131
132 static boolean
133 debug_get_option_should_print(void)
134 {
135 static boolean first = TRUE;
136 static boolean value = FALSE;
137
138 if (!first)
139 return value;
140
141 /* Oh hey this will call into this function,
142 * but its cool since we set first to false
143 */
144 first = FALSE;
145 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
146 /* XXX should we print this option? Currently it wont */
147 return value;
148 }
149
150 const char *
151 debug_get_option(const char *name, const char *dfault)
152 {
153 const char *result;
154
155 result = os_get_option(name);
156 if(!result)
157 result = dfault;
158
159 if (debug_get_option_should_print())
160 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
161
162 return result;
163 }
164
165 boolean
166 debug_get_bool_option(const char *name, boolean dfault)
167 {
168 const char *str = os_get_option(name);
169 boolean result;
170
171 if(str == NULL)
172 result = dfault;
173 else if(!util_strcmp(str, "n"))
174 result = FALSE;
175 else if(!util_strcmp(str, "no"))
176 result = FALSE;
177 else if(!util_strcmp(str, "0"))
178 result = FALSE;
179 else if(!util_strcmp(str, "f"))
180 result = FALSE;
181 else if(!util_strcmp(str, "F"))
182 result = FALSE;
183 else if(!util_strcmp(str, "false"))
184 result = FALSE;
185 else if(!util_strcmp(str, "FALSE"))
186 result = FALSE;
187 else
188 result = TRUE;
189
190 if (debug_get_option_should_print())
191 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
192
193 return result;
194 }
195
196
197 long
198 debug_get_num_option(const char *name, long dfault)
199 {
200 long result;
201 const char *str;
202
203 str = os_get_option(name);
204 if(!str)
205 result = dfault;
206 else {
207 long sign;
208 char c;
209 c = *str++;
210 if(c == '-') {
211 sign = -1;
212 c = *str++;
213 }
214 else {
215 sign = 1;
216 }
217 result = 0;
218 while('0' <= c && c <= '9') {
219 result = result*10 + (c - '0');
220 c = *str++;
221 }
222 result *= sign;
223 }
224
225 if (debug_get_option_should_print())
226 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
227
228 return result;
229 }
230
231 static boolean str_has_option(const char *str, const char *name)
232 {
233 /* Empty string. */
234 if (!*str) {
235 return FALSE;
236 }
237
238 /* OPTION=all */
239 if (!util_strcmp(str, "all")) {
240 return TRUE;
241 }
242
243 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
244 {
245 const char *start = str;
246 unsigned name_len = strlen(name);
247
248 /* 'start' is the beginning of the currently-parsed word,
249 * we increment 'str' each iteration.
250 * if we find either the end of string or a non-alphanumeric character,
251 * we compare 'start' up to 'str-1' with 'name'. */
252
253 while (1) {
254 if (!*str || !(isalnum(*str) || *str == '_')) {
255 if (str-start == name_len &&
256 !memcmp(start, name, name_len)) {
257 return TRUE;
258 }
259
260 if (!*str) {
261 return FALSE;
262 }
263
264 start = str+1;
265 }
266
267 str++;
268 }
269 }
270
271 return FALSE;
272 }
273
274 uint64_t
275 debug_get_flags_option(const char *name,
276 const struct debug_named_value *flags,
277 uint64_t dfault)
278 {
279 uint64_t result;
280 const char *str;
281 const struct debug_named_value *orig = flags;
282 unsigned namealign = 0;
283
284 str = os_get_option(name);
285 if(!str)
286 result = dfault;
287 else if (!util_strcmp(str, "help")) {
288 result = dfault;
289 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
290 for (; flags->name; ++flags)
291 namealign = MAX2(namealign, strlen(flags->name));
292 for (flags = orig; flags->name; ++flags)
293 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
294 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
295 flags->desc ? " " : "", flags->desc ? flags->desc : "");
296 }
297 else {
298 result = 0;
299 while( flags->name ) {
300 if (str_has_option(str, flags->name))
301 result |= flags->value;
302 ++flags;
303 }
304 }
305
306 if (debug_get_option_should_print()) {
307 if (str) {
308 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n", __FUNCTION__, name, result, str);
309 } else {
310 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
311 }
312 }
313
314 return result;
315 }
316
317
318 void _debug_assert_fail(const char *expr,
319 const char *file,
320 unsigned line,
321 const char *function)
322 {
323 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
324 os_abort();
325 }
326
327
328 const char *
329 debug_dump_enum(const struct debug_named_value *names,
330 unsigned long value)
331 {
332 static char rest[64];
333
334 while(names->name) {
335 if(names->value == value)
336 return names->name;
337 ++names;
338 }
339
340 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
341 return rest;
342 }
343
344
345 const char *
346 debug_dump_enum_noprefix(const struct debug_named_value *names,
347 const char *prefix,
348 unsigned long value)
349 {
350 static char rest[64];
351
352 while(names->name) {
353 if(names->value == value) {
354 const char *name = names->name;
355 while (*name == *prefix) {
356 name++;
357 prefix++;
358 }
359 return name;
360 }
361 ++names;
362 }
363
364
365
366 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
367 return rest;
368 }
369
370
371 const char *
372 debug_dump_flags(const struct debug_named_value *names,
373 unsigned long value)
374 {
375 static char output[4096];
376 static char rest[256];
377 int first = 1;
378
379 output[0] = '\0';
380
381 while(names->name) {
382 if((names->value & value) == names->value) {
383 if (!first)
384 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
385 else
386 first = 0;
387 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
388 output[sizeof(output) - 1] = '\0';
389 value &= ~names->value;
390 }
391 ++names;
392 }
393
394 if (value) {
395 if (!first)
396 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
397 else
398 first = 0;
399
400 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
401 util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
402 output[sizeof(output) - 1] = '\0';
403 }
404
405 if(first)
406 return "0";
407
408 return output;
409 }
410
411
412 #ifdef DEBUG
413 void debug_print_format(const char *msg, unsigned fmt )
414 {
415 debug_printf("%s: %s\n", msg, util_format_name(fmt));
416 }
417 #endif
418
419
420 /** Return string name of given primitive type */
421 const char *
422 u_prim_name(unsigned prim)
423 {
424 static const struct debug_named_value names[] = {
425 DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
426 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
427 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
428 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
429 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
430 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
431 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
432 DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
433 DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
434 DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
435 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES_ADJACENCY),
436 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP_ADJACENCY),
437 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES_ADJACENCY),
438 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY),
439 DEBUG_NAMED_VALUE_END
440 };
441 return debug_dump_enum(names, prim);
442 }
443
444
445
446 #ifdef DEBUG
447 int fl_indent = 0;
448 const char* fl_function[1024];
449
450 int debug_funclog_enter(const char* f, const int line, const char* file)
451 {
452 int i;
453
454 for (i = 0; i < fl_indent; i++)
455 debug_printf(" ");
456 debug_printf("%s\n", f);
457
458 assert(fl_indent < 1023);
459 fl_function[fl_indent++] = f;
460
461 return 0;
462 }
463
464 void debug_funclog_exit(const char* f, const int line, const char* file)
465 {
466 --fl_indent;
467 assert(fl_indent >= 0);
468 assert(fl_function[fl_indent] == f);
469 }
470
471 void debug_funclog_enter_exit(const char* f, const int line, const char* file)
472 {
473 int i;
474 for (i = 0; i < fl_indent; i++)
475 debug_printf(" ");
476 debug_printf("%s\n", f);
477 }
478 #endif
479
480
481
482 #ifdef DEBUG
483 /**
484 * Dump an image to .ppm file.
485 * \param format PIPE_FORMAT_x
486 * \param cpp bytes per pixel
487 * \param width width in pixels
488 * \param height height in pixels
489 * \param stride row stride in bytes
490 */
491 void debug_dump_image(const char *prefix,
492 enum pipe_format format, unsigned cpp,
493 unsigned width, unsigned height,
494 unsigned stride,
495 const void *data)
496 {
497 /* write a ppm file */
498 char filename[256];
499 unsigned char *rgb8;
500 FILE *f;
501
502 util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
503
504 rgb8 = MALLOC(height * width * 3);
505 if (!rgb8) {
506 return;
507 }
508
509 util_format_translate(
510 PIPE_FORMAT_R8G8B8_UNORM,
511 rgb8, width * 3,
512 0, 0,
513 format,
514 data, stride,
515 0, 0, width, height);
516
517 /* Must be opened in binary mode or DOS line ending causes data
518 * to be read with one byte offset.
519 */
520 f = fopen(filename, "wb");
521 if (f) {
522 fprintf(f, "P6\n");
523 fprintf(f, "# ppm-file created by gallium\n");
524 fprintf(f, "%i %i\n", width, height);
525 fprintf(f, "255\n");
526 fwrite(rgb8, 1, height * width * 3, f);
527 fclose(f);
528 }
529 else {
530 fprintf(stderr, "Can't open %s for writing\n", filename);
531 }
532
533 FREE(rgb8);
534 }
535
536 /* FIXME: dump resources, not surfaces... */
537 void debug_dump_surface(struct pipe_context *pipe,
538 const char *prefix,
539 struct pipe_surface *surface)
540 {
541 struct pipe_resource *texture;
542 struct pipe_transfer *transfer;
543 void *data;
544
545 if (!surface)
546 return;
547
548 /* XXX: this doesn't necessarily work, as the driver may be using
549 * temporary storage for the surface which hasn't been propagated
550 * back into the texture. Need to nail down the semantics of views
551 * and transfers a bit better before we can say if extra work needs
552 * to be done here:
553 */
554 texture = surface->texture;
555
556 data = pipe_transfer_map(pipe, texture, surface->u.tex.level,
557 surface->u.tex.first_layer,
558 PIPE_TRANSFER_READ,
559 0, 0, surface->width, surface->height, &transfer);
560 if(!data)
561 return;
562
563 debug_dump_image(prefix,
564 texture->format,
565 util_format_get_blocksize(texture->format),
566 util_format_get_nblocksx(texture->format, surface->width),
567 util_format_get_nblocksy(texture->format, surface->height),
568 transfer->stride,
569 data);
570
571 pipe->transfer_unmap(pipe, transfer);
572 }
573
574
575 void debug_dump_texture(struct pipe_context *pipe,
576 const char *prefix,
577 struct pipe_resource *texture)
578 {
579 struct pipe_surface *surface, surf_tmpl;
580
581 if (!texture)
582 return;
583
584 /* XXX for now, just dump image for layer=0, level=0 */
585 u_surface_default_template(&surf_tmpl, texture);
586 surface = pipe->create_surface(pipe, texture, &surf_tmpl);
587 if (surface) {
588 debug_dump_surface(pipe, prefix, surface);
589 pipe->surface_destroy(pipe, surface);
590 }
591 }
592
593
594 #pragma pack(push,2)
595 struct bmp_file_header {
596 uint16_t bfType;
597 uint32_t bfSize;
598 uint16_t bfReserved1;
599 uint16_t bfReserved2;
600 uint32_t bfOffBits;
601 };
602 #pragma pack(pop)
603
604 struct bmp_info_header {
605 uint32_t biSize;
606 int32_t biWidth;
607 int32_t biHeight;
608 uint16_t biPlanes;
609 uint16_t biBitCount;
610 uint32_t biCompression;
611 uint32_t biSizeImage;
612 int32_t biXPelsPerMeter;
613 int32_t biYPelsPerMeter;
614 uint32_t biClrUsed;
615 uint32_t biClrImportant;
616 };
617
618 struct bmp_rgb_quad {
619 uint8_t rgbBlue;
620 uint8_t rgbGreen;
621 uint8_t rgbRed;
622 uint8_t rgbAlpha;
623 };
624
625 void
626 debug_dump_surface_bmp(struct pipe_context *pipe,
627 const char *filename,
628 struct pipe_surface *surface)
629 {
630 struct pipe_transfer *transfer;
631 struct pipe_resource *texture = surface->texture;
632 void *ptr;
633
634 ptr = pipe_transfer_map(pipe, texture, surface->u.tex.level,
635 surface->u.tex.first_layer, PIPE_TRANSFER_READ,
636 0, 0, surface->width, surface->height, &transfer);
637
638 debug_dump_transfer_bmp(pipe, filename, transfer, ptr);
639
640 pipe->transfer_unmap(pipe, transfer);
641 }
642
643 void
644 debug_dump_transfer_bmp(struct pipe_context *pipe,
645 const char *filename,
646 struct pipe_transfer *transfer, void *ptr)
647 {
648 float *rgba;
649
650 if (!transfer)
651 goto error1;
652
653 rgba = MALLOC(transfer->box.width *
654 transfer->box.height *
655 transfer->box.depth *
656 4*sizeof(float));
657 if(!rgba)
658 goto error1;
659
660 pipe_get_tile_rgba(transfer, ptr, 0, 0,
661 transfer->box.width, transfer->box.height,
662 rgba);
663
664 debug_dump_float_rgba_bmp(filename,
665 transfer->box.width, transfer->box.height,
666 rgba, transfer->box.width);
667
668 FREE(rgba);
669 error1:
670 ;
671 }
672
673 void
674 debug_dump_float_rgba_bmp(const char *filename,
675 unsigned width, unsigned height,
676 float *rgba, unsigned stride)
677 {
678 FILE *stream;
679 struct bmp_file_header bmfh;
680 struct bmp_info_header bmih;
681 unsigned x, y;
682
683 if(!rgba)
684 goto error1;
685
686 bmfh.bfType = 0x4d42;
687 bmfh.bfSize = 14 + 40 + height*width*4;
688 bmfh.bfReserved1 = 0;
689 bmfh.bfReserved2 = 0;
690 bmfh.bfOffBits = 14 + 40;
691
692 bmih.biSize = 40;
693 bmih.biWidth = width;
694 bmih.biHeight = height;
695 bmih.biPlanes = 1;
696 bmih.biBitCount = 32;
697 bmih.biCompression = 0;
698 bmih.biSizeImage = height*width*4;
699 bmih.biXPelsPerMeter = 0;
700 bmih.biYPelsPerMeter = 0;
701 bmih.biClrUsed = 0;
702 bmih.biClrImportant = 0;
703
704 stream = fopen(filename, "wb");
705 if(!stream)
706 goto error1;
707
708 fwrite(&bmfh, 14, 1, stream);
709 fwrite(&bmih, 40, 1, stream);
710
711 y = height;
712 while(y--) {
713 float *ptr = rgba + (stride * y * 4);
714 for(x = 0; x < width; ++x)
715 {
716 struct bmp_rgb_quad pixel;
717 pixel.rgbRed = float_to_ubyte(ptr[x*4 + 0]);
718 pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
719 pixel.rgbBlue = float_to_ubyte(ptr[x*4 + 2]);
720 pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
721 fwrite(&pixel, 1, 4, stream);
722 }
723 }
724
725 fclose(stream);
726 error1:
727 ;
728 }
729
730
731 /**
732 * Print PIPE_TRANSFER_x flags with a message.
733 */
734 void
735 debug_print_transfer_flags(const char *msg, unsigned usage)
736 {
737 static const struct debug_named_value names[] = {
738 DEBUG_NAMED_VALUE(PIPE_TRANSFER_READ),
739 DEBUG_NAMED_VALUE(PIPE_TRANSFER_WRITE),
740 DEBUG_NAMED_VALUE(PIPE_TRANSFER_MAP_DIRECTLY),
741 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_RANGE),
742 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DONTBLOCK),
743 DEBUG_NAMED_VALUE(PIPE_TRANSFER_UNSYNCHRONIZED),
744 DEBUG_NAMED_VALUE(PIPE_TRANSFER_FLUSH_EXPLICIT),
745 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE),
746 DEBUG_NAMED_VALUE(PIPE_TRANSFER_PERSISTENT),
747 DEBUG_NAMED_VALUE(PIPE_TRANSFER_COHERENT),
748 DEBUG_NAMED_VALUE_END
749 };
750
751 debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
752 }
753
754
755 /**
756 * Print PIPE_BIND_x flags with a message.
757 */
758 void
759 debug_print_bind_flags(const char *msg, unsigned usage)
760 {
761 static const struct debug_named_value names[] = {
762 DEBUG_NAMED_VALUE(PIPE_BIND_DEPTH_STENCIL),
763 DEBUG_NAMED_VALUE(PIPE_BIND_RENDER_TARGET),
764 DEBUG_NAMED_VALUE(PIPE_BIND_BLENDABLE),
765 DEBUG_NAMED_VALUE(PIPE_BIND_SAMPLER_VIEW),
766 DEBUG_NAMED_VALUE(PIPE_BIND_VERTEX_BUFFER),
767 DEBUG_NAMED_VALUE(PIPE_BIND_INDEX_BUFFER),
768 DEBUG_NAMED_VALUE(PIPE_BIND_CONSTANT_BUFFER),
769 DEBUG_NAMED_VALUE(PIPE_BIND_DISPLAY_TARGET),
770 DEBUG_NAMED_VALUE(PIPE_BIND_TRANSFER_WRITE),
771 DEBUG_NAMED_VALUE(PIPE_BIND_TRANSFER_READ),
772 DEBUG_NAMED_VALUE(PIPE_BIND_STREAM_OUTPUT),
773 DEBUG_NAMED_VALUE(PIPE_BIND_CURSOR),
774 DEBUG_NAMED_VALUE(PIPE_BIND_CUSTOM),
775 DEBUG_NAMED_VALUE(PIPE_BIND_GLOBAL),
776 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_BUFFER),
777 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_IMAGE),
778 DEBUG_NAMED_VALUE(PIPE_BIND_COMPUTE_RESOURCE),
779 DEBUG_NAMED_VALUE(PIPE_BIND_COMMAND_ARGS_BUFFER),
780 DEBUG_NAMED_VALUE(PIPE_BIND_SCANOUT),
781 DEBUG_NAMED_VALUE(PIPE_BIND_SHARED),
782 DEBUG_NAMED_VALUE(PIPE_BIND_LINEAR),
783 DEBUG_NAMED_VALUE_END
784 };
785
786 debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
787 }
788
789
790 /**
791 * Print PIPE_USAGE_x enum values with a message.
792 */
793 void
794 debug_print_usage_enum(const char *msg, unsigned usage)
795 {
796 static const struct debug_named_value names[] = {
797 DEBUG_NAMED_VALUE(PIPE_USAGE_DEFAULT),
798 DEBUG_NAMED_VALUE(PIPE_USAGE_IMMUTABLE),
799 DEBUG_NAMED_VALUE(PIPE_USAGE_DYNAMIC),
800 DEBUG_NAMED_VALUE(PIPE_USAGE_STREAM),
801 DEBUG_NAMED_VALUE(PIPE_USAGE_STAGING),
802 DEBUG_NAMED_VALUE_END
803 };
804
805 debug_printf("%s: %s\n", msg, debug_dump_enum(names, usage));
806 }
807
808
809 #endif