vkd3d-shader/spirv: Implement outputting opcode names.

This commit is contained in:
Henri Verbeet 2025-02-28 14:17:32 +01:00
parent 997f3f8266
commit bebc550f02
Notes: Henri Verbeet 2025-03-10 15:22:45 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1382
7 changed files with 17191 additions and 12 deletions

View File

@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = @VKD3D_CFLAGS@ AM_CFLAGS = @VKD3D_CFLAGS@
AM_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/include/private -I$(builddir)/include/private AM_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/include/private -I$(builddir)/include/private
AM_LDFLAGS = -no-undefined AM_LDFLAGS = -no-undefined
VKD3D_PERL = $(PERL) -w
widl_headers = \ widl_headers = \
include/vkd3d_d3d12.h \ include/vkd3d_d3d12.h \
@ -319,6 +320,7 @@ vkd3d_demos_headers = \
demos/demo_xcb.h demos/demo_xcb.h
BUILT_SOURCES = $(widl_headers) \ BUILT_SOURCES = $(widl_headers) \
include/private/spirv_grammar.h \
include/private/vkd3d_version.h include/private/vkd3d_version.h
noinst_LTLIBRARIES = libvkd3d-common.la noinst_LTLIBRARIES = libvkd3d-common.la
@ -377,6 +379,7 @@ nodist_libvkd3d_shader_la_SOURCES = $(vkd3d_shader_yyfiles)
libvkd3d_shader_la_SOURCES = \ libvkd3d_shader_la_SOURCES = \
include/private/list.h \ include/private/list.h \
include/private/rbtree.h \ include/private/rbtree.h \
include/private/spirv_grammar.h \
include/private/vkd3d_common.h \ include/private/vkd3d_common.h \
include/private/vkd3d_memory.h \ include/private/vkd3d_memory.h \
include/vkd3d_shader.h \ include/vkd3d_shader.h \
@ -578,6 +581,15 @@ libvkd3d.pc: $(srcdir)/libs/vkd3d/libvkd3d.pc.in Makefile
-e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \ -e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \
$< > $@ $< > $@
VKD3D_V_PERL = $(vkd3d_v_perl_@AM_V@)
vkd3d_v_perl_ = $(vkd3d_v_perl_@AM_DEFAULT_V@)
vkd3d_v_perl_0 = @echo " PERL " $@;
vkd3d_v_perl_1 =
include/private/spirv_grammar.h: libs/vkd3d-shader/make_spirv include/private/spirv.core.grammar.json
@$(MKDIR_P) $(@D)
$(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@
include/private/vkd3d_version.h: dummy-vkd3d-version include/private/vkd3d_version.h: dummy-vkd3d-version
@$(MKDIR_P) include/private @$(MKDIR_P) include/private
version=`(GIT_DIR=$(top_srcdir)/.git git rev-parse --short HEAD 2>/dev/null || echo '') \ version=`(GIT_DIR=$(top_srcdir)/.git git rev-parse --short HEAD 2>/dev/null || echo '') \
@ -586,7 +598,7 @@ include/private/vkd3d_version.h: dummy-vkd3d-version
&& (echo $$version | cmp -s - $@) \ && (echo $$version | cmp -s - $@) \
|| echo $$version >$@ || ($(RM) $@ && exit 1) || echo $$version >$@ || ($(RM) $@ && exit 1)
.SILENT: include/private/vkd3d_version.h .SILENT: include/private/vkd3d_version.h
CLEANFILES += include/private/vkd3d_version.h CLEANFILES += include/private/spirv_grammar.h include/private/vkd3d_version.h
.PHONY: dummy-vkd3d-version .PHONY: dummy-vkd3d-version
dummy-vkd3d-version: dummy-vkd3d-version:

3
README
View File

@ -9,7 +9,8 @@ similar, but not identical, to Direct3D 12.
Building vkd3d Building vkd3d
============== ==============
Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.3.228). Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.3.228), as well as Perl
and libjson-perl.
Vkd3d generates some of its headers from IDL files. If you are using the Vkd3d generates some of its headers from IDL files. If you are using the
release tarballs, then these headers are pre-generated and are included. If release tarballs, then these headers are pre-generated and are included. If

View File

