Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • wine/vkd3d
  • stefan/vkd3d
  • cmccarthy/vkd3d
  • giomasce/vkd3d
  • fcasas/vkd3d
  • jactry/vkd3d
  • ReDress/vkd3d
  • mstorsjo/vkd3d
  • huw/vkd3d
  • julliard/vkd3d
  • bshanks/vkd3d
  • zfigura/vkd3d
  • hverbeet/vkd3d
  • DarkShadow44/vkd3d
  • nsivov/vkd3d
  • dhary686/vkd3d
  • Mystral/vkd3d
  • maljaf/vkd3d
  • smcv/vkd3d
  • flibitijibibo/vkd3d
  • q4a/vkd3d
  • jsikorski/vkd3d
  • alesliehughes/vkd3d-alesliehughes
  • vitorhnn/vkd3d
  • agusev/vkd3d
  • etang-cw/vkd3d
  • petrathekat/vkd3d
  • simon.mr995/vkd3d
  • sgwaki/vkd3d
  • jacek/vkd3d
  • fweimer/vkd3d
  • Clara/vkd3d
  • disini/vkd3d
  • antenabr2/vkd3d
  • gilvbp/vkd3d
  • yshui/vkd3d
  • shaunren/vkd3d
  • jennetsaryyewa96/vkd3d
  • Jamesattay/vkd3d
  • zacemmneeto77/vkd3d
  • GermanAizek/vkd3d
  • opespinach/vkd3d
  • ruslanboyka201/vkd3d
  • navi/vkd3d
  • Feifan/vkd3d
  • yashmhmdly172/vkd3d
  • Sec32fun32/vkd3d
  • ritalat/vkd3d
  • ivyl/vkd3d
  • baikaishiuc/vkd3d
  • austin987/vkd3d
  • TornadoCookie/vkd3d
