[PATCH vkd3d v3 1/5] vkd3d-shader: Implement an initial pass-through HLSL preprocessor.

Zebediah Figura zfigura at codeweavers.com
Mon Dec 7 12:56:30 CST 2020


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
v3: add the generated flex/bison files to CLEANFILES; avoid a bison warning by
always setting the output file to preproc.tab.c; avoid YYEOF which is only
available since bison 3.6

 .gitignore                               |  3 +
 Makefile.am                              | 31 +++++++-
 configure.ac                             |  6 ++
 libs/vkd3d-shader/preproc.h              | 33 ++++++++
 libs/vkd3d-shader/preproc.l              | 99 ++++++++++++++++++++++++
 libs/vkd3d-shader/preproc.y              | 60 ++++++++++++++
 libs/vkd3d-shader/vkd3d_shader_main.c    | 16 +++-
 libs/vkd3d-shader/vkd3d_shader_private.h |  8 ++
 tests/hlsl_d3d12.c                       | 31 ++++----
 9 files changed, 265 insertions(+), 22 deletions(-)
 create mode 100644 libs/vkd3d-shader/preproc.h
 create mode 100644 libs/vkd3d-shader/preproc.l
 create mode 100644 libs/vkd3d-shader/preproc.y

diff --git a/.gitignore b/.gitignore
index 63a9ffc6..b6d29d19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,10 @@ vkd3d-*.tar.xz
 *.log
 *.o
 *.pc
+*.tab.c
+*.tab.h
 *.trs
+*.yy.c
 *~
 
 .deps
diff --git a/Makefile.am b/Makefile.am
index 5a6e4dc9..32c8777f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -108,6 +108,33 @@ libvkd3d_common_la_SOURCES = \
 
 lib_LTLIBRARIES = libvkd3d-shader.la libvkd3d.la libvkd3d-utils.la
 
+VKD3D_V_FLEX = $(vkd3d_v_flex_ at AM_V@)
+vkd3d_v_flex_ = $(vkd3d_v_flex_ at AM_DEFAULT_V@)
+vkd3d_v_flex_0 = @echo "  FLEX    " $@;
+vkd3d_v_flex_1 =
+
+VKD3D_V_BISON = $(vkd3d_v_bison_ at AM_V@)
+vkd3d_v_bison_ = $(vkd3d_v_bison_ at AM_DEFAULT_V@)
+vkd3d_v_bison_0 = @echo "  BISON   " $@;
+vkd3d_v_bison_1 =
+
+libs/vkd3d-shader/preproc.yy.c: libs/vkd3d-shader/preproc.l
+	$(VKD3D_V_FLEX)$(FLEX) $(LFLAGS) -o $@ $<
+
+libs/vkd3d-shader/preproc.tab.c libs/vkd3d-shader/preproc.tab.h &: libs/vkd3d-shader/preproc.y
+	$(VKD3D_V_BISON)$(BISON) $(YFLAGS) -d -o libs/vkd3d-shader/preproc.tab.c $<
+
+BUILT_SOURCES += libs/vkd3d-shader/preproc.tab.h
+
+vkd3d_shader_yyfiles = \
+	libs/vkd3d-shader/preproc.tab.c \
+	libs/vkd3d-shader/preproc.tab.h \
+	libs/vkd3d-shader/preproc.yy.c
+
+CLEANFILES = $(vkd3d_shader_yyfiles)
+
+nodist_libvkd3d_shader_la_SOURCES = $(vkd3d_shader_yyfiles)
+
 libvkd3d_shader_la_SOURCES = \
 	include/private/list.h \
 	include/private/rbtree.h \
@@ -122,7 +149,7 @@ libvkd3d_shader_la_SOURCES = \
 	libs/vkd3d-shader/vkd3d_shader.map \
 	libs/vkd3d-shader/vkd3d_shader_main.c \
 	libs/vkd3d-shader/vkd3d_shader_private.h