@ -5,6 +5,7 @@ AC_CONFIG_AUX_DIR([bin])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS(include/config.h) AC_CONFIG_HEADERS(include/config.h)
AC_ARG_VAR([PERL], [The Perl 5 language interpreter])
AC_ARG_VAR([WIDL], [widl IDL compiler]) AC_ARG_VAR([WIDL], [widl IDL compiler])
AC_ARG_VAR([CROSSCC32], [32-bit Windows cross compiler]) AC_ARG_VAR([CROSSCC32], [32-bit Windows cross compiler])
AC_ARG_VAR([CROSSCC64], [64-bit Windows cross compiler]) AC_ARG_VAR([CROSSCC64], [64-bit Windows cross compiler])
@ -32,6 +33,11 @@ AC_PROG_MKDIR_P
VKD3D_PROG_WIDL(3, 21) VKD3D_PROG_WIDL(3, 21)
AS_IF([test "x$WIDL" = "xno"], [AC_MSG_WARN([widl is required to build header files.])]) AS_IF([test "x$WIDL" = "xno"], [AC_MSG_WARN([widl is required to build header files.])])
AC_CHECK_PROGS([PERL], [perl], [none])
AS_IF([test "$PERL" = "none"], [AC_MSG_ERROR([no suitable perl found. Please install the 'perl-base' package.])])
VKD3D_CHECK_PERL_MODULE([JSON],
[AC_MSG_ERROR([perl module 'JSON' not found. Please install the 'libjson-perl' package.])])
AC_CHECK_PROGS([FLEX], [flex], [none]) AC_CHECK_PROGS([FLEX], [flex], [none])
AS_IF([test "$FLEX" = "none"], [AC_MSG_ERROR([no suitable flex found. Please install the 'flex' package.])]) AS_IF([test "$FLEX" = "none"], [AC_MSG_ERROR([no suitable flex found. Please install the 'flex' package.])])
AC_ARG_VAR([LFLAGS], [extra flags for flex]) AC_ARG_VAR([LFLAGS], [extra flags for flex])

File diff suppressed because it is too large Load Diff

75
libs/vkd3d-shader/make_spirv Executable file
View File