52 results
Show changes
Commits on Source (75)
Showing
with 1193 additions and 171 deletions
......@@ -23,6 +23,7 @@ vkd3d-*.tar.xz
*.tab.c
*.tab.h
*.trs
*.txt
*.yy.c
*~
......
stages:
- image
- build
- test
include:
- local: "/gitlab/image.yml"
- local: "/gitlab/build.yml"
- local: "/gitlab/test.yml"
......@@ -24,6 +24,7 @@ vkd3d_public_headers = \
include/vkd3d_d3d9types.h \
include/vkd3d_d3dcommon.h \
include/vkd3d_d3dcompiler.h \
include/vkd3d_d3dcompiler_types.h \
include/vkd3d_d3dx9shader.h \
include/vkd3d_dxgibase.h \
include/vkd3d_dxgiformat.h \
......@@ -166,9 +167,13 @@ vkd3d_shader_tests = \
tests/hlsl/struct-array.shader_test \
tests/hlsl/struct-assignment.shader_test \
tests/hlsl/struct-semantics.shader_test \
tests/hlsl/switch.shader_test \
tests/hlsl/swizzle-constant-prop.shader_test \
tests/hlsl/swizzle-matrix.shader_test \
tests/hlsl/swizzles.shader_test \
tests/hlsl/technique-fx_2.shader_test \
tests/hlsl/technique-fx_4.shader_test \
tests/hlsl/technique-fx_5.shader_test \
tests/hlsl/ternary.shader_test \
tests/hlsl/texture-load-offset.shader_test \
tests/hlsl/texture-load-typed.shader_test \
......@@ -480,6 +485,9 @@ shader_runner_cross_sources = \
$(srcdir)/tests/shader_runner_d3d11.c \
$(srcdir)/tests/shader_runner_d3d12.c
driver_cross_sources = \
$(srcdir)/tests/driver.c
if HAVE_CROSSTARGET32
CROSS32_CC = @CROSSCC32@
CROSS32_DLLTOOL = @CROSSTARGET32@-dlltool
......@@ -495,6 +503,7 @@ endif
CROSS32_FILES = $(CROSS32_EXEFILES)
if BUILD_TESTS
CROSS32_FILES += tests/shader_runner.cross32.exe
CROSS32_FILES += tests/driver.cross32.exe
endif
CLEANFILES += $(CROSS32_IMPLIBS) $(CROSS32_FILES)
......@@ -517,6 +526,11 @@ tests/shader_runner.cross32.exe: $(shader_runner_cross_sources) $(CROSS32_IMPLIB
$(CROSS32_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(shader_runner_cross_sources) $(CROSS32_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
$(am__mv) $$depbase.Tpo $$depbase.Po
tests/driver.cross32.exe: $(driver_cross_sources)
$(AM_V_CCLD)depbase=`echo $@ | sed 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
$(CROSS32_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(driver_cross_sources) && \
$(am__mv) $$depbase.Tpo $$depbase.Po
else
crosstest32:
endif
......@@ -536,6 +550,7 @@ endif
CROSS64_FILES = $(CROSS64_EXEFILES)
if BUILD_TESTS
CROSS64_FILES += tests/shader_runner.cross64.exe
CROSS64_FILES += tests/driver.cross64.exe
endif
CLEANFILES += $(CROSS64_IMPLIBS) $(CROSS64_FILES)
......@@ -558,12 +573,28 @@ tests/shader_runner.cross64.exe: $(shader_runner_cross_sources) $(CROSS64_IMPLIB
$(CROSS64_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(shader_runner_cross_sources) $(CROSS64_IMPLIBS) -ldxgi -lgdi32 -ld3dcompiler_47 && \
$(am__mv) $$depbase.Tpo $$depbase.Po
tests/driver.cross64.exe: $(driver_cross_sources)
$(AM_V_CCLD)depbase=`echo $@ | sed 's![^/]*$$!$(DEPDIR)/&!;s!\.exe$$!!'`; \
$(CROSS64_CC) $(CROSS_CFLAGS) -MT $@ -MD -MP -MF $$depbase.Tpo -o $@ $(driver_cross_sources) && \
$(am__mv) $$depbase.Tpo $$depbase.Po
else
crosstest64:
endif
.PHONY: crosstest crosstest32 crosstest64
crosstest: crosstest32 crosstest64
tests/crosstests.txt: FORCE
$(AM_V_GEN) for i in $(vkd3d_cross_tests) ; do echo $$i ; done > $@
tests/shader_tests.txt: FORCE
$(AM_V_GEN) for i in $(vkd3d_shader_tests) ; do echo $$i ; done > $@
crosstest-lists: tests/crosstests.txt tests/shader_tests.txt
CLEANFILES += tests/crosstests.txt tests/shader_tests.txt
FORCE:
.PHONY: crosstest crosstest32 crosstest64 crosstest-lists FORCE
crosstest: crosstest32 crosstest64 crosstest-lists
if BUILD_DOC
@DX_RULES@
......
......@@ -19,9 +19,10 @@ MoltenVK as the Vulkan driver. The llvmpipe and macOS jobs are
currently allowed to fail.
Additionally, MinGW is used to build PE binaries for both vkd3d and
its crosstests, for both 32 and 64 bit. These builds are not currently
tested (but the pipeline still fails if the compilation is not
successful).
its crosstests, for both 32 and 64 bit. The PE crosstests are executed
on Windows 10 to check that behavior imposed by the tests corresponds
to Microsoft's D3D12 implementation. The rendering backend is
currently Window's WARP software implementation.
The testing logs are available as CI artifacts, as well as the PE
modules built by the crosstest and MinGW jobs.
......@@ -58,3 +59,6 @@ environment for running the tests. All the software required to
compile and run the tests will therefore have to be installed directly
on the host system. Complete instructions to setup the macOS are
currently not available.
Finally, a runner tagged with `win10-21h2' must be available and
submit jobs to a Windows 10 virtual machine.
......@@ -19,6 +19,9 @@ cd build
touch ../pipeline_failed
mkdir -p ../artifacts/$COMMIT
rsync -Rr config.log tests/*.exe ../artifacts/$COMMIT
rsync -Rr config.log tests/*.txt tests/*.exe ../artifacts/$COMMIT || true
# Make the driver easily available to the Windows CI job
cp tests/driver.cross64.exe ../artifacts
git reset --hard
......@@ -18,6 +18,6 @@ export LD_LIBRARY_PATH=/usr/local/lib
touch ../pipeline_failed
mkdir -p ../artifacts/$COMMIT
rsync -Rr config.log doc/* test-suite.log tests/*.log tests/*/*.log ../artifacts/$COMMIT
rsync -Rr config.log doc/* test-suite.log tests/*.log tests/*/*.log ../artifacts/$COMMIT || true
git reset --hard
......@@ -17,6 +17,6 @@ cd build
touch ../pipeline_failed
mkdir -p ../artifacts/$COMMIT
rsync -Rr config.log test-suite.log tests/*.log tests/*/*.log ../artifacts/$COMMIT
rsync -Rr config.log test-suite.log tests/*.log tests/*/*.log ../artifacts/$COMMIT || true
git reset --hard
......@@ -19,7 +19,7 @@ cp -r /usr/include/vulkan /usr/include/vk_video /usr/include/spirv vulkan-header
touch ../pipeline_failed
mkdir -p ../artifacts/$COMMIT
cp config.log ../artifacts/$COMMIT
cp destdir/usr/local/bin/* ../artifacts/$COMMIT
cp config.log ../artifacts/$COMMIT || true
cp destdir/usr/local/bin/* ../artifacts/$COMMIT || true
git reset --hard
......@@ -153,6 +153,7 @@ build-mac:
variables:
VKD3D_DISABLE_EXTENSIONS: "VK_EXT_descriptor_indexing"
VKD3D_SHADER_CONFIG: 'force_validation'
MVK_CONFIG_LOG_LEVEL: 1
artifacts:
when: always
paths:
......
test-win-64:
stage: test
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
interruptible: true
needs:
- job: build-crosstest
tags:
- win10-21h2
script:
- ./artifacts/driver.cross64.exe
variables:
TEST_ARCH: "64"
artifacts:
when: always
paths:
- artifacts
test-win-32:
stage: test
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
interruptible: true
needs:
- job: build-crosstest
tags:
- win10-21h2
script:
- ./artifacts/driver.cross64.exe
variables:
TEST_ARCH: "32"
artifacts:
when: always
paths:
- artifacts
......@@ -20,6 +20,8 @@
#define __VKD3D_D3DCOMPILER_H
#ifndef __D3DCOMPILER_H__
#include <vkd3d_d3dcompiler_types.h>
#define D3DCOMPILE_DEBUG 0x00000001
#define D3DCOMPILE_SKIP_VALIDATION 0x00000002
#define D3DCOMPILE_SKIP_OPTIMIZATION 0x00000004
......@@ -58,27 +60,6 @@
#define D3DCOMPILE_SECDATA_PRESERVE_TEMPLATE_SLOTS 0x00000002
#define D3DCOMPILE_SECDATA_REQUIRE_TEMPLATE_MATCH 0x00000004
typedef enum D3D_BLOB_PART
{
D3D_BLOB_INPUT_SIGNATURE_BLOB,
D3D_BLOB_OUTPUT_SIGNATURE_BLOB,
D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB,
D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB,
D3D_BLOB_ALL_SIGNATURE_BLOB,
D3D_BLOB_DEBUG_INFO,
D3D_BLOB_LEGACY_SHADER,
D3D_BLOB_XNA_PREPASS_SHADER,
D3D_BLOB_XNA_SHADER,
D3D_BLOB_PDB,
D3D_BLOB_PRIVATE_DATA,
D3D_BLOB_ROOT_SIGNATURE,
D3D_BLOB_DEBUG_NAME,
D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000,
D3D_BLOB_TEST_COMPILE_DETAILS,
D3D_BLOB_TEST_COMPILE_PERF,
D3D_BLOB_TEST_COMPILE_REPORT
} D3D_BLOB_PART;
typedef enum D3DCOMPILER_STRIP_FLAGS
{
D3DCOMPILER_STRIP_REFLECTION_DATA = 0x00000001,
......
/*
* Copyright 2010 Matteo Bruni 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_D3DCOMPILER_TYPES_H
#define __VKD3D_D3DCOMPILER_TYPES_H
#ifndef __D3DCOMPILER_H__
typedef enum D3D_BLOB_PART
{
D3D_BLOB_INPUT_SIGNATURE_BLOB,
D3D_BLOB_OUTPUT_SIGNATURE_BLOB,
D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB,
D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB,
D3D_BLOB_ALL_SIGNATURE_BLOB,
D3D_BLOB_DEBUG_INFO,
D3D_BLOB_LEGACY_SHADER,
D3D_BLOB_XNA_PREPASS_SHADER,
D3D_BLOB_XNA_SHADER,
D3D_BLOB_PDB,
D3D_BLOB_PRIVATE_DATA,
D3D_BLOB_ROOT_SIGNATURE,
D3D_BLOB_DEBUG_NAME,
D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000,
D3D_BLOB_TEST_COMPILE_DETAILS,
D3D_BLOB_TEST_COMPILE_PERF,
D3D_BLOB_TEST_COMPILE_REPORT
} D3D_BLOB_PART;
#endif /* __D3DCOMPILER_H__ */
#endif /* __VKD3D_D3DCOMPILER_TYPES_H */
......@@ -20,6 +20,7 @@
#define __VKD3D_UTILS_H
#include <vkd3d.h>
#include <vkd3d_d3dcompiler_types.h>
#ifndef VKD3D_UTILS_API_VERSION
#define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_0
......@@ -51,9 +52,6 @@ extern "C" {
# define VKD3D_UTILS_API VKD3D_IMPORT
#endif
/** \since 1.10 */
typedef enum D3D_BLOB_PART D3D_BLOB_PART;
/* 1.0 */
VKD3D_UTILS_API HANDLE vkd3d_create_event(void);
VKD3D_UTILS_API HRESULT vkd3d_signal_event(HANDLE event);
......
......@@ -152,6 +152,7 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_FIRSTBIT_LO ] = "firstbit_lo",
[VKD3DSIH_FIRSTBIT_SHI ] = "firstbit_shi",
[VKD3DSIH_FRC ] = "frc",
[VKD3DSIH_FREM ] = "frem",
[VKD3DSIH_FTOD ] = "ftod",
[VKD3DSIH_FTOI ] = "ftoi",
[VKD3DSIH_FTOU ] = "ftou",
......@@ -170,6 +171,7 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_HS_JOIN_PHASE ] = "hs_join_phase",
[VKD3DSIH_IADD ] = "iadd",
[VKD3DSIH_IBFE ] = "ibfe",
[VKD3DSIH_IDIV ] = "idiv",
[VKD3DSIH_IEQ ] = "ieq",
[VKD3DSIH_IF ] = "if",
[VKD3DSIH_IFC ] = "ifc",
......@@ -358,11 +360,6 @@ struct vkd3d_d3d_asm_compiler
struct vkd3d_d3d_asm_colours colours;
};
static int shader_ver_ge(const struct vkd3d_shader_version *v, int major, int minor)
{
return v->major > major || (v->major == major && v->minor >= minor);
}
static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...)
{
va_list args;
......@@ -424,7 +421,7 @@ static void shader_dump_global_flags(struct vkd3d_d3d_asm_compiler *compiler,
}
if (global_flags)
vkd3d_string_buffer_printf(&compiler->buffer, "unknown_flags(%#"PRIx64")", global_flags);
vkd3d_string_buffer_printf(&compiler->buffer, "unknown_flags(%#"PRIx64")", (uint64_t)global_flags);
}
static void shader_dump_sync_flags(struct vkd3d_d3d_asm_compiler *compiler, uint32_t sync_flags)
......@@ -684,7 +681,7 @@ static void shader_dump_decl_usage(struct vkd3d_d3d_asm_compiler *compiler,
else
{
/* Pixel shaders 3.0 don't have usage semantics. */
if (!shader_ver_ge(&compiler->shader_version, 3, 0)
if (!vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0)
&& compiler->shader_version.type == VKD3D_SHADER_TYPE_PIXEL)
return;
else
......@@ -908,7 +905,7 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
case VKD3DSPR_TEXCRDOUT:
/* Vertex shaders >= 3.0 use general purpose output registers
* (VKD3DSPR_OUTPUT), which can include an address token. */
if (shader_ver_ge(&compiler->shader_version, 3, 0))
if (vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0))
shader_addline(buffer, "o");
else
shader_addline(buffer, "oT");
......@@ -1174,7 +1171,7 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
{
if (offset != ~0u)
{
bool is_sm_5_1 = shader_ver_ge(&compiler->shader_version, 5, 1);
bool is_sm_5_1 = vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1);
if (reg->idx[0].rel_addr || reg->type == VKD3DSPR_IMMCONSTBUFFER
|| reg->type == VKD3DSPR_INCONTROLPOINT || (reg->type == VKD3DSPR_INPUT
......@@ -1570,7 +1567,7 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
break;
case VKD3DSIH_TEX:
if (shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT))
if (vkd3d_shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT))
shader_addline(buffer, "p");
break;
......@@ -1582,7 +1579,7 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
static void shader_dump_register_space(struct vkd3d_d3d_asm_compiler *compiler, unsigned int register_space)
{
if (shader_ver_ge(&compiler->shader_version, 5, 1))
if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1))
shader_print_uint_literal(compiler, ", space=", register_space, "");
}
......@@ -1626,9 +1623,9 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
case VKD3DSIH_DCL_CONSTANT_BUFFER:
vkd3d_string_buffer_printf(buffer, " ");
shader_dump_register(compiler, &ins->declaration.cb.src.reg, true);
if (shader_ver_ge(&compiler->shader_version, 6, 0))
if (vkd3d_shader_ver_ge(&compiler->shader_version, 6, 0))
shader_print_subscript(compiler, ins->declaration.cb.size, NULL);
else if (shader_ver_ge(&compiler->shader_version, 5, 1))
else if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1))
shader_print_subscript(compiler, ins->declaration.cb.size / VKD3D_VEC4_SIZE / sizeof(float), NULL);
shader_addline(buffer, ", %s",
ins->flags & VKD3DSI_INDEXED_DYNAMIC ? "dynamicIndexed" : "immediateIndexed");
......
......@@ -402,16 +402,6 @@ static uint32_t read_u32(const uint32_t **ptr)
return *(*ptr)++;
}
static bool shader_ver_ge(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor)
{
return v->major > major || (v->major == major && v->minor >= minor);
}
static bool shader_ver_le(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor)
{
return v->major < major || (v->major == major && v->minor <= minor);
}
static bool has_relative_address(uint32_t param)
{
enum vkd3d_sm1_address_mode_type address_mode;
......@@ -434,8 +424,8 @@ static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info(
return NULL;
if (opcode == info->sm1_opcode
&& shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor)
&& (shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor)
&& vkd3d_shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor)
&& (vkd3d_shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor)
|| !info->max_version.major))
return info;
}
......@@ -555,9 +545,9 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp
return false;
element = &signature->elements[signature->element_count++];
memset(element, 0, sizeof(*element));
element->semantic_name = name;
element->semantic_index = index;
element->stream_index = 0;
element->sysval_semantic = sysval;
element->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
element->register_index = register_index;
......@@ -565,7 +555,8 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp
element->register_count = 1;
element->mask = mask;
element->used_mask = is_dcl ? 0 : mask;
element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE;
if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output)
element->interpolation_mode = VKD3DSIM_LINEAR;
return true;
}
......@@ -1262,7 +1253,7 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1,
return VKD3D_ERROR_INVALID_SHADER;
}
if (!shader_ver_le(&version, 3, 0))
if (!vkd3d_shader_ver_le(&version, 3, 0))
{
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN,
"Invalid shader version %u.%u (token 0x%08x).", version.major, version.minor, code[0]);
......
This diff is collapsed.
......@@ -249,14 +249,7 @@ static enum hlsl_regset type_get_regset(const struct hlsl_type *type)
enum hlsl_regset hlsl_deref_get_regset(struct hlsl_ctx *ctx, const struct hlsl_deref *deref)
{
struct hlsl_type *type;
if (deref->data_type)
type = deref->data_type;
else
type = hlsl_deref_get_type(ctx, deref);
return type_get_regset(type);
return type_get_regset(hlsl_deref_get_type(ctx, deref));
}
unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset)
......@@ -519,7 +512,9 @@ static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hl
{
deref->var = var;
deref->path_len = path_len;
deref->offset.node = NULL;
deref->rel_offset.node = NULL;
deref->const_offset = 0;
deref->data_type = NULL;
if (path_len == 0)
{
......@@ -546,7 +541,8 @@ bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *d
deref->path = NULL;
deref->path_len = 0;
deref->offset.node = NULL;
deref->rel_offset.node = NULL;
deref->const_offset = 0;
assert(chain);
if (chain->type == HLSL_IR_INDEX)
......@@ -609,7 +605,7 @@ struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_de
assert(deref);
if (deref->offset.node)
if (hlsl_deref_is_lowered(deref))
return deref->data_type;
type = deref->var->data_type;
......@@ -763,7 +759,7 @@ struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim
{
struct hlsl_type *type;
if (!(type = vkd3d_calloc(1, sizeof(*type))))
if (!(type = hlsl_alloc(ctx, sizeof(*type))))
return NULL;
type->class = HLSL_CLASS_OBJECT;
type->base_type = HLSL_TYPE_UAV;
......@@ -1120,7 +1116,7 @@ bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struc
if (!other)
return true;
assert(!other->offset.node);
assert(!hlsl_deref_is_lowered(other));
if (!init_deref(ctx, deref, other->var, other->path_len))
return false;
......@@ -1142,7 +1138,8 @@ void hlsl_cleanup_deref(struct hlsl_deref *deref)
deref->path = NULL;
deref->path_len = 0;
hlsl_src_remove(&deref->offset);
hlsl_src_remove(&deref->rel_offset);
deref->const_offset = 0;
}
/* Initializes a simple variable dereference, so that it can be passed to load/store functions. */
......@@ -1177,7 +1174,7 @@ struct hlsl_ir_node *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hls
unsigned int i;
assert(lhs);
assert(!lhs->offset.node);
assert(!hlsl_deref_is_lowered(lhs));
if (!(store = hlsl_alloc(ctx, sizeof(*store))))
return NULL;
......@@ -1343,6 +1340,40 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond
return &iff->node;
}
struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value,
bool is_default, struct hlsl_block *body, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_switch_case *c;
if (!(c = hlsl_alloc(ctx, sizeof(*c))))
return NULL;
c->value = value;
c->is_default = is_default;
hlsl_block_init(&c->body);
if (body)
hlsl_block_add_block(&c->body, body);
c->loc = *loc;
return c;
}
struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector,
struct list *cases, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_switch *s;
if (!(s = hlsl_alloc(ctx, sizeof(*s))))
return NULL;
init_node(&s->node, HLSL_IR_SWITCH, NULL, loc);
hlsl_src_from_node(&s->selector, selector);
list_init(&s->cases);
if (cases)
list_move_head(&s->cases, cases);
return &s->node;
}
struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl_deref *deref,
struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc)
{
......@@ -1350,7 +1381,7 @@ struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl
struct hlsl_type *type;
unsigned int i;
assert(!deref->offset.node);
assert(!hlsl_deref_is_lowered(deref));
type = hlsl_deref_get_type(ctx, deref);
if (idx)
......@@ -1586,7 +1617,7 @@ static bool clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block,
if (!list_empty(&src->uses))
{
if (!vkd3d_array_reserve((void **)&map->instrs, &map->capacity, map->count + 1, sizeof(*map->instrs)))
if (!hlsl_array_reserve(ctx, (void **)&map->instrs, &map->capacity, map->count + 1, sizeof(*map->instrs)))
{
hlsl_block_cleanup(dst_block);
return false;
......@@ -1623,7 +1654,7 @@ static bool clone_deref(struct hlsl_ctx *ctx, struct clone_instr_map *map,
{
unsigned int i;
assert(!src->offset.node);
assert(!hlsl_deref_is_lowered(src));
if (!init_deref(ctx, dst, src->var, src->path_len))
return false;
......@@ -1805,6 +1836,58 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr
return dst;
}
void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c)
{
hlsl_block_cleanup(&c->body);
list_remove(&c->entry);
vkd3d_free(c);
}
void hlsl_cleanup_ir_switch_cases(struct list *cases)
{
struct hlsl_ir_switch_case *c, *next;
LIST_FOR_EACH_ENTRY_SAFE(c, next, cases, struct hlsl_ir_switch_case, entry)
{
hlsl_free_ir_switch_case(c);
}
}
static struct hlsl_ir_node *clone_switch(struct hlsl_ctx *ctx,
struct clone_instr_map *map, struct hlsl_ir_switch *s)
{
struct hlsl_ir_switch_case *c, *d;
struct hlsl_ir_node *ret;
struct hlsl_block body;
struct list cases;
list_init(&cases);
LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry)
{
if (!(clone_block(ctx, &body, &c->body, map)))
{
hlsl_cleanup_ir_switch_cases(&cases);
return NULL;
}
d = hlsl_new_switch_case(ctx, c->value, c->is_default, &body, &c->loc);
hlsl_block_cleanup(&body);
if (!d)
{
hlsl_cleanup_ir_switch_cases(&cases);
return NULL;
}
list_add_tail(&cases, &d->entry);
}
ret = hlsl_new_switch(ctx, map_instr(map, s->selector.node), &cases, &s->node.loc);
hlsl_cleanup_ir_switch_cases(&cases);
return ret;
}
static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx,
struct clone_instr_map *map, const struct hlsl_ir_node *instr)
{
......@@ -1843,6 +1926,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx,
case HLSL_IR_STORE:
return clone_store(ctx, map, hlsl_ir_store(instr));
case HLSL_IR_SWITCH:
return clone_switch(ctx, map, hlsl_ir_switch(instr));
case HLSL_IR_SWIZZLE:
return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr));
}
......@@ -2261,6 +2347,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type)
[HLSL_IR_RESOURCE_LOAD ] = "HLSL_IR_RESOURCE_LOAD",
[HLSL_IR_RESOURCE_STORE] = "HLSL_IR_RESOURCE_STORE",
[HLSL_IR_STORE ] = "HLSL_IR_STORE",
[HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH",
[HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE",
};
......@@ -2327,21 +2414,34 @@ static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_der
if (deref->var)
{
vkd3d_string_buffer_printf(buffer, "%s", deref->var->name);
if (deref->path_len)
if (!hlsl_deref_is_lowered(deref))
{
vkd3d_string_buffer_printf(buffer, "[");
for (i = 0; i < deref->path_len; ++i)
if (deref->path_len)
{
vkd3d_string_buffer_printf(buffer, "[");
dump_src(buffer, &deref->path[i]);
for (i = 0; i < deref->path_len; ++i)
{
vkd3d_string_buffer_printf(buffer, "[");
dump_src(buffer, &deref->path[i]);
vkd3d_string_buffer_printf(buffer, "]");
}
vkd3d_string_buffer_printf(buffer, "]");
}
vkd3d_string_buffer_printf(buffer, "]");
}
else if (deref->offset.node)
else
{
bool show_rel, show_const;
show_rel = deref->rel_offset.node;
show_const = deref->const_offset != 0 || !show_rel;
vkd3d_string_buffer_printf(buffer, "[");
dump_src(buffer, &deref->offset);
if (show_rel)
dump_src(buffer, &deref->rel_offset);
if (show_rel && show_const)
vkd3d_string_buffer_printf(buffer, " + ");
if (show_const)
vkd3d_string_buffer_printf(buffer, "%uc", deref->const_offset);
vkd3d_string_buffer_printf(buffer, "]");
}
}
......@@ -2685,6 +2785,32 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_
vkd3d_string_buffer_printf(buffer, "]");
}
static void dump_ir_switch(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_switch *s)
{
struct hlsl_ir_switch_case *c;
vkd3d_string_buffer_printf(buffer, "switch (");
dump_src(buffer, &s->selector);
vkd3d_string_buffer_printf(buffer, ") {\n");
LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry)
{
if (c->is_default)
{
vkd3d_string_buffer_printf(buffer, " %10s default: {\n", "");
}
else
{
vkd3d_string_buffer_printf(buffer, " %10s case %u : {\n", "", c->value);
}
dump_block(ctx, buffer, &c->body);
vkd3d_string_buffer_printf(buffer, " %10s }\n", "");
}
vkd3d_string_buffer_printf(buffer, " %10s }", "");
}
static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_node *instr)
{
if (instr->index)
......@@ -2740,6 +2866,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer,
dump_ir_store(buffer, hlsl_ir_store(instr));
break;
case HLSL_IR_SWITCH:
dump_ir_switch(ctx, buffer, hlsl_ir_switch(instr));
break;
case HLSL_IR_SWIZZLE:
dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr));
break;
......@@ -2881,7 +3011,7 @@ static void free_ir_resource_load(struct hlsl_ir_resource_load *load)
static void free_ir_resource_store(struct hlsl_ir_resource_store *store)
{
hlsl_src_remove(&store->resource.offset);
hlsl_src_remove(&store->resource.rel_offset);
hlsl_src_remove(&store->coords);
hlsl_src_remove(&store->value);
vkd3d_free(store);
......@@ -2900,6 +3030,14 @@ static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle)
vkd3d_free(swizzle);
}
static void free_ir_switch(struct hlsl_ir_switch *s)
{
hlsl_src_remove(&s->selector);
hlsl_cleanup_ir_switch_cases(&s->cases);
vkd3d_free(s);
}
static void free_ir_index(struct hlsl_ir_index *index)
{
hlsl_src_remove(&index->val);
......@@ -2960,6 +3098,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node)
case HLSL_IR_SWIZZLE:
free_ir_swizzle(hlsl_ir_swizzle(node));
break;
case HLSL_IR_SWITCH:
free_ir_switch(hlsl_ir_switch(node));
break;
}
}
......@@ -3118,7 +3260,7 @@ unsigned int hlsl_combine_swizzles(unsigned int first, unsigned int second, unsi
return ret;
}
static const struct hlsl_profile_info *get_target_info(const char *target)
const struct hlsl_profile_info *hlsl_get_target_info(const char *target)
{
unsigned int i;
......@@ -3485,14 +3627,12 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
}
entry_point = hlsl_source_info->entry_point ? hlsl_source_info->entry_point : "main";
if (!(profile = get_target_info(hlsl_source_info->profile)))
if (!(profile = hlsl_get_target_info(hlsl_source_info->profile)))
{
FIXME("Unknown compilation target %s.\n", debugstr_a(hlsl_source_info->profile));
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
vkd3d_shader_dump_shader(compile_info->source_type, profile->type, &compile_info->source);
if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_BYTECODE && profile->major_version > 3)
{
vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
......
......@@ -281,6 +281,7 @@ enum hlsl_ir_node_type
HLSL_IR_RESOURCE_STORE,
HLSL_IR_STORE,
HLSL_IR_SWIZZLE,
HLSL_IR_SWITCH,
};
/* Common data for every type of IR instruction node. */
......@@ -424,6 +425,9 @@ struct hlsl_ir_var
* It may be less than the allocation size, e.g. for texture arrays. */
unsigned int bind_count[HLSL_REGSET_LAST_OBJECT + 1];
/* Whether the shader performs dereferences with non-constant offsets in the variable. */
bool indexable;
uint32_t is_input_semantic : 1;
uint32_t is_output_semantic : 1;
uint32_t is_uniform : 1;
......@@ -499,6 +503,22 @@ struct hlsl_ir_loop
unsigned int next_index; /* liveness index of the end of the loop */
};
struct hlsl_ir_switch_case
{
unsigned int value;
bool is_default;
struct hlsl_block body;
struct list entry;
struct vkd3d_shader_location loc;
};
struct hlsl_ir_switch
{
struct hlsl_ir_node node;
struct hlsl_src selector;
struct list cases;
};
enum hlsl_ir_expr_op
{
HLSL_OP0_VOID,
......@@ -621,17 +641,25 @@ struct hlsl_deref
unsigned int path_len;
struct hlsl_src *path;
/* Single instruction node of data type uint used to represent the register offset (in register
* components, within the pertaining regset), from the start of the variable, of the part
* referenced.
* The path is lowered to this single offset -- whose value may vary between SM1 and SM4 --
* before writing the bytecode.
/* Before writing the bytecode, deref paths are lowered into an offset (within the pertaining
* regset) from the start of the variable, to the part of the variable that is referenced.
* This offset is stored using two fields, one for a variable part and other for a constant
* part, which are added together:
* - rel_offset: An offset given by an instruction node, in whole registers.
* - const_offset: A constant number of register components.
* Since the type information cannot longer be retrieved from the offset alone, the type is
* stored in the data_type field. */
struct hlsl_src offset;
* stored in the data_type field, which remains NULL if the deref hasn't been lowered yet. */
struct hlsl_src rel_offset;
unsigned int const_offset;
struct hlsl_type *data_type;
};
/* Whether the path has been lowered to an offset or not. */
static inline bool hlsl_deref_is_lowered(const struct hlsl_deref *deref)
{
return !!deref->data_type;
}
struct hlsl_ir_load
{
struct hlsl_ir_node node;
......@@ -710,6 +738,8 @@ struct hlsl_scope
struct hlsl_scope *upper;
/* The scope was created for the loop statement. */
bool loop;
/* The scope was created for the switch statement. */
bool _switch;
};
struct hlsl_profile_info
......@@ -947,6 +977,12 @@ static inline struct hlsl_ir_index *hlsl_ir_index(const struct hlsl_ir_node *nod
return CONTAINING_RECORD(node, struct hlsl_ir_index, node);
}
static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *node)
{
assert(node->type == HLSL_IR_SWITCH);
return CONTAINING_RECORD(node, struct hlsl_ir_switch, node);
}
static inline void hlsl_block_init(struct hlsl_block *block)
{
list_init(&block->instrs);
......@@ -1120,6 +1156,9 @@ bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struc
void hlsl_cleanup_deref(struct hlsl_deref *deref);
void hlsl_cleanup_semantic(struct hlsl_semantic *semantic);
void hlsl_cleanup_ir_switch_cases(struct list *cases);
void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c);
void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new);
void hlsl_free_attribute(struct hlsl_attribute *attr);
......@@ -1130,6 +1169,7 @@ void hlsl_free_var(struct hlsl_ir_var *decl);
struct hlsl_ir_function *hlsl_get_function(struct hlsl_ctx *ctx, const char *name);
struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const char *name);
const struct hlsl_profile_info *hlsl_get_target_info(const char *target);
struct hlsl_type *hlsl_get_type(struct hlsl_scope *scope, const char *name, bool recursive, bool case_insensitive);
struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name);
......@@ -1213,6 +1253,10 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr
struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type,
const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, unsigned int modifiers,
const struct hlsl_reg_reservation *reg_reservation);
struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value, bool is_default,
struct hlsl_block *body, const struct vkd3d_shader_location *loc);
struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector,
struct list *cases, const struct vkd3d_shader_location *loc);
void hlsl_error(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc,
enum vkd3d_shader_error error, const char *fmt, ...) VKD3D_PRINTF_FUNC(4, 5);
......
......@@ -46,14 +46,13 @@ static void update_location(struct hlsl_ctx *ctx, YYLTYPE *loc);
%x pp pp_line pp_pragma pp_ignore
RESERVED1 auto|case|catch|char|class|const_cast|default|delete|dynamic_cast|enum
RESERVED1 auto|catch|char|class|const_cast|delete|dynamic_cast|enum
RESERVED2 explicit|friend|goto|long|mutable|new|operator|private|protected|public
RESERVED3 reinterpret_cast|short|signed|sizeof|static_cast|template|this|throw|try
RESERVED4 typename|union|unsigned|using|virtual
WS [ \t]
NEWLINE (\n)|(\r\n)
DOUBLESLASHCOMMENT "//"[^\n]*
STRING \"[^\"]*\"
IDENTIFIER [A-Za-z_][A-Za-z0-9_]*
......@@ -73,13 +72,16 @@ ANY (.)
BlendState {return KW_BLENDSTATE; }
break {return KW_BREAK; }
Buffer {return KW_BUFFER; }
case {return KW_CASE; }
cbuffer {return KW_CBUFFER; }
centroid {return KW_CENTROID; }
column_major {return KW_COLUMN_MAJOR; }
compile {return KW_COMPILE; }
const {return KW_CONST; }
continue {return KW_CONTINUE; }
DepthStencilState {return KW_DEPTHSTENCILSTATE; }
DepthStencilView {return KW_DEPTHSTENCILVIEW; }
default {return KW_DEFAULT; }
discard {return KW_DISCARD; }
do {return KW_DO; }
double {return KW_DOUBLE; }
......@@ -103,9 +105,10 @@ pass {return KW_PASS; }
PixelShader {return KW_PIXELSHADER; }
precise {return KW_PRECISE; }
RasterizerState {return KW_RASTERIZERSTATE; }
register {return KW_REGISTER; }
RenderTargetView {return KW_RENDERTARGETVIEW; }
return {return KW_RETURN; }
register {return KW_REGISTER; }
row_major {return KW_ROW_MAJOR; }
RWBuffer {return KW_RWBUFFER; }
RWStructuredBuffer {return KW_RWSTRUCTUREDBUFFER; }
RWTexture1D {return KW_RWTEXTURE1D; }
......@@ -117,10 +120,10 @@ sampler {return KW_SAMPLER; }
sampler1D {return KW_SAMPLER1D; }
sampler2D {return KW_SAMPLER2D; }
sampler3D {return KW_SAMPLER3D; }
samplerCUBE {return KW_SAMPLERCUBE; }
sampler_state {return KW_SAMPLER_STATE; }
SamplerComparisonState {return KW_SAMPLERCOMPARISONSTATE;}
samplerCUBE {return KW_SAMPLERCUBE; }
SamplerState {return KW_SAMPLER; }
sampler_state {return KW_SAMPLER_STATE; }
shared {return KW_SHARED; }
stateblock {return KW_STATEBLOCK; }
stateblock_state {return KW_STATEBLOCK_STATE; }
......@@ -129,21 +132,22 @@ string {return KW_STRING; }
struct {return KW_STRUCT; }
switch {return KW_SWITCH; }
tbuffer {return KW_TBUFFER; }
technique {return KW_TECHNIQUE; }
(?i:technique) {return KW_TECHNIQUE; }
technique10 {return KW_TECHNIQUE10; }
technique11 {return KW_TECHNIQUE11; }
texture {return KW_TEXTURE; }
texture1D {return KW_TEXTURE1D; }
Texture1D {return KW_TEXTURE1D; }
texture1D {return KW_TEXTURE1D; }
Texture1DArray {return KW_TEXTURE1DARRAY; }
texture2D {return KW_TEXTURE2D; }
Texture2D {return KW_TEXTURE2D; }
texture2D {return KW_TEXTURE2D; }
Texture2DArray {return KW_TEXTURE2DARRAY; }
Texture2DMS {return KW_TEXTURE2DMS; }
Texture2DMSArray {return KW_TEXTURE2DMSARRAY; }
texture3D {return KW_TEXTURE3D; }
Texture3D {return KW_TEXTURE3D; }
textureCUBE {return KW_TEXTURECUBE; }
texture3D {return KW_TEXTURE3D; }
TextureCube {return KW_TEXTURECUBE; }
textureCUBE {return KW_TEXTURECUBE; }
TextureCubeArray {return KW_TEXTURECUBEARRAY; }
true {return KW_TRUE; }
typedef {return KW_TYPEDEF; }
......@@ -163,7 +167,6 @@ while {return KW_WHILE; }
\<\<= {return OP_LEFTSHIFTASSIGN; }
\>\> {return OP_RIGHTSHIFT; }
\>\>= {return OP_RIGHTSHIFTASSIGN; }
\.\.\. {return OP_ELLIPSIS; }
\<= {return OP_LE; }
\>= {return OP_GE; }
!= {return OP_NE; }
......@@ -175,13 +178,6 @@ while {return KW_WHILE; }
&= {return OP_ANDASSIGN; }
\|= {return OP_ORASSIGN; }
^= {return OP_XORASSIGN; }
## {return OP_UNKNOWN1; }
#@ {return OP_UNKNOWN2; }
:: {return OP_UNKNOWN3; }
\-\> {return OP_UNKNOWN4; }
column_major {return KW_COLUMN_MAJOR; }
row_major {return KW_ROW_MAJOR; }
{IDENTIFIER} {
struct hlsl_ctx *ctx = yyget_extra(yyscanner);
......@@ -220,8 +216,6 @@ row_major {return KW_ROW_MAJOR; }
return C_INTEGER;
}
{DOUBLESLASHCOMMENT} {}
{WS}+ {}
{NEWLINE} {
struct hlsl_ctx *ctx = yyget_extra(yyscanner);
......
......@@ -162,6 +162,12 @@ static void destroy_block(struct hlsl_block *block)
vkd3d_free(block);
}
static void destroy_switch_cases(struct list *cases)
{
hlsl_cleanup_ir_switch_cases(cases);
vkd3d_free(cases);
}
static bool hlsl_types_are_componentwise_compatible(struct hlsl_ctx *ctx, struct hlsl_type *src,
struct hlsl_type *dst)
{
......@@ -508,6 +514,28 @@ static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block
}
}
static void check_loop_attributes(struct hlsl_ctx *ctx, const struct parse_attribute_list *attributes,
const struct vkd3d_shader_location *loc)
{
bool has_unroll = false, has_loop = false, has_fastopt = false;
unsigned int i;
for (i = 0; i < attributes->count; ++i)
{
const char *name = attributes->attrs[i]->name;
has_loop |= !strcmp(name, "loop");
has_unroll |= !strcmp(name, "unroll");
has_fastopt |= !strcmp(name, "fastopt");
}
if (has_unroll && has_loop)
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Unroll attribute can't be used with 'loop' attribute.");
if (has_unroll && has_fastopt)
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Unroll attribute can't be used with 'fastopt' attribute.");
}
static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type,
const struct parse_attribute_list *attributes, struct hlsl_block *init, struct hlsl_block *cond,
struct hlsl_block *iter, struct hlsl_block *body, const struct vkd3d_shader_location *loc)
......@@ -518,6 +546,8 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type,
if (attribute_list_has_duplicates(attributes))
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute.");
check_loop_attributes(ctx, attributes, loc);
/* Ignore unroll(0) attribute, and any invalid attribute. */
for (i = 0; i < attributes->count; ++i)
{
......@@ -533,8 +563,11 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type,
hlsl_warning(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_IMPLEMENTED, "Loop unrolling is not implemented.");
}
}
else if (!strcmp(attr->name, "loop")
|| !strcmp(attr->name, "fastopt")
else if (!strcmp(attr->name, "loop"))
{
/* TODO: this attribute will be used to disable unrolling, once it's implememented. */
}
else if (!strcmp(attr->name, "fastopt")
|| !strcmp(attr->name, "allow_uav_condition"))
{
hlsl_fixme(ctx, loc, "Unhandled attribute '%s'.", attr->name);
......@@ -1180,6 +1213,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str
case HLSL_IR_RESOURCE_LOAD:
case HLSL_IR_RESOURCE_STORE:
case HLSL_IR_STORE:
case HLSL_IR_SWITCH:
hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"Expected literal expression.");
}
......@@ -4633,12 +4667,64 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type
}
}
static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
static bool check_continue(struct hlsl_ctx *ctx, const struct hlsl_scope *scope, const struct vkd3d_shader_location *loc)
{
if (scope->_switch)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'continue' statement is not allowed in 'switch' statements.");
return false;
}
if (scope->loop)
return scope;
return true;
if (scope->upper)
return check_continue(ctx, scope->upper, loc);
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'continue' statement is only allowed in loops.");
return false;
}
static bool is_break_allowed(const struct hlsl_scope *scope)
{
if (scope->loop || scope->_switch)
return true;
return scope->upper ? is_break_allowed(scope->upper) : false;
}
static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hlsl_ir_switch_case *check, struct list *cases)
{
struct hlsl_ir_switch_case *c;
bool found_duplicate = false;
return scope->upper ? get_loop_scope(scope->upper) : NULL;
LIST_FOR_EACH_ENTRY(c, cases, struct hlsl_ir_switch_case, entry)
{
if (check->is_default)
{
if ((found_duplicate = c->is_default))
{
hlsl_error(ctx, &check->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_SWITCH_CASE,
"Found multiple 'default' statements.");
hlsl_note(ctx, &c->loc, VKD3D_SHADER_LOG_ERROR, "The 'default' statement was previously found here.");
}
}
else
{
if (c->is_default) continue;
if ((found_duplicate = (c->value == check->value)))
{
hlsl_error(ctx, &check->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_SWITCH_CASE,
"Found duplicate 'case' statement.");
hlsl_note(ctx, &c->loc, VKD3D_SHADER_LOG_ERROR, "The same 'case %d' statement was previously found here.",
c->value);
}
}
if (found_duplicate)
break;
}
}
}
......@@ -4679,17 +4765,20 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
enum hlsl_sampler_dim sampler_dim;
struct hlsl_attribute *attr;
struct parse_attribute_list attr_list;
struct hlsl_ir_switch_case *switch_case;
}
%token KW_BLENDSTATE
%token KW_BREAK
%token KW_BUFFER
%token KW_CASE
%token KW_CBUFFER
%token KW_CENTROID
%token KW_COLUMN_MAJOR
%token KW_COMPILE
%token KW_CONST
%token KW_CONTINUE
%token KW_DEFAULT
%token KW_DEPTHSTENCILSTATE
%token KW_DEPTHSTENCILVIEW
%token KW_DISCARD
......@@ -4743,6 +4832,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%token KW_TBUFFER
%token KW_TECHNIQUE
%token KW_TECHNIQUE10
%token KW_TECHNIQUE11
%token KW_TEXTURE
%token KW_TEXTURE1D
%token KW_TEXTURE1DARRAY
......@@ -4771,7 +4861,6 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%token OP_LEFTSHIFTASSIGN
%token OP_RIGHTSHIFT
%token OP_RIGHTSHIFTASSIGN
%token OP_ELLIPSIS
%token OP_LE
%token OP_GE
%token OP_NE
......@@ -4783,10 +4872,6 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%token OP_ANDASSIGN
%token OP_ORASSIGN
%token OP_XORASSIGN
%token OP_UNKNOWN1
%token OP_UNKNOWN2
%token OP_UNKNOWN3
%token OP_UNKNOWN4
%token <floatval> C_FLOAT
......@@ -4796,6 +4881,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%type <list> type_specs
%type <list> variables_def
%type <list> variables_def_typed
%type <list> switch_cases
%token <name> VAR_IDENTIFIER
%token <name> NEW_IDENTIFIER
......@@ -4838,6 +4924,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%type <block> statement
%type <block> statement_list
%type <block> struct_declaration_without_vars
%type <block> switch_statement
%type <block> unary_expr
%type <boolval> boolean
......@@ -4863,6 +4950,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%type <name> any_identifier
%type <name> var_identifier
%type <name> technique_name
%type <parameter> parameter
......@@ -4876,6 +4964,8 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope)
%type <semantic> semantic
%type <switch_case> switch_case
%type <type> field_type
%type <type> named_struct_spec
%type <type> unnamed_struct_spec
......@@ -4902,8 +4992,50 @@ hlsl_prog:
destroy_block($2);
}
| hlsl_prog preproc_directive
| hlsl_prog technique
| hlsl_prog ';'
technique_name:
%empty
{
$$ = NULL;
}
| any_identifier
pass_list:
%empty
technique9:
KW_TECHNIQUE technique_name '{' pass_list '}'
{
hlsl_fixme(ctx, &@$, "Unsupported \'technique\' declaration.");
}
technique10:
KW_TECHNIQUE10 technique_name '{' pass_list '}'
{
if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2)
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'technique10' keyword is invalid for this profile.");
hlsl_fixme(ctx, &@$, "Unsupported \'technique10\' declaration.");
}
technique11:
KW_TECHNIQUE11 technique_name '{' pass_list '}'
{
if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2)
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'technique11' keyword is invalid for this profile.");
hlsl_fixme(ctx, &@$, "Unsupported \'technique11\' declaration.");
}
technique:
technique9
| technique10
| technique11
buffer_declaration:
buffer_type any_identifier colon_attribute
{
......@@ -5357,6 +5489,13 @@ loop_scope_start:
ctx->cur_scope->loop = true;
}
switch_scope_start:
%empty
{
hlsl_push_scope(ctx);
ctx->cur_scope->_switch = true;
}
var_identifier:
VAR_IDENTIFIER
| NEW_IDENTIFIER
......@@ -6185,18 +6324,17 @@ statement:
| jump_statement
| selection_statement
| loop_statement
| switch_statement
jump_statement:
KW_BREAK ';'
{
struct hlsl_ir_node *jump;
/* TODO: allow 'break' in the 'switch' statements. */
if (!get_loop_scope(ctx->cur_scope))
if (!is_break_allowed(ctx->cur_scope))
{
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'break' statement must be used inside of a loop.");
"The 'break' statement must be used inside of a loop or a switch.");
}
if (!($$ = make_empty_block(ctx)))
......@@ -6208,13 +6346,8 @@ jump_statement:
| KW_CONTINUE ';'
{
struct hlsl_ir_node *jump;
struct hlsl_scope *scope;
if (!(scope = get_loop_scope(ctx->cur_scope)))
{
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'continue' statement must be used inside of a loop.");
}
check_continue(ctx, ctx->cur_scope, &@1);
if (!($$ = make_empty_block(ctx)))
YYABORT;
......@@ -6333,6 +6466,106 @@ loop_statement:
hlsl_pop_scope(ctx);
}
switch_statement:
attribute_list_optional switch_scope_start KW_SWITCH '(' expr ')' '{' switch_cases '}'
{
struct hlsl_ir_node *selector = node_from_block($5);
struct hlsl_ir_node *s;
if (!(selector = add_implicit_conversion(ctx, $5, selector, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &@5)))
{
destroy_switch_cases($8);
destroy_block($5);
YYABORT;
}
s = hlsl_new_switch(ctx, selector, $8, &@3);
destroy_switch_cases($8);
if (!s)
{
destroy_block($5);
YYABORT;
}
$$ = $5;
hlsl_block_add_instr($$, s);
hlsl_pop_scope(ctx);
}
switch_case:
KW_CASE expr ':' statement_list
{
struct hlsl_ir_switch_case *c;
unsigned int value;
value = evaluate_static_expression_as_uint(ctx, $2, &@2);
c = hlsl_new_switch_case(ctx, value, false, $4, &@2);
destroy_block($2);
destroy_block($4);
if (!c)
YYABORT;
$$ = c;
}
| KW_CASE expr ':'
{
struct hlsl_ir_switch_case *c;
unsigned int value;
value = evaluate_static_expression_as_uint(ctx, $2, &@2);
c = hlsl_new_switch_case(ctx, value, false, NULL, &@2);
destroy_block($2);
if (!c)
YYABORT;
$$ = c;
}
| KW_DEFAULT ':' statement_list
{
struct hlsl_ir_switch_case *c;
c = hlsl_new_switch_case(ctx, 0, true, $3, &@1);
destroy_block($3);
if (!c)
YYABORT;
$$ = c;
}
| KW_DEFAULT ':'
{
struct hlsl_ir_switch_case *c;
if (!(c = hlsl_new_switch_case(ctx, 0, true, NULL, &@1)))
YYABORT;
$$ = c;
}
switch_cases:
switch_case
{
struct hlsl_ir_switch_case *c = LIST_ENTRY($1, struct hlsl_ir_switch_case, entry);
if (!($$ = make_empty_list(ctx)))
{
hlsl_free_ir_switch_case(c);
YYABORT;
}
list_add_head($$, &$1->entry);
}
| switch_cases switch_case
{
$$ = $1;
check_duplicated_switch_cases(ctx, $2, $$);
list_add_tail($$, &$2->entry);
}
expr_optional:
%empty
{
......