-libvkd3d_shader_la_CFLAGS = $(AM_CFLAGS) @SPIRV_TOOLS_CFLAGS@
+libvkd3d_shader_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libs/vkd3d-shader @SPIRV_TOOLS_CFLAGS@
 libvkd3d_shader_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0
 libvkd3d_shader_la_LIBADD = libvkd3d-common.la @SPIRV_TOOLS_LIBS@
 if HAVE_LD_VERSION_SCRIPT
@@ -173,7 +200,7 @@ EXTRA_DIST = ANNOUNCE LICENSE
 pkgconfigdir = $(libdir)/pkgconfig
 pkginclude_HEADERS = $(vkd3d_public_headers)
 nodist_pkgconfig_DATA = libvkd3d.pc libvkd3d-shader.pc libvkd3d-utils.pc
-CLEANFILES = libvkd3d.pc libvkd3d-shader.pc libvkd3d-utils.pc
+CLEANFILES += libvkd3d.pc libvkd3d-shader.pc libvkd3d-utils.pc
 EXTRA_DIST += \
 	libs/vkd3d/libvkd3d.pc.in \
 	libs/vkd3d-shader/libvkd3d-shader.pc.in \
diff --git a/configure.ac b/configure.ac
index 2f22b05f..b7902b63 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,12 @@ AC_PROG_MKDIR_P
 VKD3D_PROG_WIDL(3, 20)
 AS_IF([test "x$WIDL" = "xno"], [AC_MSG_WARN([widl is required to build header files.])])
 
+AC_CHECK_PROGS([FLEX], [flex], [none])
+AS_IF([test "$FLEX" = "none"], [AC_MSG_ERROR([no suitable flex found. Please install the 'flex' package.])])
+
+AC_CHECK_PROGS([BISON], [bison], [none])
+AS_IF([test "$BISON" = "none"], [AC_MSG_ERROR([no suitable bison found. Please install the 'bison' package.])])
+
 DX_PS_FEATURE([OFF])
 DX_INIT_DOXYGEN([vkd3d], [Doxyfile], [doc])
 AC_CONFIG_FILES([Doxyfile])