@ -0,0 +1,75 @@
#!/usr/bin/perl -w
#
# Copyright 2025 Henri Verbeet
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
use strict;
use warnings;
use JSON;
use open ':utf8';
binmode STDOUT, ':utf8';
sub opcode_id($)
{
sprintf "0x%04x", shift;
}
sub grammar_version($)
{
my ($grammar) = @_;
"$grammar->{major_version}.$grammar->{minor_version}.$grammar->{revision}";
}
sub print_opcode_info(_)
{
my ($instruction) = @_;
my $operand_count = @{$instruction->{operands} // []};
print " {${\opcode_id $instruction->{opcode}}, \"$instruction->{opname}\", $operand_count},\n";
}
sub print_header($)
{
my ($grammar) = @_;
print "/* This file is automatically generated from version ${\grammar_version $grammar} of the\n";
print " * machine-readable SPIR-V grammar.\n";
print " *\n";
print " * The original source is covered by the following license:\n";
print " *\n";
print map {" * $_" =~ s/ +$//r . "\n"} @{$grammar->{copyright}};
print " */\n\n";
print "static const struct spirv_parser_opcode_info\n";
print "{\n";
print " uint16_t op;\n";
print " const char *name;\n";
print " size_t operand_count;\n";
print "}\n";
print "spirv_parser_opcode_info[] =\n";
print "{\n";
print_opcode_info foreach sort {$a->{opcode} <=> $b->{opcode}} @{$grammar->{instructions}};
print "};\n";
}
die "No input file specified.\n" unless @ARGV;
print_header do
{
local $/;
open my $fh, '<', $ARGV[0] or die $!;
decode_json <$fh>;
};

View File

@ -18,6 +18,7 @@
*/ */
#include "vkd3d_shader_private.h" #include "vkd3d_shader_private.h"
#include "spirv_grammar.h"
#include "rbtree.h" #include "rbtree.h"
#include <stdarg.h> #include <stdarg.h>
@ -214,6 +215,7 @@ struct spirv_colours
const char *reset; const char *reset;
const char *comment; const char *comment;
const char *literal; const char *literal;
const char *opcode;
}; };
struct spirv_parser struct spirv_parser
@ -310,6 +312,12 @@ static void spirv_parser_print_immediate_word(struct spirv_parser *parser,
prefix, parser->colours.literal, w, parser->colours.reset, suffix); prefix, parser->colours.literal, w, parser->colours.reset, suffix);
} }
static void spirv_parser_print_opcode(struct spirv_parser *parser,
struct vkd3d_string_buffer *buffer, const char *name)
{
vkd3d_string_buffer_printf(buffer, "%s%s%s", parser->colours.opcode, name, parser->colours.reset);
}
static void spirv_parser_print_instruction_offset(struct spirv_parser *parser, static void spirv_parser_print_instruction_offset(struct spirv_parser *parser,
struct vkd3d_string_buffer *buffer, const char *prefix, size_t offset, const char *suffix) struct vkd3d_string_buffer *buffer, const char *prefix, size_t offset, const char *suffix)
{ {
@ -317,6 +325,20 @@ static void spirv_parser_print_instruction_offset(struct spirv_parser *parser,
parser->colours.comment, offset * sizeof(uint32_t), parser->colours.reset, suffix); parser->colours.comment, offset * sizeof(uint32_t), parser->colours.reset, suffix);
} }
static int spirv_parser_opcode_info_compare(const void *key, const void *element)
{
const struct spirv_parser_opcode_info *e = element;
const uint16_t *op = key;
return vkd3d_u32_compare(*op, e->op);
}
static const struct spirv_parser_opcode_info *spirv_parser_get_opcode_info(uint16_t op)
{
return bsearch(&op, spirv_parser_opcode_info, ARRAY_SIZE(spirv_parser_opcode_info),
sizeof(*spirv_parser_opcode_info), spirv_parser_opcode_info_compare);
}
static enum vkd3d_result spirv_parser_read_header(struct spirv_parser *parser) static enum vkd3d_result spirv_parser_read_header(struct spirv_parser *parser)
{ {
uint32_t magic, version, generator, bound, schema; uint32_t magic, version, generator, bound, schema;
@ -384,10 +406,26 @@ static enum vkd3d_result spirv_parser_read_header(struct spirv_parser *parser)
return VKD3D_OK; return VKD3D_OK;
} }
static void spirv_parser_parse_raw_instruction(struct spirv_parser *parser, uint16_t count)
{
size_t pos = parser->pos;
size_t i;
if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT)
vkd3d_string_buffer_printf(parser->text, "%*s", VKD3D_SPIRV_INDENT, "");
for (i = 0; i < count; ++i)
{
spirv_parser_print_immediate_word(parser, parser->text, i ? " " : "", spirv_parser_read_u32(parser), "");
}
if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_OFFSETS)
spirv_parser_print_instruction_offset(parser, parser->text, " ", pos, "");
vkd3d_string_buffer_printf(parser->text, "\n");
}
static enum vkd3d_result spirv_parser_parse_instruction(struct spirv_parser *parser) static enum vkd3d_result spirv_parser_parse_instruction(struct spirv_parser *parser)
{ {
const struct spirv_parser_opcode_info *info;
uint16_t op, count; uint16_t op, count;
unsigned int i;
uint32_t word; uint32_t word;
size_t pos; size_t pos;
@ -403,21 +441,32 @@ static enum vkd3d_result spirv_parser_parse_instruction(struct spirv_parser *par
return VKD3D_ERROR_INVALID_SHADER; return VKD3D_ERROR_INVALID_SHADER;
} }
if (!(info = spirv_parser_get_opcode_info(op)))
{
spirv_parser_warning(parser, VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED,
"Unrecognised instruction %#x.", op);
goto raw;
}
if (info->operand_count)
{
spirv_parser_warning(parser, VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED,
"Operands for instruction \"%s\" not handled.", info->name);
goto raw;
}
if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT) if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT)
vkd3d_string_buffer_printf(parser->text, "%*s", VKD3D_SPIRV_INDENT, ""); vkd3d_string_buffer_printf(parser->text, "%*s", VKD3D_SPIRV_INDENT, "");
spirv_parser_print_immediate_word(parser, parser->text, "", word, ""); spirv_parser_print_opcode(parser, parser->text, info->name);
--count;
for (i = 0; i < count; ++i)
{
spirv_parser_print_immediate_word(parser, parser->text, " ", spirv_parser_read_u32(parser), "");
}
if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_OFFSETS) if (parser->formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_OFFSETS)
spirv_parser_print_instruction_offset(parser, parser->text, " ", pos, ""); spirv_parser_print_instruction_offset(parser, parser->text, " ", pos, "");
vkd3d_string_buffer_printf(parser->text, "\n"); vkd3d_string_buffer_printf(parser->text, "\n");
spirv_parser_warning(parser, VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED, return VKD3D_OK;
"Unrecognised instruction %#x.", op);
raw:
parser->pos = pos;
spirv_parser_parse_raw_instruction(parser, count);
return VKD3D_OK; return VKD3D_OK;
} }
@ -473,12 +522,14 @@ static enum vkd3d_result spirv_parser_init(struct spirv_parser *parser, const st
.reset = "", .reset = "",
.comment = "", .comment = "",
.literal = "", .literal = "",
.opcode = "",
}; };
static const struct spirv_colours colours = static const struct spirv_colours colours =
{ {
.reset = "\x1b[m", .reset = "\x1b[m",
.comment = "\x1b[36m", .comment = "\x1b[36m",
.literal = "\x1b[95m", .literal = "\x1b[95m",
.opcode = "\x1b[96;1m",
}; };
memset(parser, 0, sizeof(*parser)); memset(parser, 0, sizeof(*parser));

7
m4/check-perl-module.m4 Normal file
View File

@ -0,0 +1,7 @@
dnl VKD3D_PERL_MODULE(module, action-if-not-found)
AC_DEFUN([VKD3D_CHECK_PERL_MODULE],
[AC_MSG_CHECKING([for perl module $1])
AS_IF([$PERL -e "use $1;" 2>&AS_MESSAGE_LOG_FD],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
[$2])])