Just inspection for now, but I do have in-progress patches to extract and update sections.
From: Henri Verbeet hverbeet@codeweavers.com
--- .gitignore | 1 + Makefile.am | 6 +- programs/vkd3d-dxbc/main.c | 120 +++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 programs/vkd3d-dxbc/main.c
diff --git a/.gitignore b/.gitignore index b6d29d199..841220ee6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ Makefile Makefile.in test-suite.log /vkd3d-compiler +/vkd3d-dxbc
vkd3d-*.tar.xz
diff --git a/Makefile.am b/Makefile.am index ecb7c7e25..45f1dd549 100644 --- a/Makefile.am +++ b/Makefile.am @@ -353,11 +353,15 @@ EXTRA_DIST += \ libs/vkd3d-shader/libvkd3d-shader.pc.in \ libs/vkd3d-utils/libvkd3d-utils.pc.in
-bin_PROGRAMS = vkd3d-compiler +bin_PROGRAMS = vkd3d-compiler vkd3d-dxbc + vkd3d_compiler_SOURCES = programs/vkd3d-compiler/main.c vkd3d_compiler_CFLAGS = $(AM_CFLAGS) @NCURSES_CFLAGS@ vkd3d_compiler_LDADD = libvkd3d-shader.la @NCURSES_LIBS@
+vkd3d_dxbc_SOURCES = programs/vkd3d-dxbc/main.c +vkd3d_dxbc_LDADD = libvkd3d-shader.la + LDADD = libvkd3d.la libvkd3d-shader.la libvkd3d-utils.la AM_DEFAULT_SOURCE_EXT = .c
diff --git a/programs/vkd3d-dxbc/main.c b/programs/vkd3d-dxbc/main.c new file mode 100644 index 000000000..f75f95429 --- /dev/null +++ b/programs/vkd3d-dxbc/main.c @@ -0,0 +1,120 @@ +/* + * Copyright 2023 Henri Verbeet for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <unistd.h> +#include <getopt.h> + +#include "vkd3d_common.h" +#include "vkd3d_shader.h" + +enum +{ + OPTION_HELP = CHAR_MAX + 1, + OPTION_VERSION, +}; + +struct options +{ + bool print_help; + bool print_version; +}; + +static bool parse_command_line(int argc, char **argv, struct options *options) +{ + int option; + + static struct option long_options[] = + { + {"help", no_argument, NULL, OPTION_HELP}, + {"version", no_argument, NULL, OPTION_VERSION}, + {NULL, 0, NULL, 0}, + }; + + memset(options, 0, sizeof(*options)); + + for (;;) + { + if ((option = getopt_long(argc, argv, "hV", long_options, NULL)) == -1) + break; + + switch (option) + { + case 'h': + case OPTION_HELP: + options->print_help = true; + return true; + + case 'V': + case OPTION_VERSION: + options->print_version = true; + return true; + + default: + return false; + } + } + + return true; +} + +static void print_usage(const char *program_name) +{ + static const char usage[] = + "[options...]\n" + "Options:\n" + " -h, --help Display this information and exit.\n" + " -V, --version Display version information and exit.\n" + " -- Stop option processing. Any subsequent argument is\n" + " interpreted as a filename.\n"; + + fprintf(stderr, "Usage: %s %s", program_name, usage); +} + +int main(int argc, char **argv) +{ + struct options options; + + if (!parse_command_line(argc, argv, &options)) + { + print_usage(argv[0]); + return 1; + } + + if (options.print_help || (argc < 2 && isatty(fileno(stdin)))) + { + print_usage(argv[0]); + return 0; + } + + if (options.print_version) + { + const char *version = vkd3d_shader_get_version(NULL, NULL); + + fprintf(stdout, "vkd3d-dxbc version " PACKAGE_VERSION " using %s\n", version); + return 0; + } + + return 0; +}
From: Henri Verbeet hverbeet@codeweavers.com
--- Makefile.am | 3 +- README | 4 +- programs/vkd3d-dxbc/main.c | 241 ++++++++++++++++++++++++++++++++++++- 3 files changed, 240 insertions(+), 8 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 45f1dd549..27738f3bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -360,7 +360,8 @@ vkd3d_compiler_CFLAGS = $(AM_CFLAGS) @NCURSES_CFLAGS@ vkd3d_compiler_LDADD = libvkd3d-shader.la @NCURSES_LIBS@
vkd3d_dxbc_SOURCES = programs/vkd3d-dxbc/main.c -vkd3d_dxbc_LDADD = libvkd3d-shader.la +vkd3d_dxbc_CFLAGS = $(AM_CFLAGS) @NCURSES_CFLAGS@ +vkd3d_dxbc_LDADD = libvkd3d-shader.la @NCURSES_LIBS@
LDADD = libvkd3d.la libvkd3d-shader.la libvkd3d-utils.la AM_DEFAULT_SOURCE_EXT = .c diff --git a/README b/README index 465d5f915..cac0d6dd3 100644 --- a/README +++ b/README @@ -47,8 +47,8 @@ commas or semicolons.
* NO_COLOR - this is an alias of NO_COLOUR.
- * NO_COLOUR - when set, vkd3d-compiler will default to monochrome output, - even when the output supports colour. + * NO_COLOUR - when set, vkd3d-compiler and vkd3d-dxbc will default to + monochrome output, even when the output supports colour.
* VKD3D_CONFIG - a list of options that change the behavior of libvkd3d. * virtual_heaps - Create descriptors for each D3D12 root signature diff --git a/programs/vkd3d-dxbc/main.c b/programs/vkd3d-dxbc/main.c index f75f95429..6766016dd 100644 --- a/programs/vkd3d-dxbc/main.c +++ b/programs/vkd3d-dxbc/main.c @@ -25,47 +25,117 @@ #include <stdbool.h> #include <unistd.h> #include <getopt.h> +#include <sys/stat.h>
#include "vkd3d_common.h" #include "vkd3d_shader.h" +#ifdef HAVE_NCURSES +#include <term.h> +#endif
enum { - OPTION_HELP = CHAR_MAX + 1, + OPTION_COLOUR = CHAR_MAX + 1, + OPTION_HELP, + OPTION_LIST, + OPTION_NO_COLOUR, OPTION_VERSION, };
struct options { + const char *input_filename; bool print_help; + bool list; bool print_version; + + struct colours + { + const char *reset; + const char *index; + const char *label; + } colours; };
+static bool has_colour(void) +{ +#ifdef HAVE_NCURSES + bool supported; + int ret; + + if (!isatty(fileno(stdout))) + return false; + setupterm(NULL, fileno(stdout), &ret); + if (ret != 1) + return false; + supported = !!tigetstr("setaf"); + del_curterm(cur_term); + + return supported; +#else + return false; +#endif +} + static bool parse_command_line(int argc, char **argv, struct options *options) { int option;
static struct option long_options[] = { + {"colour", no_argument, NULL, OPTION_COLOUR}, {"help", no_argument, NULL, OPTION_HELP}, + {"list", no_argument, NULL, OPTION_LIST}, + {"no-colour", no_argument, NULL, OPTION_NO_COLOUR}, {"version", no_argument, NULL, OPTION_VERSION}, {NULL, 0, NULL, 0}, };
+ static const struct colours colours = + { + .reset = "\x1b[m", + .index = "\x1b[92m", + .label = "\x1b[93m", + }; + + static const struct colours no_colours = + { + .reset = "", + .index = "", + .label = "", + }; + memset(options, 0, sizeof(*options)); + if (!getenv("NO_COLOUR") && !getenv("NO_COLOR") && has_colour()) + options->colours = colours; + else + options->colours = no_colours;
for (;;) { - if ((option = getopt_long(argc, argv, "hV", long_options, NULL)) == -1) + if ((option = getopt_long(argc, argv, "htV", long_options, NULL)) == -1) break;
switch (option) { + case OPTION_COLOUR: + options->colours = colours; + break; + case 'h': case OPTION_HELP: options->print_help = true; return true;
+ case 't': + case OPTION_LIST: + options->list = true; + break; + + case OPTION_NO_COLOUR: + options->colours = no_colours; + break; + case 'V': case OPTION_VERSION: options->print_version = true; @@ -76,25 +146,161 @@ static bool parse_command_line(int argc, char **argv, struct options *options) } }
+ if (optind < argc) + options->input_filename = argv[argc - 1]; + return true; }
static void print_usage(const char *program_name) { static const char usage[] = - "[options...]\n" + "[options...] [file]\n" "Options:\n" + " --colour Enable colour, even when not supported by the output.\n" " -h, --help Display this information and exit.\n" + " -t, --list List the contents of the DXBC blob.\n" + " --no-colour Disable colour, even when supported by the output.\n" " -V, --version Display version information and exit.\n" " -- Stop option processing. Any subsequent argument is\n" - " interpreted as a filename.\n"; + " interpreted as a filename.\n" + "\n" + "If the input file is '-' or not specified, input will be read from standard\n" + "input.\n";
fprintf(stderr, "Usage: %s %s", program_name, usage); }
+static FILE *open_input(const char *filename, bool *close) +{ + FILE *f; + + *close = false; + + if (!filename || !strcmp(filename, "-")) + return stdin; + + if (!(f = fopen(filename, "rb"))) + { + fprintf(stderr, "Unable to open '%s' for reading.\n", filename); + return NULL; + } + + *close = true; + return f; +} + +static bool read_input(FILE *f, struct vkd3d_shader_code *dxbc) +{ + size_t size = 4096; + struct stat st; + size_t pos = 0; + uint8_t *data; + size_t ret; + + memset(dxbc, 0, sizeof(*dxbc)); + + if (fstat(fileno(f), &st) == -1) + { + fprintf(stderr, "Could not stat input.\n"); + return false; + } + + if (S_ISREG(st.st_mode)) + size = st.st_size; + + if (!(data = malloc(size))) + { + fprintf(stderr, "Out of memory.\n"); + return false; + } + + for (;;) + { + if (pos >= size) + { + if (size > SIZE_MAX / 2 || !(data = realloc(data, size * 2))) + { + fprintf(stderr, "Out of memory.\n"); + free(data); + return false; + } + size *= 2; + } + + if (!(ret = fread(&data[pos], 1, size - pos, f))) + break; + pos += ret; + } + + if (!feof(f)) + { + free(data); + return false; + } + + dxbc->code = data; + dxbc->size = pos; + + return true; +} + +static const char *dump_tag(char *out, uint32_t tag) +{ + unsigned int i; + + memcpy(out, &tag, sizeof(tag)); + for (i = 0; i < sizeof(tag); ++i) + { + if (!isprint(out[i])) + out[i] = '.'; + } + + return out; +} + +static void dump_dxbc(const struct vkd3d_shader_dxbc_desc *dxbc_desc, const struct options *options) +{ + const struct colours *colours = &options->colours; + struct vkd3d_shader_dxbc_section_desc *section; + char tag[4]; + size_t i; + + printf(" %stag%s: %08x (%.4s)\n", + colours->label, colours->reset, + dxbc_desc->tag, dump_tag(tag, dxbc_desc->tag)); + printf(" %schecksum%s: %08x %08x %08x %08x\n", + colours->label, colours->reset, + dxbc_desc->checksum[0], dxbc_desc->checksum[1], + dxbc_desc->checksum[2], dxbc_desc->checksum[3]); + printf(" %sversion%s: %u\n", colours->label, colours->reset, dxbc_desc->version); + printf(" %ssize%s: %#zx (%zu) bytes\n", colours->label, colours->reset, dxbc_desc->size, dxbc_desc->size); + printf(" %ssections%s: %zu\n\n", colours->label, colours->reset, dxbc_desc->section_count); + + printf(" %s#%s %stag%s %ssize%s\n", + colours->label, colours->reset, + colours->label, colours->reset, + colours->label, colours->reset); + for (i = 0; i < dxbc_desc->section_count; ++i) + { + section = &dxbc_desc->sections[i]; + printf("%s%2zu%s %08x (%.4s) 0x%08zx (%zu) bytes\n", + colours->index, i, colours->reset, + section->tag, dump_tag(tag, section->tag), + section->data.size, section->data.size); + } +} + int main(int argc, char **argv) { + struct vkd3d_shader_dxbc_desc dxbc_desc; + struct vkd3d_shader_code dxbc; struct options options; + bool close_input; + char *messages; + int fail = 1; + FILE *input; + int ret;
if (!parse_command_line(argc, argv, &options)) { @@ -116,5 +322,30 @@ int main(int argc, char **argv) return 0; }
- return 0; + if (!(input = open_input(options.input_filename, &close_input))) + goto done; + + if (!read_input(input, &dxbc)) + { + fprintf(stderr, "Failed to read input blob.\n"); + goto done; + } + + ret = vkd3d_shader_parse_dxbc(&dxbc, 0, &dxbc_desc, &messages); + if (messages) + fputs(messages, stderr); + vkd3d_shader_free_messages(messages); + if (ret < 0) + goto done; + + if (options.list) + dump_dxbc(&dxbc_desc, &options); + + vkd3d_shader_free_dxbc(&dxbc_desc); + vkd3d_shader_free_shader_code(&dxbc); + fail = 0; +done: + if (close_input) + fclose(input); + return fail; }
From: Henri Verbeet hverbeet@codeweavers.com
--- programs/vkd3d-dxbc/main.c | 72 +++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/programs/vkd3d-dxbc/main.c b/programs/vkd3d-dxbc/main.c index 6766016dd..ea425f099 100644 --- a/programs/vkd3d-dxbc/main.c +++ b/programs/vkd3d-dxbc/main.c @@ -38,6 +38,7 @@ enum OPTION_COLOUR = CHAR_MAX + 1, OPTION_HELP, OPTION_LIST, + OPTION_LIST_DATA, OPTION_NO_COLOUR, OPTION_VERSION, }; @@ -47,12 +48,14 @@ struct options const char *input_filename; bool print_help; bool list; + bool list_data; bool print_version;
struct colours { const char *reset; const char *index; + const char *offset; const char *label; } colours; }; @@ -86,6 +89,7 @@ static bool parse_command_line(int argc, char **argv, struct options *options) {"colour", no_argument, NULL, OPTION_COLOUR}, {"help", no_argument, NULL, OPTION_HELP}, {"list", no_argument, NULL, OPTION_LIST}, + {"list-data", no_argument, NULL, OPTION_LIST_DATA}, {"no-colour", no_argument, NULL, OPTION_NO_COLOUR}, {"version", no_argument, NULL, OPTION_VERSION}, {NULL, 0, NULL, 0}, @@ -95,6 +99,7 @@ static bool parse_command_line(int argc, char **argv, struct options *options) { .reset = "\x1b[m", .index = "\x1b[92m", + .offset = "\x1b[36m", .label = "\x1b[93m", };
@@ -102,6 +107,7 @@ static bool parse_command_line(int argc, char **argv, struct options *options) { .reset = "", .index = "", + .offset = "", .label = "", };
@@ -132,6 +138,10 @@ static bool parse_command_line(int argc, char **argv, struct options *options) options->list = true; break;
+ case OPTION_LIST_DATA: + options->list_data = true; + break; + case OPTION_NO_COLOUR: options->colours = no_colours; break; @@ -160,6 +170,7 @@ static void print_usage(const char *program_name) " --colour Enable colour, even when not supported by the output.\n" " -h, --help Display this information and exit.\n" " -t, --list List the contents of the DXBC blob.\n" + " --list-data List the data contained in the DXBC sections.\n" " --no-colour Disable colour, even when supported by the output.\n" " -V, --version Display version information and exit.\n" " -- Stop option processing. Any subsequent argument is\n" @@ -259,6 +270,59 @@ static const char *dump_tag(char *out, uint32_t tag) return out; }
+static void dump_line(const struct colours *colours, const char *prefix, + const uint8_t *data, size_t offset, size_t count) +{ + const uint8_t *ptr = &data[offset]; + size_t i; + + if (!count) + return; + + printf("%s%s%08zx%s ", prefix, colours->offset, offset, colours->reset); + for (i = 0; i < count; ++i) + { + printf("%02x ", ptr[i]); + if (i == 7) + printf(" "); + } + + while (i < 16) + { + printf(" "); + if (i == 7) + printf(" "); + ++i; + } + printf(" %s|%s", colours->offset, colours->reset); + + for (i = 0; i < count; ++i) + { + printf("%c", isprint(ptr[i]) ? ptr[i] : '.'); + } + printf("%s|%s\n", colours->offset, colours->reset); +} + +static void dump_data(const struct colours *colours, const char *prefix, const struct vkd3d_shader_code *data) +{ + size_t line_count, remainder, i; + const uint8_t *ptr; + + ptr = data->code; + line_count = data->size / 16; + remainder = data->size % 16; + + for (i = 0; i < line_count; ++i, ptr += 16) + { + dump_line(colours, prefix, data->code, i * 16, 16); + } + if (remainder) + { + dump_line(colours, prefix, data->code, i * 16, remainder); + } + printf("%s%s%08zx%s\n", prefix, colours->offset, data->size, colours->reset); +} + static void dump_dxbc(const struct vkd3d_shader_dxbc_desc *dxbc_desc, const struct options *options) { const struct colours *colours = &options->colours; @@ -288,6 +352,12 @@ static void dump_dxbc(const struct vkd3d_shader_dxbc_desc *dxbc_desc, const stru colours->index, i, colours->reset, section->tag, dump_tag(tag, section->tag), section->data.size, section->data.size); + + if (!options->list_data) + continue; + printf("\n"); + dump_data(colours, " ", §ion->data); + printf("\n"); } }
@@ -338,7 +408,7 @@ int main(int argc, char **argv) if (ret < 0) goto done;
- if (options.list) + if (options.list || options.list_data) dump_dxbc(&dxbc_desc, &options);
vkd3d_shader_free_dxbc(&dxbc_desc);
This merge request was approved by Giovanni Mascellani.
This merge request was approved by Henri Verbeet.