diff --git a/libs/vkd3d-shader/preproc.h b/libs/vkd3d-shader/preproc.h
new file mode 100644
index 00000000..cbd93229
--- /dev/null
+++ b/libs/vkd3d-shader/preproc.h
@@ -0,0 +1,33 @@
+/*
+ * HLSL preprocessor
+ *
+ * Copyright 2020 Zebediah Figura 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 __VKD3D_SHADER_PREPROC_H
+#define __VKD3D_SHADER_PREPROC_H
+
+#include "vkd3d_shader_private.h"
+
+struct preproc_ctx
+{
+    void *scanner;
+
+    struct vkd3d_string_buffer buffer;
+};
+
+#endif
diff --git a/libs/vkd3d-shader/preproc.l b/libs/vkd3d-shader/preproc.l
new file mode 100644
index 00000000..656ad674
--- /dev/null
+++ b/libs/vkd3d-shader/preproc.l
@@ -0,0 +1,99 @@
+/*
+ * HLSL preprocessor
+ *
+ * Copyright 2020 Zebediah Figura 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
+ */
+
+%{
+
+#include "preproc.tab.h"
+
+#define YYSTYPE PREPROC_YYSTYPE
+#define YYLTYPE PREPROC_YYLTYPE
+
+#define YY_DECL static int preproc_lexer_lex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner)
+
+%}
+
+%option 8bit
+%option bison-bridge
+%option bison-locations
+%option extra-type="struct preproc_ctx *"
+%option never-interactive
+%option noinput
+%option nounput
+%option noyywrap
+%option prefix="preproc_yy"
+%option reentrant
+
+WS              [ \t]
+
+%%
+
+{WS}+                               {}
+.                                   {return T_TEXT;}
+
+%%
+
+int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner)
+{
+    struct preproc_ctx *ctx = yyget_extra(scanner);
+
+    for (;;)
+    {
+        const char *text;
+        int token;
+
+        if (!(token = preproc_lexer_lex(lval, lloc, scanner)))
+            return 0;
+        text = yyget_text(scanner);
+
+        TRACE("Parsing token %d, string %s.\n", token, debugstr_a(text));
+
+        vkd3d_string_buffer_printf(&ctx->buffer, "%s ", text);
+    }
+}
+
+int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
+        struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context)
+{
+    struct preproc_ctx ctx = {0};
+    YY_BUFFER_STATE top_buffer;
+    void *output_code;
+
+    vkd3d_string_buffer_init(&ctx.buffer);
+
+    yylex_init_extra(&ctx, &ctx.scanner);
+    top_buffer = yy_scan_bytes(compile_info->source.code, compile_info->source.size, ctx.scanner);
+
+    preproc_yyparse(ctx.scanner, &ctx);
+
+    yy_delete_buffer(top_buffer, ctx.scanner);
+    yylex_destroy(ctx.scanner);
+
+    if (!(output_code = vkd3d_malloc(ctx.buffer.content_size)))
+    {
+        vkd3d_string_buffer_cleanup(&ctx.buffer);
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+    }
+    memcpy(output_code, ctx.buffer.buffer, ctx.buffer.content_size);
+    out->size = ctx.buffer.content_size;
+    out->code = output_code;
+    vkd3d_string_buffer_trace(&ctx.buffer);
+    vkd3d_string_buffer_cleanup(&ctx.buffer);
+    return VKD3D_OK;
+}
diff --git a/libs/vkd3d-shader/preproc.y b/libs/vkd3d-shader/preproc.y
new file mode 100644
index 00000000..92448f24
--- /dev/null
+++ b/libs/vkd3d-shader/preproc.y
@@ -0,0 +1,60 @@
+/*
+ * HLSL preprocessor
+ *
+ * Copyright 2020 Zebediah Figura 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
+ */
+
+%code requires
+{
+
+#include "vkd3d_shader_private.h"
+#include "preproc.h"
+
+}
+
+%code provides
+{
+
+int preproc_yylex(PREPROC_YYSTYPE *yylval_param, PREPROC_YYLTYPE *yylloc_param, void *scanner);
+
+}
+
+%code
+{
+
+static void yyerror(const YYLTYPE *loc, void *scanner, struct preproc_ctx *ctx, const char *string)
+{
+    FIXME("Error reporting is not implemented.\n");
+}
+
+}
+
+%define api.prefix {preproc_yy}
+%define api.pure full
+%define parse.error verbose
+%expect 0
+%locations
+%lex-param {yyscan_t scanner}
+%parse-param {void *scanner}
+%parse-param {struct preproc_ctx *ctx}
+
+%token T_TEXT
+
+%%
+
+shader_text
+    : %empty
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c
index 1a029246..eed0316c 100644
--- a/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -78,8 +78,7 @@ int vkd3d_string_buffer_vprintf(struct vkd3d_string_buffer *buffer, const char *
     }
 }
 
