wine-staging/patches/vkd3d-latest/0011-Updated-vkd3d-to-68b898fcb6b4ab2a9660f35edf3554465ab.patch
2024-01-16 11:01:10 +11:00

957 lines
35 KiB
Diff

From 6763e88d1a79484e304096631e47726784ebcb6a Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Tue, 16 Jan 2024 10:48:52 +1100
Subject: [PATCH] Updated vkd3d to 68b898fcb6b4ab2a9660f35edf3554465ab0efbe.
---
libs/vkd3d/include/private/vkd3d_common.h | 4 -
libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 11 +-
libs/vkd3d/libs/vkd3d-shader/dxil.c | 2 +-
libs/vkd3d/libs/vkd3d-shader/fx.c | 235 +++++++++++++++++-
libs/vkd3d/libs/vkd3d-shader/hlsl.y | 40 ++-
libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 39 +++
libs/vkd3d/libs/vkd3d-shader/ir.c | 171 ++++++++++++-
libs/vkd3d/libs/vkd3d-shader/spirv.c | 5 +-
libs/vkd3d/libs/vkd3d-shader/tpf.c | 26 +-
.../libs/vkd3d-shader/vkd3d_shader_private.h | 3 +-
10 files changed, 482 insertions(+), 54 deletions(-)
diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h
index 54fe1ca5017..4c97fa06e32 100644
--- a/libs/vkd3d/include/private/vkd3d_common.h
+++ b/libs/vkd3d/include/private/vkd3d_common.h
@@ -277,10 +277,6 @@ static inline LONG64 InterlockedIncrement64(LONG64 volatile *x)
{
return __sync_add_and_fetch(x, 1);
}
-static inline LONG InterlockedAdd(LONG volatile *x, LONG val)
-{
- return __sync_add_and_fetch(x, val);
-}
# else
# error "InterlockedIncrement() not implemented for this platform"
# endif /* HAVE_SYNC_ADD_AND_FETCH */
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
index 8fec1e6371a..aa0dd8f4b0d 100644
--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
@@ -1360,18 +1360,21 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi
sm1->p.shader_desc.flat_constant_count[i].external = get_external_constant_count(sm1, i);
if (!sm1->p.failed)
- vsir_validate(&sm1->p);
+ ret = vsir_validate(&sm1->p);
- if (sm1->p.failed)
+ if (sm1->p.failed && ret >= 0)
+ ret = VKD3D_ERROR_INVALID_SHADER;
+
+ if (ret < 0)
{
WARN("Failed to parse shader.\n");
shader_sm1_destroy(&sm1->p);
- return VKD3D_ERROR_INVALID_SHADER;
+ return ret;
}
*parser = &sm1->p;
- return VKD3D_OK;
+ return ret;
}
bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c
index 869a709d63f..b39ec204bff 100644
--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c
+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c
@@ -6282,7 +6282,7 @@ int vkd3d_shader_sm6_parser_create(const struct vkd3d_shader_compile_info *compi
vkd3d_free(byte_code);
if (!sm6->p.failed && ret >= 0)
- vsir_validate(&sm6->p);
+ ret = vsir_validate(&sm6->p);
if (sm6->p.failed && ret >= 0)
ret = VKD3D_ERROR_INVALID_SHADER;
diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c
index 6c4c1203d48..17b9627b6bd 100644
--- a/libs/vkd3d/libs/vkd3d-shader/fx.c
+++ b/libs/vkd3d/libs/vkd3d-shader/fx.c
@@ -20,32 +20,146 @@
#include "hlsl.h"
+struct string_entry
+{
+ struct rb_entry entry;
+ /* String points to original data, should not be freed. */
+ const char *string;
+ uint32_t offset;
+};
+
+static int string_storage_compare(const void *key, const struct rb_entry *entry)
+{
+ struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+ const char *string = key;
+
+ return strcmp(string, string_entry->string);
+}
+
+static void string_storage_destroy(struct rb_entry *entry, void *context)
+{
+ struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+
+ vkd3d_free(string_entry);
+}
+
struct fx_write_context
{
+ struct hlsl_ctx *ctx;
+
struct vkd3d_bytecode_buffer unstructured;
struct vkd3d_bytecode_buffer structured;
+ struct rb_tree strings;
+
+ unsigned int min_technique_version;
+ unsigned int max_technique_version;
+
uint32_t technique_count;
+ uint32_t group_count;
int status;
};
+static void fx_write_context_init(struct hlsl_ctx *ctx, struct fx_write_context *fx)
+{
+ unsigned int version = ctx->profile->major_version;
+
+ memset(fx, 0, sizeof(*fx));
+
+ fx->ctx = ctx;
+ if (version == 2)
+ {
+ fx->min_technique_version = 9;
+ fx->max_technique_version = 9;
+ }
+ else if (version == 4)
+ {
+ fx->min_technique_version = 10;
+ fx->max_technique_version = 10;
+ }
+ else if (version == 5)
+ {
+ fx->min_technique_version = 10;
+ fx->max_technique_version = 11;
+ }
+
+ rb_init(&fx->strings, string_storage_compare);
+}
+
+static int fx_write_context_cleanup(struct fx_write_context *fx)
+{
+ int status = fx->status;
+ rb_destroy(&fx->strings, string_storage_destroy, NULL);
+
+ return status;
+}
+
+static bool technique_matches_version(const struct hlsl_ir_var *var, const struct fx_write_context *fx)
+{
+ const struct hlsl_type *type = var->data_type;
+
+ if (type->base_type != HLSL_TYPE_TECHNIQUE)
+ return false;
+
+ return type->e.version >= fx->min_technique_version && type->e.version <= fx->max_technique_version;
+}
+
static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *string)
{
+ struct string_entry *string_entry;
+ struct rb_entry *entry;
+
/* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */
- return string ? put_string(&fx->unstructured, string) : 0;
+ if (!string)
+ return 0;
+
+ if ((entry = rb_get(&fx->strings, string)))
+ {
+ string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+ return string_entry->offset;
+ }
+
+ if (!(string_entry = hlsl_alloc(fx->ctx, sizeof(*string_entry))))
+ return 0;
+
+ string_entry->offset = put_string(&fx->unstructured, string);
+ string_entry->string = string;
+
+ rb_put(&fx->strings, string, &string_entry->entry);
+
+ return string_entry->offset;
}
-static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
+static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
{
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
uint32_t name_offset;
name_offset = fx_put_raw_string(fx, var->name);
put_u32(buffer, name_offset);
- put_u32(buffer, 0); /* Pass count. */
put_u32(buffer, 0); /* Annotation count. */
+ put_u32(buffer, 0); /* Assignment count. */
+}
+
+static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset, count = 0;
+ struct hlsl_ir_var *pass;
+ uint32_t count_offset;
- /* TODO: passes */
+ name_offset = fx_put_raw_string(fx, var->name);
+ put_u32(buffer, name_offset);
+ count_offset = put_u32(buffer, 0);
+ put_u32(buffer, 0); /* Annotation count. */
+
+ LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ write_pass(pass, fx);
+ ++count;
+ }
+
+ set_u32(buffer, count_offset, count);
}
static void set_status(struct fx_write_context *fx, int status)
@@ -75,13 +189,55 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *
set_status(fx, fx->structured.status);
}
+static void write_group(struct hlsl_scope *scope, const char *name, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset = fx_put_raw_string(fx, name);
+ uint32_t count_offset, count;
+
+ put_u32(buffer, name_offset);
+ count_offset = put_u32(buffer, 0); /* Technique count */
+ put_u32(buffer, 0); /* Annotation count */
+
+ count = fx->technique_count;
+ write_techniques(scope, fx);
+ set_u32(buffer, count_offset, fx->technique_count - count);
+
+ ++fx->group_count;
+}
+
+static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx)
+{
+ bool needs_default_group = false;
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (technique_matches_version(var, fx))
+ {
+ needs_default_group = true;
+ break;
+ }
+ }
+
+ if (needs_default_group)
+ write_group(scope, NULL, fx);
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ const struct hlsl_type *type = var->data_type;
+
+ if (type->base_type == HLSL_TYPE_EFFECT_GROUP)
+ write_group(var->scope, var->name, fx);
+ }
+}
+
static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
{
struct vkd3d_bytecode_buffer buffer = { 0 };
struct fx_write_context fx;
uint32_t size_offset, size;
- memset(&fx, 0, sizeof(fx));
+ fx_write_context_init(ctx, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
@@ -132,7 +288,71 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
if (fx.status < 0)
ctx->result = fx.status;
- return fx.status;
+ return fx_write_context_cleanup(&fx);
+}
+
+static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
+{
+ struct vkd3d_bytecode_buffer buffer = { 0 };
+ struct fx_write_context fx;
+ uint32_t size_offset, size;
+
+ fx_write_context_init(ctx, &fx);
+
+ put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
+
+ /* TODO: buffers */
+ /* TODO: objects */
+ /* TODO: interface variables */
+
+ write_groups(ctx->globals, &fx);
+
+ put_u32(&buffer, 0xfeff2001); /* Version. */
+ put_u32(&buffer, 0); /* Buffer count. */
+ put_u32(&buffer, 0); /* Variable count. */
+ put_u32(&buffer, 0); /* Object count. */
+ put_u32(&buffer, 0); /* Pool buffer count. */
+ put_u32(&buffer, 0); /* Pool variable count. */
+ put_u32(&buffer, 0); /* Pool object count. */
+ put_u32(&buffer, fx.technique_count);
+ size_offset = put_u32(&buffer, 0); /* Unstructured size. */
+ put_u32(&buffer, 0); /* String count. */
+ put_u32(&buffer, 0); /* Texture object count. */
+ put_u32(&buffer, 0); /* Depth stencil state count. */
+ put_u32(&buffer, 0); /* Blend state count. */
+ put_u32(&buffer, 0); /* Rasterizer state count. */
+ put_u32(&buffer, 0); /* Sampler state count. */
+ put_u32(&buffer, 0); /* Rendertarget view count. */
+ put_u32(&buffer, 0); /* Depth stencil view count. */
+ put_u32(&buffer, 0); /* Shader count. */
+ put_u32(&buffer, 0); /* Inline shader count. */
+ put_u32(&buffer, fx.group_count); /* Group count. */
+ put_u32(&buffer, 0); /* UAV count. */
+ put_u32(&buffer, 0); /* Interface variables count. */
+ put_u32(&buffer, 0); /* Interface variable element count. */
+ put_u32(&buffer, 0); /* Class instance elements count. */
+
+ size = align(fx.unstructured.size, 4);
+ set_u32(&buffer, size_offset, size);
+
+ bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
+ bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
+
+ vkd3d_free(fx.unstructured.data);
+ vkd3d_free(fx.structured.data);
+
+ set_status(&fx, buffer.status);
+
+ if (!fx.status)
+ {
+ out->code = buffer.data;
+ out->size = buffer.size;
+ }
+
+ if (fx.status < 0)
+ ctx->result = fx.status;
+
+ return fx_write_context_cleanup(&fx);
}
int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
@@ -148,8 +368,7 @@ int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
}
else if (ctx->profile->major_version == 5)
{
- hlsl_fixme(ctx, &ctx->location, "Writing fx_5_0 binaries is not implemented.");
- return VKD3D_ERROR_NOT_IMPLEMENTED;
+ return hlsl_fx_5_write(ctx, out);
}
else
{
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
index 7424e63a478..b11cbde26f1 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
@@ -1096,8 +1096,8 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters
return true;
}
-static bool add_technique(struct hlsl_ctx *ctx, const char *name, const char *typename,
- const struct vkd3d_shader_location *loc)
+static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope,
+ const char *typename, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_var *var;
struct hlsl_type *type;
@@ -1105,6 +1105,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, const char *ty
type = hlsl_get_type(ctx->globals, typename, false, false);
if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL)))
return false;
+ var->scope = scope;
if (!hlsl_add_var(ctx, var, false))
{
@@ -5102,7 +5103,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
%type <name> any_identifier
%type <name> var_identifier
-%type <name> technique_name
+%type <name> name_opt
%type <parameter> parameter
@@ -5148,42 +5149,59 @@ hlsl_prog:
| hlsl_prog effect_group
| hlsl_prog ';'
-technique_name:
+name_opt:
%empty
{
$$ = NULL;
}
| any_identifier
+pass:
+ KW_PASS name_opt '{' '}'
+
pass_list:
- %empty
+ pass
+ | pass_list pass
+
+passes:
+ scope_start
+ | scope_start pass_list
technique9:
- KW_TECHNIQUE technique_name '{' pass_list '}'
+ KW_TECHNIQUE name_opt '{' passes '}'
{
- if (!add_technique(ctx, $2, "technique", &@1))
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
+ if (!add_technique(ctx, $2, scope, "technique", &@1))
YYABORT;
}
technique10:
- KW_TECHNIQUE10 technique_name '{' pass_list '}'
+ KW_TECHNIQUE10 name_opt '{' passes '}'
{
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
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.");
- if (!add_technique(ctx, $2, "technique10", &@1))
+ if (!add_technique(ctx, $2, scope, "technique10", &@1))
YYABORT;
}
technique11:
- KW_TECHNIQUE11 technique_name '{' pass_list '}'
+ KW_TECHNIQUE11 name_opt '{' passes '}'
{
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
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.");
- if (!add_technique(ctx, $2, "technique11", &@1))
+ if (!add_technique(ctx, $2, scope, "technique11", &@1))
YYABORT;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
index acc19dd8ba5..d37bef15cce 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
@@ -32,6 +32,11 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
switch (type->class)
{
case HLSL_CLASS_VECTOR:
+ if (idx->type != HLSL_IR_CONSTANT)
+ {
+ hlsl_fixme(ctx, &idx->loc, "Non-constant vector addressing.");
+ break;
+ }
*offset_component += hlsl_ir_constant(idx)->value.u[0].u;
break;
@@ -2478,6 +2483,38 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir
return false;
}
+static bool validate_nonconstant_vector_store_derefs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block)
+{
+ struct hlsl_ir_node *idx;
+ struct hlsl_deref *deref;
+ struct hlsl_type *type;
+ unsigned int i;
+
+ if (instr->type != HLSL_IR_STORE)
+ return false;
+
+ deref = &hlsl_ir_store(instr)->lhs;
+ assert(deref->var);
+
+ if (deref->path_len == 0)
+ return false;
+
+ type = deref->var->data_type;
+ for (i = 0; i < deref->path_len - 1; ++i)
+ type = hlsl_get_element_type_from_path_index(ctx, type, deref->path[i].node);
+
+ idx = deref->path[deref->path_len - 1].node;
+
+ if (type->class == HLSL_CLASS_VECTOR && idx->type != HLSL_IR_CONSTANT)
+ {
+ /* We should turn this into an hlsl_error after we implement unrolling, because if we get
+ * here after that, it means that the HLSL is invalid. */
+ hlsl_fixme(ctx, &instr->loc, "Non-constant vector addressing on store. Unrolling may be missing.");
+ }
+
+ return false;
+}
+
/* Lower combined samples and sampler variables to synthesized separated textures and samplers.
* That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */
static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
@@ -4969,6 +5006,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
lower_ir(ctx, lower_abs, body);
}
+ lower_ir(ctx, validate_nonconstant_vector_store_derefs, body);
+
/* TODO: move forward, remove when no longer needed */
transform_derefs(ctx, replace_deref_path_with_offset, body);
while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));
diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c
index 9fd60fa76a4..28c7d158452 100644
--- a/libs/vkd3d/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c
@@ -1511,7 +1511,7 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
vkd3d_shader_trace(instructions, &parser->shader_version);
if (result >= 0 && !parser->failed)
- vsir_validate(parser);
+ result = vsir_validate(parser);
if (result >= 0 && parser->failed)
result = VKD3D_ERROR_INVALID_SHADER;
@@ -1523,10 +1523,26 @@ struct validation_context
{
struct vkd3d_shader_parser *parser;
size_t instruction_idx;
+ bool invalid_instruction_idx;
bool dcl_temps_found;
unsigned int temp_count;
enum vkd3d_shader_opcode phase;
+ struct validation_context_temp_data
+ {
+ enum vsir_dimension dimension;
+ size_t first_seen;
+ } *temps;
+
+ struct validation_context_ssa_data
+ {
+ enum vsir_dimension dimension;
+ size_t first_seen;
+ uint32_t write_mask;
+ uint32_t read_mask;
+ size_t first_assigned;
+ } *ssas;
+
enum vkd3d_shader_opcode *blocks;
size_t depth;
size_t blocks_capacity;
@@ -1544,8 +1560,16 @@ static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *c
vkd3d_string_buffer_vprintf(&buf, format, args);
va_end(args);
- vkd3d_shader_parser_error(ctx->parser, error, "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer);
- ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer);
+ if (ctx->invalid_instruction_idx)
+ {
+ vkd3d_shader_parser_error(ctx->parser, error, "%s", buf.buffer);
+ ERR("VSIR validation error: %s\n", buf.buffer);
+ }
+ else
+ {
+ vkd3d_shader_parser_error(ctx->parser, error, "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer);
+ ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer);
+ }
vkd3d_string_buffer_cleanup(&buf);
}
@@ -1592,30 +1616,101 @@ static void vsir_validate_register(struct validation_context *ctx,
switch (reg->type)
{
case VKD3DSPR_TEMP:
+ {
+ struct validation_context_temp_data *data;
+
if (reg->idx_count != 1)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a TEMP register.",
reg->idx_count);
+ break;
+ }
- if (reg->idx_count >= 1 && reg->idx[0].rel_addr)
+ if (reg->idx[0].rel_addr)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a TEMP register.");
- if (reg->idx_count >= 1 && reg->idx[0].offset >= temp_count)
+ if (reg->idx[0].offset >= temp_count)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "TEMP register index %u exceeds the maximum count %u.",
reg->idx[0].offset, temp_count);
+ break;
+ }
+
+ /* parser->shader_desc.temp_count might be smaller then
+ * temp_count if the parser made a mistake; we still don't
+ * want to overflow the array. */
+ if (reg->idx[0].offset >= ctx->parser->shader_desc.temp_count)
+ break;
+ data = &ctx->temps[reg->idx[0].offset];
+
+ if (reg->dimension == VSIR_DIMENSION_NONE)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a TEMP register.");
+ break;
+ }
+
+ /* TEMP registers can be scalar or vec4, provided that
+ * each individual register always appears with the same
+ * dimension. */
+ if (data->dimension == VSIR_DIMENSION_NONE)
+ {
+ data->dimension = reg->dimension;
+ data->first_seen = ctx->instruction_idx;
+ }
+ else if (data->dimension != reg->dimension)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a TEMP register: "
+ "it has already been seen with dimension %#x at instruction %zu.",
+ reg->dimension, data->dimension, data->first_seen);
+ }
break;
+ }
case VKD3DSPR_SSA:
+ {
+ struct validation_context_ssa_data *data;
+
if (reg->idx_count != 1)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a SSA register.",
reg->idx_count);
+ break;
+ }
- if (reg->idx_count >= 1 && reg->idx[0].rel_addr)
+ if (reg->idx[0].rel_addr)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a SSA register.");
- if (reg->idx_count >= 1 && reg->idx[0].offset >= ctx->parser->shader_desc.ssa_count)
+ if (reg->idx[0].offset >= ctx->parser->shader_desc.ssa_count)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "SSA register index %u exceeds the maximum count %u.",
reg->idx[0].offset, ctx->parser->shader_desc.ssa_count);
+ break;
+ }
+
+ data = &ctx->ssas[reg->idx[0].offset];
+
+ if (reg->dimension == VSIR_DIMENSION_NONE)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a SSA register.");
+ break;
+ }
+
+ /* SSA registers can be scalar or vec4, provided that each
+ * individual register always appears with the same
+ * dimension. */
+ if (data->dimension == VSIR_DIMENSION_NONE)
+ {
+ data->dimension = reg->dimension;
+ data->first_seen = ctx->instruction_idx;
+ }
+ else if (data->dimension != reg->dimension)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a SSA register: "
+ "it has already been seen with dimension %#x at instruction %zu.",
+ reg->dimension, data->dimension, data->first_seen);
+ }
break;
+ }
case VKD3DSPR_NULL:
if (reg->idx_count != 0)
@@ -1688,6 +1783,23 @@ static void vsir_validate_dst_param(struct validation_context *ctx,
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, "Destination has invalid shift %#x.",
dst->shift);
}
+
+ if (dst->reg.type == VKD3DSPR_SSA && dst->reg.idx[0].offset < ctx->parser->shader_desc.ssa_count)
+ {
+ struct validation_context_ssa_data *data = &ctx->ssas[dst->reg.idx[0].offset];
+
+ if (data->write_mask == 0)
+ {
+ data->write_mask = dst->write_mask;
+ data->first_assigned = ctx->instruction_idx;
+ }
+ else
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE,
+ "SSA register is already assigned at instruction %zu.",
+ data->first_assigned);
+ }
+ }
}
static void vsir_validate_src_param(struct validation_context *ctx,
@@ -1706,6 +1818,15 @@ static void vsir_validate_src_param(struct validation_context *ctx,
if (src->modifiers >= VKD3DSPSM_COUNT)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.",
src->modifiers);
+
+ if (src->reg.type == VKD3DSPR_SSA && src->reg.idx[0].offset < ctx->parser->shader_desc.ssa_count)
+ {
+ struct validation_context_ssa_data *data = &ctx->ssas[src->reg.idx[0].offset];
+ unsigned int i;
+
+ for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+ data->read_mask |= (1u << vsir_swizzle_get_component(src->swizzle, i));
+ }
}
static void vsir_validate_dst_count(struct validation_context *ctx,
@@ -1877,22 +1998,52 @@ static void vsir_validate_instruction(struct validation_context *ctx)
}
}
-void vsir_validate(struct vkd3d_shader_parser *parser)
+enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser)
{
struct validation_context ctx =
{
.parser = parser,
.phase = VKD3DSIH_INVALID,
};
+ unsigned int i;
if (!(parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION))
- return;
+ return VKD3D_OK;
+
+ if (!(ctx.temps = vkd3d_calloc(parser->shader_desc.temp_count, sizeof(*ctx.temps))))
+ goto fail;
+
+ if (!(ctx.ssas = vkd3d_calloc(parser->shader_desc.ssa_count, sizeof(*ctx.ssas))))
+ goto fail;
for (ctx.instruction_idx = 0; ctx.instruction_idx < parser->instructions.count; ++ctx.instruction_idx)
vsir_validate_instruction(&ctx);
+ ctx.invalid_instruction_idx = true;
+
if (ctx.depth != 0)
validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "%zu nested blocks were not closed.", ctx.depth);
- free(ctx.blocks);
+ for (i = 0; i < parser->shader_desc.ssa_count; ++i)
+ {
+ struct validation_context_ssa_data *data = &ctx.ssas[i];
+
+ if ((data->write_mask | data->read_mask) != data->write_mask)
+ validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE,
+ "SSA register %u has invalid read mask %#x, which is not a subset of the write mask %#x "
+ "at the point of definition.", i, data->read_mask, data->write_mask);
+ }
+
+ vkd3d_free(ctx.blocks);
+ vkd3d_free(ctx.temps);
+ vkd3d_free(ctx.ssas);
+
+ return VKD3D_OK;
+
+fail:
+ vkd3d_free(ctx.blocks);
+ vkd3d_free(ctx.temps);
+ vkd3d_free(ctx.ssas);
+
+ return VKD3D_ERROR_OUT_OF_MEMORY;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c
index a9e02d0a98e..7743319bed5 100644
--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c
@@ -6907,8 +6907,8 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t src_id[SPIRV_MAX_SRC_COUNT];
uint32_t instr_set_id, type_id, val_id;
+ unsigned int i, component_count;
enum GLSLstd450 glsl_inst;
- unsigned int i;
glsl_inst = spirv_compiler_map_ext_glsl_instruction(instruction);
if (glsl_inst == GLSLstd450Bad)
@@ -6934,8 +6934,9 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp
|| instruction->handler_idx == VKD3DSIH_FIRSTBIT_SHI)
{
/* In D3D bits are numbered from the most significant bit. */
+ component_count = vsir_write_mask_component_count(dst->write_mask);
val_id = vkd3d_spirv_build_op_isub(builder, type_id,
- spirv_compiler_get_constant_uint(compiler, 31), val_id);
+ spirv_compiler_get_constant_uint_vector(compiler, 31, component_count), val_id);
}
spirv_compiler_emit_store_dst(compiler, dst, val_id);
diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c
index 43b3525bb7b..1f1944bc0da 100644
--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c
+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c
@@ -821,7 +821,7 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u
const uint32_t *end = &tokens[token_count];
enum vkd3d_sm4_data_type data_type;
enum vkd3d_data_type reg_data_type;
- DWORD components;
+ uint32_t components;
unsigned int i;
resource_type = (opcode_token & VKD3D_SM4_RESOURCE_TYPE_MASK) >> VKD3D_SM4_RESOURCE_TYPE_SHIFT;
@@ -1759,11 +1759,11 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
const struct vkd3d_sm4_register_type_info *register_type_info;
enum vkd3d_shader_register_type vsir_register_type;
enum vkd3d_sm4_register_precision precision;
+ uint32_t token, order, extended, addressing;
enum vkd3d_sm4_register_type register_type;
enum vkd3d_sm4_extended_operand_type type;
- enum vkd3d_sm4_register_modifier m;
enum vkd3d_sm4_dimension sm4_dimension;
- uint32_t token, order, extended;
+ enum vkd3d_sm4_register_modifier m;
if (*ptr >= end)
{
@@ -1861,7 +1861,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 1)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK0) >> VKD3D_SM4_ADDRESSING_SHIFT0;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK0) >> VKD3D_SM4_ADDRESSING_SHIFT0;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[0])))
{
ERR("Failed to read register index.\n");
@@ -1871,7 +1871,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 2)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK1) >> VKD3D_SM4_ADDRESSING_SHIFT1;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK1) >> VKD3D_SM4_ADDRESSING_SHIFT1;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[1])))
{
ERR("Failed to read register index.\n");
@@ -1881,7 +1881,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 3)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[2])))
{
ERR("Failed to read register index.\n");
@@ -2075,7 +2075,7 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons
const uint32_t *end, enum vkd3d_data_type data_type, struct vkd3d_shader_src_param *src_param)
{
unsigned int dimension, mask;
- DWORD token;
+ uint32_t token;
if (*ptr >= end)
{
@@ -2162,7 +2162,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons
enum vkd3d_sm4_swizzle_type swizzle_type;
enum vkd3d_shader_src_modifier modifier;
unsigned int dimension, swizzle;
- DWORD token;
+ uint32_t token;
if (*ptr >= end)
{
@@ -2242,7 +2242,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons
return true;
}
-static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_shader_instruction *ins)
+static void shader_sm4_read_instruction_modifier(uint32_t modifier, struct vkd3d_shader_instruction *ins)
{
enum vkd3d_sm4_instruction_modifier modifier_type = modifier & VKD3D_SM4_MODIFIER_MASK;
@@ -2250,7 +2250,7 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh
{
case VKD3D_SM4_MODIFIER_AOFFIMMI:
{
- static const DWORD recognized_bits = VKD3D_SM4_INSTRUCTION_MODIFIER
+ static const uint32_t recognized_bits = VKD3D_SM4_INSTRUCTION_MODIFIER
| VKD3D_SM4_MODIFIER_MASK
| VKD3D_SM4_AOFFIMMI_U_MASK
| VKD3D_SM4_AOFFIMMI_V_MASK
@@ -2278,7 +2278,7 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh
case VKD3D_SM5_MODIFIER_DATA_TYPE:
{
- DWORD components = (modifier & VKD3D_SM5_MODIFIER_DATA_TYPE_MASK) >> VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT;
+ uint32_t components = (modifier & VKD3D_SM5_MODIFIER_DATA_TYPE_MASK) >> VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT;
unsigned int i;
for (i = 0; i < VKD3D_VEC4_SIZE; i++)
@@ -2334,9 +2334,9 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str
struct vkd3d_shader_src_param *src_params;
const uint32_t **ptr = &sm4->ptr;
unsigned int i, len;
- size_t remaining;
const uint32_t *p;
- DWORD precise;
+ uint32_t precise;
+ size_t remaining;
if (*ptr >= sm4->end)
{
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
index cc156f88074..0af7ea0d266 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -216,6 +216,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS = 9014,
VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015,
VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING = 9016,
+ VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017,
VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300,
};
@@ -1450,7 +1451,7 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context);
-void vsir_validate(struct vkd3d_shader_parser *parser);
+enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser);
static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_type(
enum vkd3d_data_type data_type)
--
2.43.0