17ec681f3Smrg/* 27ec681f3Smrg * Copyright © Microsoft Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "dxil_dump.h" 257ec681f3Smrg#include "dxil_internal.h" 267ec681f3Smrg 277ec681f3Smrg#define DIXL_DUMP_DECL 287ec681f3Smrg#include "dxil_dump_decls.h" 297ec681f3Smrg 307ec681f3Smrg#include "dxil_module.h" 317ec681f3Smrg 327ec681f3Smrg 337ec681f3Smrg#include "util/string_buffer.h" 347ec681f3Smrg#include "util/list.h" 357ec681f3Smrg 367ec681f3Smrg#include <stdio.h> 377ec681f3Smrg 387ec681f3Smrgstruct dxil_dumper { 397ec681f3Smrg struct _mesa_string_buffer *buf; 407ec681f3Smrg int current_indent; 417ec681f3Smrg}; 427ec681f3Smrg 437ec681f3Smrgstruct dxil_dumper *dxil_dump_create(void) 447ec681f3Smrg{ 457ec681f3Smrg struct dxil_dumper *d = calloc(1, sizeof(struct dxil_dumper)); 467ec681f3Smrg d->buf = _mesa_string_buffer_create(NULL, 1024); 477ec681f3Smrg d->current_indent = 0; 487ec681f3Smrg return d; 497ec681f3Smrg} 507ec681f3Smrg 517ec681f3Smrgvoid dxil_dump_free(struct dxil_dumper *d) 527ec681f3Smrg{ 537ec681f3Smrg _mesa_string_buffer_destroy(d->buf); 547ec681f3Smrg d->buf = 0; 557ec681f3Smrg free(d); 567ec681f3Smrg} 577ec681f3Smrg 587ec681f3Smrgvoid dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f) 597ec681f3Smrg{ 607ec681f3Smrg assert(f); 617ec681f3Smrg assert(d); 627ec681f3Smrg assert(d->buf); 637ec681f3Smrg fprintf(f, "%s", d->buf->buf); 647ec681f3Smrg} 657ec681f3Smrg 667ec681f3Smrgstatic 677ec681f3Smrgvoid dxil_dump_indention_inc(struct dxil_dumper *d) 687ec681f3Smrg{ 697ec681f3Smrg ++d->current_indent; 707ec681f3Smrg} 717ec681f3Smrg 727ec681f3Smrgstatic 737ec681f3Smrgvoid dxil_dump_indention_dec(struct dxil_dumper *d) 747ec681f3Smrg{ 757ec681f3Smrg --d->current_indent; 767ec681f3Smrg assert(d->current_indent >= 0); 777ec681f3Smrg} 787ec681f3Smrg 797ec681f3Smrgstatic 807ec681f3Smrgvoid dxil_dump_indent(struct dxil_dumper *d) 817ec681f3Smrg{ 827ec681f3Smrg for (int i = 0; i < 2 * d->current_indent; ++i) 837ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 847ec681f3Smrg} 857ec681f3Smrg 867ec681f3Smrgvoid 877ec681f3Smrgdxil_dump_module(struct dxil_dumper *d, struct dxil_module *m) 887ec681f3Smrg{ 897ec681f3Smrg assert(m); 907ec681f3Smrg assert(d); 917ec681f3Smrg 927ec681f3Smrg _mesa_string_buffer_printf(d->buf, "DXIL MODULE:\n"); 937ec681f3Smrg dump_metadata(d, m); 947ec681f3Smrg dump_shader_info(d, &m->info); 957ec681f3Smrg dump_types(d, &m->type_list); 967ec681f3Smrg dump_gvars(d, &m->gvar_list); 977ec681f3Smrg dump_funcs(d, &m->func_list); 987ec681f3Smrg dump_attr_set_list(d, &m->attr_set_list); 997ec681f3Smrg dump_constants(d, &m->const_list); 1007ec681f3Smrg dump_instrs(d, &m->instr_list); 1017ec681f3Smrg dump_mdnodes(d, &m->mdnode_list); 1027ec681f3Smrg dump_named_nodes(d, &m->md_named_node_list); 1037ec681f3Smrg dump_io_signatures(d->buf, m); 1047ec681f3Smrg dump_psv(d->buf, m); 1057ec681f3Smrg _mesa_string_buffer_printf(d->buf, "END DXIL MODULE\n"); 1067ec681f3Smrg} 1077ec681f3Smrg 1087ec681f3Smrgstatic void 1097ec681f3Smrgdump_metadata(struct dxil_dumper *d, struct dxil_module *m) 1107ec681f3Smrg{ 1117ec681f3Smrg _mesa_string_buffer_printf(d->buf, "Shader: %s\n", 1127ec681f3Smrg dump_shader_string(m->shader_kind)); 1137ec681f3Smrg 1147ec681f3Smrg _mesa_string_buffer_printf(d->buf, "Version: %d.%d\n", 1157ec681f3Smrg m->major_version, m->minor_version); 1167ec681f3Smrg 1177ec681f3Smrg dump_features(d->buf, &m->feats); 1187ec681f3Smrg} 1197ec681f3Smrg 1207ec681f3Smrgstatic void 1217ec681f3Smrgdump_shader_info(struct dxil_dumper *d, struct dxil_shader_info *info) 1227ec681f3Smrg{ 1237ec681f3Smrg _mesa_string_buffer_append(d->buf, "Shader Info:\n"); 1247ec681f3Smrg if (info->has_out_position) 1257ec681f3Smrg _mesa_string_buffer_append(d->buf, " has_out_position\n"); 1267ec681f3Smrg} 1277ec681f3Smrg 1287ec681f3Smrgstatic const char * 1297ec681f3Smrgdump_shader_string(enum dxil_shader_kind kind) 1307ec681f3Smrg{ 1317ec681f3Smrg#define SHADER_STR(X) case DXIL_ ## X ## _SHADER: return #X 1327ec681f3Smrg 1337ec681f3Smrg switch (kind) { 1347ec681f3Smrg SHADER_STR(VERTEX); 1357ec681f3Smrg SHADER_STR(PIXEL); 1367ec681f3Smrg SHADER_STR(GEOMETRY); 1377ec681f3Smrg SHADER_STR(COMPUTE); 1387ec681f3Smrg default: 1397ec681f3Smrg return "UNSUPPORTED"; 1407ec681f3Smrg } 1417ec681f3Smrg#undef SHADER_STR 1427ec681f3Smrg} 1437ec681f3Smrg 1447ec681f3Smrgstatic void 1457ec681f3Smrgdump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat) 1467ec681f3Smrg{ 1477ec681f3Smrg _mesa_string_buffer_printf(buf, "Features:\n"); 1487ec681f3Smrg#define PRINT_FEAT(F) if (feat->F) _mesa_string_buffer_printf(buf, " %s\n", #F) 1497ec681f3Smrg PRINT_FEAT(doubles); 1507ec681f3Smrg PRINT_FEAT(cs_4x_raw_sb); 1517ec681f3Smrg PRINT_FEAT(uavs_at_every_stage); 1527ec681f3Smrg PRINT_FEAT(use_64uavs); 1537ec681f3Smrg PRINT_FEAT(min_precision); 1547ec681f3Smrg PRINT_FEAT(dx11_1_double_extensions); 1557ec681f3Smrg PRINT_FEAT(dx11_1_shader_extensions); 1567ec681f3Smrg PRINT_FEAT(dx9_comparison_filtering); 1577ec681f3Smrg PRINT_FEAT(tiled_resources); 1587ec681f3Smrg PRINT_FEAT(stencil_ref); 1597ec681f3Smrg PRINT_FEAT(inner_coverage); 1607ec681f3Smrg PRINT_FEAT(typed_uav_load_additional_formats); 1617ec681f3Smrg PRINT_FEAT(rovs); 1627ec681f3Smrg PRINT_FEAT(array_layer_from_vs_or_ds); 1637ec681f3Smrg PRINT_FEAT(wave_ops); 1647ec681f3Smrg PRINT_FEAT(int64_ops); 1657ec681f3Smrg PRINT_FEAT(view_id); 1667ec681f3Smrg PRINT_FEAT(barycentrics); 1677ec681f3Smrg PRINT_FEAT(native_low_precision); 1687ec681f3Smrg PRINT_FEAT(shading_rate); 1697ec681f3Smrg PRINT_FEAT(raytracing_tier_1_1); 1707ec681f3Smrg PRINT_FEAT(sampler_feedback); 1717ec681f3Smrg#undef PRINT_FEAT 1727ec681f3Smrg} 1737ec681f3Smrg 1747ec681f3Smrgstatic void 1757ec681f3Smrgdump_types(struct dxil_dumper *d, struct list_head *list) 1767ec681f3Smrg{ 1777ec681f3Smrg if (!list_length(list)) 1787ec681f3Smrg return; 1797ec681f3Smrg 1807ec681f3Smrg _mesa_string_buffer_append(d->buf, "Types:\n"); 1817ec681f3Smrg dxil_dump_indention_inc(d); 1827ec681f3Smrg list_for_each_entry(struct dxil_type, type, list, head) { 1837ec681f3Smrg dxil_dump_indent(d); 1847ec681f3Smrg dump_type(d, type); 1857ec681f3Smrg _mesa_string_buffer_append(d->buf, "\n"); 1867ec681f3Smrg } 1877ec681f3Smrg dxil_dump_indention_dec(d); 1887ec681f3Smrg} 1897ec681f3Smrg 1907ec681f3Smrgstatic void dump_type_name(struct dxil_dumper *d, const struct dxil_type *type) 1917ec681f3Smrg{ 1927ec681f3Smrg if (!type) { 1937ec681f3Smrg _mesa_string_buffer_append(d->buf, "(type error)"); 1947ec681f3Smrg return; 1957ec681f3Smrg } 1967ec681f3Smrg 1977ec681f3Smrg switch (type->type) { 1987ec681f3Smrg case TYPE_VOID: 1997ec681f3Smrg _mesa_string_buffer_append(d->buf, "void"); 2007ec681f3Smrg break; 2017ec681f3Smrg case TYPE_INTEGER: 2027ec681f3Smrg _mesa_string_buffer_printf(d->buf, "int%d", type->int_bits); 2037ec681f3Smrg break; 2047ec681f3Smrg case TYPE_FLOAT: 2057ec681f3Smrg _mesa_string_buffer_printf(d->buf, "float%d", type->float_bits); 2067ec681f3Smrg break; 2077ec681f3Smrg case TYPE_POINTER: 2087ec681f3Smrg dump_type_name(d, type->ptr_target_type); 2097ec681f3Smrg _mesa_string_buffer_append(d->buf, "*"); 2107ec681f3Smrg break; 2117ec681f3Smrg case TYPE_STRUCT: 2127ec681f3Smrg _mesa_string_buffer_printf(d->buf, "struct %s", type->struct_def.name); 2137ec681f3Smrg break; 2147ec681f3Smrg case TYPE_ARRAY: 2157ec681f3Smrg dump_type_name(d, type->array_or_vector_def.elem_type); 2167ec681f3Smrg _mesa_string_buffer_printf(d->buf, "[%d]", type->array_or_vector_def.num_elems); 2177ec681f3Smrg break; 2187ec681f3Smrg case TYPE_FUNCTION: 2197ec681f3Smrg _mesa_string_buffer_append(d->buf, "("); 2207ec681f3Smrg dump_type_name(d, type->function_def.ret_type); 2217ec681f3Smrg _mesa_string_buffer_append(d->buf, ")("); 2227ec681f3Smrg for (size_t i = 0; i < type->function_def.args.num_types; ++i) { 2237ec681f3Smrg if (i > 0) 2247ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 2257ec681f3Smrg dump_type_name(d, type->function_def.args.types[i]); 2267ec681f3Smrg } 2277ec681f3Smrg _mesa_string_buffer_append(d->buf, ")"); 2287ec681f3Smrg break; 2297ec681f3Smrg case TYPE_VECTOR: 2307ec681f3Smrg _mesa_string_buffer_append(d->buf, "vector<"); 2317ec681f3Smrg dump_type_name(d, type->array_or_vector_def.elem_type); 2327ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", %d>", type->array_or_vector_def.num_elems); 2337ec681f3Smrg break; 2347ec681f3Smrg default: 2357ec681f3Smrg _mesa_string_buffer_printf(d->buf, "unknown type %d", type->type); 2367ec681f3Smrg } 2377ec681f3Smrg} 2387ec681f3Smrg 2397ec681f3Smrgstatic void 2407ec681f3Smrgdump_type(struct dxil_dumper *d, const struct dxil_type *type) 2417ec681f3Smrg{ 2427ec681f3Smrg switch (type->type) { 2437ec681f3Smrg case TYPE_STRUCT: 2447ec681f3Smrg _mesa_string_buffer_printf(d->buf, "struct %s {\n", type->struct_def.name); 2457ec681f3Smrg dxil_dump_indention_inc(d); 2467ec681f3Smrg 2477ec681f3Smrg for (size_t i = 0; i < type->struct_def.elem.num_types; ++i) { 2487ec681f3Smrg dxil_dump_indent(d); 2497ec681f3Smrg dump_type(d, type->struct_def.elem.types[i]); 2507ec681f3Smrg _mesa_string_buffer_append(d->buf, "\n"); 2517ec681f3Smrg } 2527ec681f3Smrg dxil_dump_indention_dec(d); 2537ec681f3Smrg dxil_dump_indent(d); 2547ec681f3Smrg _mesa_string_buffer_append(d->buf, "}\n"); 2557ec681f3Smrg break; 2567ec681f3Smrg default: 2577ec681f3Smrg dump_type_name(d, type); 2587ec681f3Smrg break; 2597ec681f3Smrg } 2607ec681f3Smrg} 2617ec681f3Smrg 2627ec681f3Smrgstatic void 2637ec681f3Smrgdump_gvars(struct dxil_dumper *d, struct list_head *list) 2647ec681f3Smrg{ 2657ec681f3Smrg if (!list_length(list)) 2667ec681f3Smrg return; 2677ec681f3Smrg 2687ec681f3Smrg _mesa_string_buffer_append(d->buf, "Global variables:\n"); 2697ec681f3Smrg dxil_dump_indention_inc(d); 2707ec681f3Smrg list_for_each_entry(struct dxil_gvar, gvar, list, head) { 2717ec681f3Smrg dxil_dump_indent(d); 2727ec681f3Smrg _mesa_string_buffer_printf(d->buf, "address_space(%d) ", gvar->as); 2737ec681f3Smrg if (gvar->constant) 2747ec681f3Smrg _mesa_string_buffer_append(d->buf, "const "); 2757ec681f3Smrg if (gvar->align) 2767ec681f3Smrg _mesa_string_buffer_append(d->buf, "align "); 2777ec681f3Smrg if (gvar->initializer) 2787ec681f3Smrg _mesa_string_buffer_printf(d->buf, "init_id:%d\n", gvar->initializer->id); 2797ec681f3Smrg dump_type_name(d, gvar->type); 2807ec681f3Smrg _mesa_string_buffer_printf(d->buf, " val_id:%d\n", gvar->value.id); 2817ec681f3Smrg } 2827ec681f3Smrg dxil_dump_indention_dec(d); 2837ec681f3Smrg} 2847ec681f3Smrg 2857ec681f3Smrgstatic void 2867ec681f3Smrgdump_funcs(struct dxil_dumper *d, struct list_head *list) 2877ec681f3Smrg{ 2887ec681f3Smrg if (!list_length(list)) 2897ec681f3Smrg return; 2907ec681f3Smrg 2917ec681f3Smrg _mesa_string_buffer_append(d->buf, "Functions:\n"); 2927ec681f3Smrg dxil_dump_indention_inc(d); 2937ec681f3Smrg list_for_each_entry(struct dxil_func, func, list, head) { 2947ec681f3Smrg dxil_dump_indent(d); 2957ec681f3Smrg if (func->decl) 2967ec681f3Smrg _mesa_string_buffer_append(d->buf, "declare "); 2977ec681f3Smrg _mesa_string_buffer_append(d->buf, func->name); 2987ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 2997ec681f3Smrg dump_type_name(d, func->type); 3007ec681f3Smrg if (func->attr_set) 3017ec681f3Smrg _mesa_string_buffer_printf(d->buf, " #%d", func->attr_set); 3027ec681f3Smrg _mesa_string_buffer_append_char(d->buf, '\n'); 3037ec681f3Smrg } 3047ec681f3Smrg dxil_dump_indention_dec(d); 3057ec681f3Smrg} 3067ec681f3Smrg 3077ec681f3Smrgstatic void 3087ec681f3Smrgdump_attr_set_list(struct dxil_dumper *d, struct list_head *list) 3097ec681f3Smrg{ 3107ec681f3Smrg if (!list_length(list)) 3117ec681f3Smrg return; 3127ec681f3Smrg 3137ec681f3Smrg _mesa_string_buffer_append(d->buf, "Attribute set:\n"); 3147ec681f3Smrg dxil_dump_indention_inc(d); 3157ec681f3Smrg int attr_id = 1; 3167ec681f3Smrg list_for_each_entry(struct attrib_set, attr, list, head) { 3177ec681f3Smrg _mesa_string_buffer_printf(d->buf, " #%d: {", attr_id++); 3187ec681f3Smrg for (unsigned i = 0; i < attr->num_attrs; ++i) { 3197ec681f3Smrg if (i > 0) 3207ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 3217ec681f3Smrg 3227ec681f3Smrg assert(attr->attrs[i].type == DXIL_ATTR_ENUM); 3237ec681f3Smrg const char *value = ""; 3247ec681f3Smrg switch (attr->attrs[i].kind) { 3257ec681f3Smrg case DXIL_ATTR_KIND_NONE: value = "none"; break; 3267ec681f3Smrg case DXIL_ATTR_KIND_NO_UNWIND: value = "nounwind"; break; 3277ec681f3Smrg case DXIL_ATTR_KIND_READ_NONE: value = "readnone"; break; 3287ec681f3Smrg case DXIL_ATTR_KIND_READ_ONLY: value = "readonly"; break; 3297ec681f3Smrg case DXIL_ATTR_KIND_NO_DUPLICATE: value = "noduplicate"; break; 3307ec681f3Smrg } 3317ec681f3Smrg _mesa_string_buffer_append(d->buf, value); 3327ec681f3Smrg } 3337ec681f3Smrg _mesa_string_buffer_append(d->buf, "}\n"); 3347ec681f3Smrg } 3357ec681f3Smrg dxil_dump_indention_dec(d); 3367ec681f3Smrg} 3377ec681f3Smrg 3387ec681f3Smrgstatic void 3397ec681f3Smrgdump_constants(struct dxil_dumper *d, struct list_head *list) 3407ec681f3Smrg{ 3417ec681f3Smrg if (!list_length(list)) 3427ec681f3Smrg return; 3437ec681f3Smrg 3447ec681f3Smrg _mesa_string_buffer_append(d->buf, "Constants:\n"); 3457ec681f3Smrg dxil_dump_indention_inc(d); 3467ec681f3Smrg list_for_each_entry(struct dxil_const, cnst, list, head) { 3477ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 3487ec681f3Smrg dump_value(d, &cnst->value); 3497ec681f3Smrg _mesa_string_buffer_append(d->buf, " = "); 3507ec681f3Smrg dump_type_name(d, cnst->value.type); 3517ec681f3Smrg if (!cnst->undef) { 3527ec681f3Smrg switch (cnst->value.type->type) { 3537ec681f3Smrg case TYPE_FLOAT: 3547ec681f3Smrg _mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value); 3557ec681f3Smrg break; 3567ec681f3Smrg case TYPE_INTEGER: 3577ec681f3Smrg _mesa_string_buffer_printf(d->buf, " %d\n", cnst->int_value); 3587ec681f3Smrg break; 3597ec681f3Smrg case TYPE_ARRAY: 3607ec681f3Smrg _mesa_string_buffer_append(d->buf, "{"); 3617ec681f3Smrg for (unsigned i = 0; 3627ec681f3Smrg i < cnst->value.type->array_or_vector_def.num_elems; i++) { 3637ec681f3Smrg _mesa_string_buffer_printf(d->buf, " %%%d", 3647ec681f3Smrg cnst->array_values[i]->id); 3657ec681f3Smrg dump_type_name(d, cnst->value.type); 3667ec681f3Smrg if (i != cnst->value.type->array_or_vector_def.num_elems - 1) 3677ec681f3Smrg _mesa_string_buffer_append(d->buf, ","); 3687ec681f3Smrg _mesa_string_buffer_append(d->buf, " "); 3697ec681f3Smrg } 3707ec681f3Smrg _mesa_string_buffer_append(d->buf, "}\n"); 3717ec681f3Smrg break; 3727ec681f3Smrg default: 3737ec681f3Smrg unreachable("Unsupported const type"); 3747ec681f3Smrg } 3757ec681f3Smrg } else 3767ec681f3Smrg _mesa_string_buffer_append(d->buf, " undef\n"); 3777ec681f3Smrg } 3787ec681f3Smrg dxil_dump_indention_dec(d); 3797ec681f3Smrg} 3807ec681f3Smrg 3817ec681f3Smrgstatic void 3827ec681f3Smrgdump_instrs(struct dxil_dumper *d, struct list_head *list) 3837ec681f3Smrg{ 3847ec681f3Smrg _mesa_string_buffer_append(d->buf, "Shader body:\n"); 3857ec681f3Smrg dxil_dump_indention_inc(d); 3867ec681f3Smrg 3877ec681f3Smrg list_for_each_entry(struct dxil_instr, instr, list, head) { 3887ec681f3Smrg 3897ec681f3Smrg dxil_dump_indent(d); 3907ec681f3Smrg if (instr->has_value) { 3917ec681f3Smrg dump_value(d, &instr->value); 3927ec681f3Smrg _mesa_string_buffer_append(d->buf, " = "); 3937ec681f3Smrg } else { 3947ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 3957ec681f3Smrg } 3967ec681f3Smrg 3977ec681f3Smrg switch (instr->type) { 3987ec681f3Smrg case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break; 3997ec681f3Smrg case INSTR_CMP: dump_instr_cmp(d, &instr->cmp);break; 4007ec681f3Smrg case INSTR_SELECT:dump_instr_select(d, &instr->select); break; 4017ec681f3Smrg case INSTR_CAST: dump_instr_cast(d, &instr->cast); break; 4027ec681f3Smrg case INSTR_CALL: dump_instr_call(d, &instr->call); break; 4037ec681f3Smrg case INSTR_RET: dump_instr_ret(d, &instr->ret); break; 4047ec681f3Smrg case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break; 4057ec681f3Smrg case INSTR_BR: dump_instr_branch(d, &instr->br); break; 4067ec681f3Smrg case INSTR_PHI: dump_instr_phi(d, &instr->phi); break; 4077ec681f3Smrg case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break; 4087ec681f3Smrg case INSTR_GEP: dump_instr_gep(d, &instr->gep); break; 4097ec681f3Smrg case INSTR_LOAD: dump_instr_load(d, &instr->load); break; 4107ec681f3Smrg case INSTR_STORE: dump_instr_store(d, &instr->store); break; 4117ec681f3Smrg case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break; 4127ec681f3Smrg default: 4137ec681f3Smrg _mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type); 4147ec681f3Smrg } 4157ec681f3Smrg 4167ec681f3Smrg _mesa_string_buffer_append(d->buf, "\n"); 4177ec681f3Smrg } 4187ec681f3Smrg dxil_dump_indention_dec(d); 4197ec681f3Smrg} 4207ec681f3Smrg 4217ec681f3Smrgstatic void 4227ec681f3Smrgdump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop) 4237ec681f3Smrg{ 4247ec681f3Smrg const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ? 4257ec681f3Smrg binop_strings[binop->opcode] : "INVALID"; 4267ec681f3Smrg 4277ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%s ", str); 4287ec681f3Smrg dump_instr_print_operands(d, 2, binop->operands); 4297ec681f3Smrg} 4307ec681f3Smrg 4317ec681f3Smrgstatic void 4327ec681f3Smrgdump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp) 4337ec681f3Smrg{ 4347ec681f3Smrg const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ? 4357ec681f3Smrg pred_strings[cmp->pred] : "INVALID"; 4367ec681f3Smrg 4377ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%s ", str); 4387ec681f3Smrg dump_instr_print_operands(d, 2, cmp->operands); 4397ec681f3Smrg} 4407ec681f3Smrg 4417ec681f3Smrgstatic void 4427ec681f3Smrgdump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select) 4437ec681f3Smrg{ 4447ec681f3Smrg _mesa_string_buffer_append(d->buf, "sel "); 4457ec681f3Smrg dump_instr_print_operands(d, 3, select->operands); 4467ec681f3Smrg} 4477ec681f3Smrg 4487ec681f3Smrgstatic void 4497ec681f3Smrgdump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast) 4507ec681f3Smrg{ 4517ec681f3Smrg const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ? 4527ec681f3Smrg cast_opcode_strings[cast->opcode] : "INVALID"; 4537ec681f3Smrg 4547ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%s.", str); 4557ec681f3Smrg dump_type_name(d, cast->type); 4567ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 4577ec681f3Smrg dump_value(d, cast->value); 4587ec681f3Smrg} 4597ec681f3Smrg 4607ec681f3Smrgstatic void 4617ec681f3Smrgdump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call) 4627ec681f3Smrg{ 4637ec681f3Smrg assert(call->num_args == call->func->type->function_def.args.num_types); 4647ec681f3Smrg struct dxil_type **func_arg_types = call->func->type->function_def.args.types; 4657ec681f3Smrg 4667ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%s(", call->func->name); 4677ec681f3Smrg for (unsigned i = 0; i < call->num_args; ++i) { 4687ec681f3Smrg if (i > 0) 4697ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 4707ec681f3Smrg dump_type_name(d, func_arg_types[i]); 4717ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 4727ec681f3Smrg dump_value(d, call->args[i]); 4737ec681f3Smrg } 4747ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ')'); 4757ec681f3Smrg} 4767ec681f3Smrg 4777ec681f3Smrgstatic void 4787ec681f3Smrgdump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret) 4797ec681f3Smrg{ 4807ec681f3Smrg _mesa_string_buffer_append(d->buf, "ret "); 4817ec681f3Smrg if (ret->value) 4827ec681f3Smrg dump_value(d, ret->value); 4837ec681f3Smrg} 4847ec681f3Smrg 4857ec681f3Smrgstatic void 4867ec681f3Smrgdump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr) 4877ec681f3Smrg{ 4887ec681f3Smrg _mesa_string_buffer_append(d->buf, "extractvalue "); 4897ec681f3Smrg dump_type_name(d, extr->type); 4907ec681f3Smrg dump_value(d, extr->src); 4917ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", %d", extr->idx); 4927ec681f3Smrg} 4937ec681f3Smrg 4947ec681f3Smrgstatic void 4957ec681f3Smrgdump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br) 4967ec681f3Smrg{ 4977ec681f3Smrg _mesa_string_buffer_append(d->buf, "branch "); 4987ec681f3Smrg if (br->cond) 4997ec681f3Smrg dump_value(d, br->cond); 5007ec681f3Smrg else 5017ec681f3Smrg _mesa_string_buffer_append(d->buf, " (uncond)"); 5027ec681f3Smrg _mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]); 5037ec681f3Smrg} 5047ec681f3Smrg 5057ec681f3Smrgstatic void 5067ec681f3Smrgdump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi) 5077ec681f3Smrg{ 5087ec681f3Smrg _mesa_string_buffer_append(d->buf, "phi "); 5097ec681f3Smrg dump_type_name(d, phi->type); 5107ec681f3Smrg struct dxil_phi_src *src = phi->incoming; 5117ec681f3Smrg for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) { 5127ec681f3Smrg if (i > 0) 5137ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5147ec681f3Smrg dump_value(d, src->value); 5157ec681f3Smrg _mesa_string_buffer_printf(d->buf, "(%d)", src->block); 5167ec681f3Smrg } 5177ec681f3Smrg} 5187ec681f3Smrg 5197ec681f3Smrgstatic void 5207ec681f3Smrgdump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca) 5217ec681f3Smrg{ 5227ec681f3Smrg _mesa_string_buffer_append(d->buf, "alloca "); 5237ec681f3Smrg dump_type_name(d, alloca->alloc_type); 5247ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5257ec681f3Smrg dump_type_name(d, alloca->size_type); 5267ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5277ec681f3Smrg dump_value(d, alloca->size); 5287ec681f3Smrg unsigned align_mask = (1 << 6 ) - 1; 5297ec681f3Smrg unsigned align = alloca->align & align_mask; 5307ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1)); 5317ec681f3Smrg} 5327ec681f3Smrg 5337ec681f3Smrgstatic void 5347ec681f3Smrgdump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep) 5357ec681f3Smrg{ 5367ec681f3Smrg _mesa_string_buffer_append(d->buf, "getelementptr "); 5377ec681f3Smrg if (gep->inbounds) 5387ec681f3Smrg _mesa_string_buffer_append(d->buf, "inbounds "); 5397ec681f3Smrg dump_type_name(d, gep->source_elem_type); 5407ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5417ec681f3Smrg for (unsigned i = 0; i < gep->num_operands; ++i) { 5427ec681f3Smrg if (i > 0) 5437ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5447ec681f3Smrg dump_value(d, gep->operands[i]); 5457ec681f3Smrg } 5467ec681f3Smrg} 5477ec681f3Smrg 5487ec681f3Smrgstatic void 5497ec681f3Smrgdump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load) 5507ec681f3Smrg{ 5517ec681f3Smrg _mesa_string_buffer_append(d->buf, "load "); 5527ec681f3Smrg if (load->is_volatile) 5537ec681f3Smrg _mesa_string_buffer_append(d->buf, " volatile"); 5547ec681f3Smrg dump_type_name(d, load->type); 5557ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5567ec681f3Smrg dump_value(d, load->ptr); 5577ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", %d", load->align); 5587ec681f3Smrg} 5597ec681f3Smrg 5607ec681f3Smrgstatic void 5617ec681f3Smrgdump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store) 5627ec681f3Smrg{ 5637ec681f3Smrg _mesa_string_buffer_append(d->buf, "store "); 5647ec681f3Smrg if (store->is_volatile) 5657ec681f3Smrg _mesa_string_buffer_append(d->buf, " volatile"); 5667ec681f3Smrg dump_value(d, store->value); 5677ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 5687ec681f3Smrg dump_value(d, store->ptr); 5697ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", %d", store->align); 5707ec681f3Smrg} 5717ec681f3Smrg 5727ec681f3Smrgstatic const char *rmworder_str[] = { 5737ec681f3Smrg [DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic", 5747ec681f3Smrg [DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered", 5757ec681f3Smrg [DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic", 5767ec681f3Smrg [DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire", 5777ec681f3Smrg [DXIL_ATOMIC_ORDERING_RELEASE] = "release", 5787ec681f3Smrg [DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel", 5797ec681f3Smrg [DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst", 5807ec681f3Smrg}; 5817ec681f3Smrg 5827ec681f3Smrgstatic const char *rmwsync_str[] = { 5837ec681f3Smrg [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread", 5847ec681f3Smrg [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread", 5857ec681f3Smrg}; 5867ec681f3Smrg 5877ec681f3Smrgstatic const char *rmwop_str[] = { 5887ec681f3Smrg [DXIL_RMWOP_XCHG] = "xchg", 5897ec681f3Smrg [DXIL_RMWOP_ADD] = "add", 5907ec681f3Smrg [DXIL_RMWOP_SUB] = "sub", 5917ec681f3Smrg [DXIL_RMWOP_AND] = "and", 5927ec681f3Smrg [DXIL_RMWOP_NAND] = "nand", 5937ec681f3Smrg [DXIL_RMWOP_OR] = "or", 5947ec681f3Smrg [DXIL_RMWOP_XOR] = "xor", 5957ec681f3Smrg [DXIL_RMWOP_MAX] = "max", 5967ec681f3Smrg [DXIL_RMWOP_MIN] = "min", 5977ec681f3Smrg [DXIL_RMWOP_UMAX] = "umax", 5987ec681f3Smrg [DXIL_RMWOP_UMIN] = "umin", 5997ec681f3Smrg}; 6007ec681f3Smrg 6017ec681f3Smrgstatic void 6027ec681f3Smrgdump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw) 6037ec681f3Smrg{ 6047ec681f3Smrg _mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]); 6057ec681f3Smrg 6067ec681f3Smrg if (rmw->is_volatile) 6077ec681f3Smrg _mesa_string_buffer_append(d->buf, " volatile"); 6087ec681f3Smrg dump_value(d, rmw->value); 6097ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 6107ec681f3Smrg dump_value(d, rmw->ptr); 6117ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]); 6127ec681f3Smrg _mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]); 6137ec681f3Smrg} 6147ec681f3Smrg 6157ec681f3Smrgstatic void 6167ec681f3Smrgdump_instr_print_operands(struct dxil_dumper *d, int num, 6177ec681f3Smrg const struct dxil_value *val[]) 6187ec681f3Smrg{ 6197ec681f3Smrg for (int i = 0; i < num; ++i) { 6207ec681f3Smrg if (i > 0) 6217ec681f3Smrg _mesa_string_buffer_append(d->buf, ", "); 6227ec681f3Smrg dump_value(d, val[i]); 6237ec681f3Smrg } 6247ec681f3Smrg} 6257ec681f3Smrg 6267ec681f3Smrgstatic void 6277ec681f3Smrgdump_value(struct dxil_dumper *d, const struct dxil_value *val) 6287ec681f3Smrg{ 6297ec681f3Smrg if (val->id < 10) 6307ec681f3Smrg _mesa_string_buffer_append(d->buf, " "); 6317ec681f3Smrg if (val->id < 100) 6327ec681f3Smrg _mesa_string_buffer_append(d->buf, " "); 6337ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%%%d", val->id); 6347ec681f3Smrg dump_type_name(d, val->type); 6357ec681f3Smrg} 6367ec681f3Smrg 6377ec681f3Smrgstatic void 6387ec681f3Smrgdump_mdnodes(struct dxil_dumper *d, struct list_head *list) 6397ec681f3Smrg{ 6407ec681f3Smrg if (!list_length(list)) 6417ec681f3Smrg return; 6427ec681f3Smrg 6437ec681f3Smrg _mesa_string_buffer_append(d->buf, "MD-Nodes:\n"); 6447ec681f3Smrg dxil_dump_indention_inc(d); 6457ec681f3Smrg list_for_each_entry(struct dxil_mdnode, node, list, head) { 6467ec681f3Smrg dump_mdnode(d, node); 6477ec681f3Smrg } 6487ec681f3Smrg dxil_dump_indention_dec(d); 6497ec681f3Smrg} 6507ec681f3Smrg 6517ec681f3Smrgstatic void 6527ec681f3Smrgdump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node) 6537ec681f3Smrg{ 6547ec681f3Smrg dxil_dump_indent(d); 6557ec681f3Smrg switch (node->type) { 6567ec681f3Smrg case MD_STRING: 6577ec681f3Smrg _mesa_string_buffer_printf(d->buf, "S:%s\n", node->string); 6587ec681f3Smrg break; 6597ec681f3Smrg case MD_VALUE: 6607ec681f3Smrg _mesa_string_buffer_append(d->buf, "V:"); 6617ec681f3Smrg dump_type_name(d, node->value.type); 6627ec681f3Smrg _mesa_string_buffer_append_char(d->buf, ' '); 6637ec681f3Smrg dump_value(d, node->value.value); 6647ec681f3Smrg _mesa_string_buffer_append_char(d->buf, '\n'); 6657ec681f3Smrg break; 6667ec681f3Smrg case MD_NODE: 6677ec681f3Smrg _mesa_string_buffer_append(d->buf, " \\\n"); 6687ec681f3Smrg dxil_dump_indention_inc(d); 6697ec681f3Smrg for (size_t i = 0; i < node->node.num_subnodes; ++i) { 6707ec681f3Smrg if (node->node.subnodes[i]) 6717ec681f3Smrg dump_mdnode(d, node->node.subnodes[i]); 6727ec681f3Smrg else { 6737ec681f3Smrg dxil_dump_indent(d); 6747ec681f3Smrg _mesa_string_buffer_append(d->buf, "(nullptr)\n"); 6757ec681f3Smrg } 6767ec681f3Smrg } 6777ec681f3Smrg dxil_dump_indention_dec(d); 6787ec681f3Smrg break; 6797ec681f3Smrg } 6807ec681f3Smrg} 6817ec681f3Smrg 6827ec681f3Smrgstatic void 6837ec681f3Smrgdump_named_nodes(struct dxil_dumper *d, struct list_head *list) 6847ec681f3Smrg{ 6857ec681f3Smrg if (!list_length(list)) 6867ec681f3Smrg return; 6877ec681f3Smrg 6887ec681f3Smrg _mesa_string_buffer_append(d->buf, "Named Nodes:\n"); 6897ec681f3Smrg dxil_dump_indention_inc(d); 6907ec681f3Smrg list_for_each_entry(struct dxil_named_node, node, list, head) { 6917ec681f3Smrg dxil_dump_indent(d); 6927ec681f3Smrg _mesa_string_buffer_printf(d->buf, "%s:\n", node->name); 6937ec681f3Smrg dxil_dump_indention_inc(d); 6947ec681f3Smrg for (size_t i = 0; i < node->num_subnodes; ++i) { 6957ec681f3Smrg if (node->subnodes[i]) 6967ec681f3Smrg dump_mdnode(d, node->subnodes[i]); 6977ec681f3Smrg else { 6987ec681f3Smrg dxil_dump_indent(d); 6997ec681f3Smrg _mesa_string_buffer_append(d->buf, "(nullptr)\n"); 7007ec681f3Smrg } 7017ec681f3Smrg } 7027ec681f3Smrg dxil_dump_indention_dec(d); 7037ec681f3Smrg } 7047ec681f3Smrg dxil_dump_indention_dec(d); 7057ec681f3Smrg} 7067ec681f3Smrg 7077ec681f3Smrgstatic void 7087ec681f3Smrgmask_to_string(uint32_t mask, char str[5]) 7097ec681f3Smrg{ 7107ec681f3Smrg const char *mc = "xyzw"; 7117ec681f3Smrg for (int i = 0; i < 4 && mask; ++i) { 7127ec681f3Smrg str[i] = (mask & (1 << i)) ? mc[i] : '_'; 7137ec681f3Smrg } 7147ec681f3Smrg str[4] = 0; 7157ec681f3Smrg} 7167ec681f3Smrg 7177ec681f3Smrgstatic void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m) 7187ec681f3Smrg{ 7197ec681f3Smrg _mesa_string_buffer_append(buf, "\nInput signature:\n"); 7207ec681f3Smrg dump_io_signature(buf, m->num_sig_inputs, m->inputs); 7217ec681f3Smrg _mesa_string_buffer_append(buf, "\nOutput signature:\n"); 7227ec681f3Smrg dump_io_signature(buf, m->num_sig_outputs, m->outputs); 7237ec681f3Smrg} 7247ec681f3Smrg 7257ec681f3Smrgstatic void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num, 7267ec681f3Smrg struct dxil_signature_record *io) 7277ec681f3Smrg{ 7287ec681f3Smrg _mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n"); 7297ec681f3Smrg _mesa_string_buffer_append(buf, "----------------------------------------------\n"); 7307ec681f3Smrg for (unsigned i = 0; i < num; ++i, ++io) { 7317ec681f3Smrg for (unsigned j = 0; j < io->num_elements; ++j) { 7327ec681f3Smrg char mask[5] = ""; 7337ec681f3Smrg mask_to_string(io->elements[j].mask, mask); 7347ec681f3Smrg _mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n", 7357ec681f3Smrg io->name, io->elements[j].semantic_index, 7367ec681f3Smrg mask, io->elements[j].reg, io->sysvalue, 7377ec681f3Smrg component_type_as_string(io->elements[j].comp_type)); 7387ec681f3Smrg } 7397ec681f3Smrg } 7407ec681f3Smrg} 7417ec681f3Smrg 7427ec681f3Smrgstatic const char *component_type_as_string(uint32_t type) 7437ec681f3Smrg{ 7447ec681f3Smrg return (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ? 7457ec681f3Smrg dxil_type_strings[type] : "invalid"; 7467ec681f3Smrg} 7477ec681f3Smrg 7487ec681f3Smrgstatic void dump_psv(struct _mesa_string_buffer *buf, 7497ec681f3Smrg struct dxil_module *m) 7507ec681f3Smrg{ 7517ec681f3Smrg _mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n"); 7527ec681f3Smrg dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs); 7537ec681f3Smrg _mesa_string_buffer_append(buf, "\nOutputs:\n"); 7547ec681f3Smrg dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs); 7557ec681f3Smrg} 7567ec681f3Smrg 7577ec681f3Smrgstatic void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m, 7587ec681f3Smrg unsigned num, struct dxil_psv_signature_element *io) 7597ec681f3Smrg{ 7607ec681f3Smrg _mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n"); 7617ec681f3Smrg _mesa_string_buffer_append(buf, "----------------------------------------------\n"); 7627ec681f3Smrg for (unsigned i = 0; i < num; ++i, ++io) { 7637ec681f3Smrg _mesa_string_buffer_printf(buf, "%-14s %d+%d %d+%d %4d %-7s %-4d %-9d [", 7647ec681f3Smrg m->sem_string_table->buf + io->semantic_name_offset, 7657ec681f3Smrg (int)io->start_row, (int)io->rows, 7667ec681f3Smrg (int)((io->cols_and_start & 0xf) >> 4), 7677ec681f3Smrg (int)(io->cols_and_start & 0xf), 7687ec681f3Smrg (int)io->semantic_kind, 7697ec681f3Smrg component_type_as_string(io->component_type), 7707ec681f3Smrg (int)io->interpolation_mode, 7717ec681f3Smrg (int)io->dynamic_mask_and_stream); 7727ec681f3Smrg for (int k = 0; k < io->rows; ++k) { 7737ec681f3Smrg if (k > 0) 7747ec681f3Smrg _mesa_string_buffer_append(buf, ", "); 7757ec681f3Smrg _mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row + k]); 7767ec681f3Smrg } 7777ec681f3Smrg _mesa_string_buffer_append(buf, "]\n"); 7787ec681f3Smrg } 7797ec681f3Smrg} 780