-static int VKD3D_PRINTF_FUNC(2, 3) vkd3d_string_buffer_printf(struct vkd3d_string_buffer *buffer,
-        const char *format, ...)
+int vkd3d_string_buffer_printf(struct vkd3d_string_buffer *buffer, const char *format, ...)
 {
     va_list args;
     int ret;
@@ -91,7 +90,7 @@ static int VKD3D_PRINTF_FUNC(2, 3) vkd3d_string_buffer_printf(struct vkd3d_strin
     return ret;
 }
 
-static void vkd3d_string_buffer_trace_(const struct vkd3d_string_buffer *buffer, const char *function)
+void vkd3d_string_buffer_trace_(const struct vkd3d_string_buffer *buffer, const char *function)
 {
     const char *p, *q, *end = buffer->buffer + buffer->content_size;
 
@@ -1154,6 +1153,7 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types(
 int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info,
         struct vkd3d_shader_code *out, char **messages)
 {
+    struct vkd3d_shader_message_context message_context;
     int ret;
 
     TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages);
@@ -1164,5 +1164,13 @@ int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info
     if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
         return ret;
 
-    return VKD3D_ERROR_NOT_IMPLEMENTED;
+    vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name);
+
+    ret = preproc_lexer_parse(compile_info, out, &message_context);
+
+    vkd3d_shader_message_context_trace_messages(&message_context);
+    if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
+        ret = VKD3D_ERROR_OUT_OF_MEMORY;
+    vkd3d_shader_message_context_cleanup(&message_context);
+    return ret;
 }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index 5ae5724a..83038384 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -837,6 +837,11 @@ struct vkd3d_string_buffer
 enum vkd3d_result vkd3d_dxbc_binary_to_text(void *data, struct vkd3d_shader_code *out) DECLSPEC_HIDDEN;
 void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer) DECLSPEC_HIDDEN;
 void vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer) DECLSPEC_HIDDEN;
+int vkd3d_string_buffer_printf(struct vkd3d_string_buffer *buffer,
+        const char *format, ...) VKD3D_PRINTF_FUNC(2, 3) DECLSPEC_HIDDEN;
+#define vkd3d_string_buffer_trace(buffer) \
+        vkd3d_string_buffer_trace_(buffer, __FUNCTION__)
+void vkd3d_string_buffer_trace_(const struct vkd3d_string_buffer *buffer, const char *function) DECLSPEC_HIDDEN;
 int vkd3d_string_buffer_vprintf(struct vkd3d_string_buffer *buffer, const char *format, va_list args) DECLSPEC_HIDDEN;
 
 struct vkd3d_shader_message_context
@@ -882,6 +887,9 @@ void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler) DECLSPEC_
 
 void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) DECLSPEC_HIDDEN;
 
+int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
+        struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+
 static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_type(
         enum vkd3d_data_type data_type)
 {
diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c
index 4f4cc37f..787355ba 100644
--- a/tests/hlsl_d3d12.c
+++ b/tests/hlsl_d3d12.c
@@ -30,22 +30,20 @@ static void check_preprocess_(int line, const char *source, const D3D_SHADER_MAC
     HRESULT hr;
 
     hr = D3DPreprocess(source, strlen(source), NULL, macros, include, &blob, &errors);
-    todo ok_(line)(hr == S_OK, "Failed to preprocess shader, hr %#x.\n", hr);
+    assert_that_(line)(hr == S_OK, "Failed to preprocess shader, hr %#x.\n", hr);
     if (errors)
     {
         if (vkd3d_test_state.debug_level)
             trace_(line)("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors));
         ID3D10Blob_Release(errors);
     }
-    if (hr != S_OK)
-        return;
     code = ID3D10Blob_GetBufferPointer(blob);
     size = ID3D10Blob_GetBufferSize(blob);
     if (present)
         ok_(line)(vkd3d_memmem(code, size, present, strlen(present)),
                 "\"%s\" not found in preprocessed shader.\n", present);
     if (absent)
-        ok_(line)(!vkd3d_memmem(code, size, absent, strlen(absent)),
+        assert_that_(line)(!vkd3d_memmem(code, size, absent, strlen(absent)),
                 "\"%s\" found in preprocessed shader.\n", absent);
     ID3D10Blob_Release(blob);
 }
@@ -352,7 +350,8 @@ static void test_preprocess(void)
     for (i = 0; i < ARRAY_SIZE(tests); ++i)
     {
         vkd3d_test_set_context("Source \"%s\"", tests[i].source);
-        check_preprocess(tests[i].source, NULL, NULL, tests[i].present, tests[i].absent);
+        todo_if (i != 5 && i != 8 && i != 42)
+            check_preprocess(tests[i].source, NULL, NULL, tests[i].present, tests[i].absent);
     }
     vkd3d_test_set_context(NULL);
 
@@ -360,16 +359,16 @@ static void test_preprocess(void)
     macros[0].Definition = "value";
     macros[1].Name = NULL;
     macros[1].Definition = NULL;
-    check_preprocess("KEY", macros, NULL, "value", "KEY");
+    todo check_preprocess("KEY", macros, NULL, "value", "KEY");
 
-    check_preprocess("#undef KEY\nKEY", macros, NULL, "KEY", "value");
+    todo check_preprocess("#undef KEY\nKEY", macros, NULL, "KEY", "value");
 
     macros[0].Name = NULL;
-    check_preprocess("KEY", macros, NULL, "KEY", "value");
+    todo check_preprocess("KEY", macros, NULL, "KEY", "value");
 
     macros[0].Name = "KEY";
     macros[0].Definition = NULL;
-    check_preprocess("KEY", macros, NULL, NULL, "KEY");
+    todo check_preprocess("KEY", macros, NULL, NULL, "KEY");
 
     macros[0].Name = "0";
     macros[0].Definition = "value";
@@ -377,7 +376,7 @@ static void test_preprocess(void)
 
     macros[0].Name = "KEY(a)";
     macros[0].Definition = "value";
-    check_preprocess("KEY(a)", macros, NULL, "KEY", "value");
+    todo check_preprocess("KEY(a)", macros, NULL, "KEY", "value");
 
     macros[0].Name = "KEY";
     macros[0].Definition = "value1";
@@ -385,33 +384,33 @@ static void test_preprocess(void)
     macros[1].Definition = "value2";
     macros[2].Name = NULL;
     macros[2].Definition = NULL;
-    check_preprocess("KEY", macros, NULL, "value2", NULL);
+    todo check_preprocess("KEY", macros, NULL, "value2", NULL);
 
     macros[0].Name = "KEY";
     macros[0].Definition = "KEY2";
     macros[1].Name = "KEY2";
     macros[1].Definition = "value";
-    check_preprocess("KEY", macros, NULL, "value", NULL);
+    todo check_preprocess("KEY", macros, NULL, "value", NULL);
 
     macros[0].Name = "KEY2";
     macros[0].Definition = "value";
     macros[1].Name = "KEY";
     macros[1].Definition = "KEY2";
-    check_preprocess("KEY", macros, NULL, "value", NULL);
+    todo check_preprocess("KEY", macros, NULL, "value", NULL);
 
-    check_preprocess(test_include_top, NULL, &test_include, "pass", "fail");
+    todo check_preprocess(test_include_top, NULL, &test_include, "pass", "fail");
     ok(!refcount_file1, "Got %d references to file1.\n", refcount_file1);
     ok(!refcount_file2, "Got %d references to file1.\n", refcount_file2);
     ok(!refcount_file3, "Got %d references to file1.\n", refcount_file3);
     todo ok(include_count_file2 == 2, "file2 was included %u times.\n", include_count_file2);
 
     /* Macro invocation spread across multiple files. */
-    check_preprocess(test_include2_top, NULL, &test_include, "pass", NULL);
+    todo check_preprocess(test_include2_top, NULL, &test_include, "pass", NULL);
 
     blob = errors = (ID3D10Blob *)0xdeadbeef;
     hr = D3DPreprocess(test_include_top, strlen(test_include_top), NULL, NULL, &test_include_fail, &blob, &errors);
     todo ok(hr == E_FAIL, "Got hr %#x.\n", hr);
-    ok(blob == (ID3D10Blob *)0xdeadbeef, "Expected no compiled shader blob.\n");
+    todo ok(blob == (ID3D10Blob *)0xdeadbeef, "Expected no compiled shader blob.\n");
     todo ok(!!errors, "Expected non-NULL error blob.\n");
     if (errors)
     {
-- 
2.29.2




More information about the wine-devel mailing list