From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Use struct vkd3d_string_buffer, stop expecting uniforms in function parameters.
libs/vkd3d-shader/hlsl_codegen.c | 59 +++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 21bd9ab..e9f3699 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -19,6 +19,49 @@ */
#include "hlsl.h" +#include <stdio.h> + +/* Split uniforms into two variables representing the constant and temp + * registers, and copy the former to the latter, so that writes to uniforms + * work. */ +static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) +{ + struct vkd3d_string_buffer *name; + struct hlsl_ir_assignment *store; + struct hlsl_ir_var *const_var; + struct hlsl_ir_load *load; + + if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) + { + ctx->failed = true; + return; + } + vkd3d_string_buffer_printf(name, "<uniform-%s>", var->name); + if (!(const_var = hlsl_new_var(vkd3d_strdup(name->buffer), var->data_type, var->loc, NULL, var->reg_reservation))) + { + vkd3d_string_buffer_release(&ctx->string_buffers, name); + ctx->failed = true; + return; + } + vkd3d_string_buffer_release(&ctx->string_buffers, name); + list_add_head(&ctx->globals->vars, &const_var->scope_entry); + var->is_uniform = 0; + const_var->is_uniform = 1; + + if (!(load = hlsl_new_var_load(const_var, var->loc))) + { + ctx->failed = true; + return; + } + list_add_head(instrs, &load->node.entry); + + if (!(store = hlsl_new_simple_assignment(var, &load->node))) + { + ctx->failed = true; + return; + } + list_add_after(&load->node.entry, &store->node.entry); +}
static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct list *instrs, void *context) @@ -404,7 +447,7 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) { - if (var->is_input_varying || var->is_uniform) + if (var->is_input_varying) var->first_write = 1; if (var->is_output_varying) var->last_read = UINT_MAX; @@ -418,8 +461,22 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) { + struct hlsl_ir_var *var; + list_move_head(entry_func->body, &ctx->static_initializers);
+ LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + if (var->is_uniform) + prepend_uniform_copy(ctx, entry_func->body, var); + } + + LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) + { + if (var->is_uniform) + prepend_uniform_copy(ctx, entry_func->body, var); + } + while (transform_ir(ctx, fold_redundant_casts, entry_func->body, NULL)); while (transform_ir(ctx, split_struct_copies, entry_func->body, NULL)); while (transform_ir(ctx, fold_constants, entry_func->body, NULL));
From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 9 +++++++++ tests/hlsl-invalid.shader_test | 13 +++++++++++++ 2 files changed, 22 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 794166d..daf354d 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1626,6 +1626,7 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d struct hlsl_ir_function_decl *entry_func; const struct hlsl_profile_info *profile; const char *entry_point; + struct hlsl_ir_var *var; struct hlsl_ctx ctx; int ret;
@@ -1668,6 +1669,14 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d return VKD3D_ERROR_INVALID_SHADER; }
+ LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) + { + if (var->data_type->type != HLSL_CLASS_STRUCT && !var->semantic + && (var->is_input_varying || var->is_output_varying)) + hlsl_error(&ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Parameter "%s" is missing a semantic.", var->name); + } + if (!hlsl_type_is_void(entry_func->return_type) && entry_func->return_type->type != HLSL_CLASS_STRUCT && !entry_func->semantic) hlsl_error(&ctx, entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index 370d84d..b30ff3d 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -108,6 +108,19 @@ float4 main(out float4 o : sv_target) return 0; }
+[pixel shader fail] +float4 main(out float4 o) : sv_target +{ + o = 1; + return 0; +} + +[pixel shader fail] +float4 main(in float4 i) : sv_target +{ + return 0; +} + [pixel shader fail] struct {float4 a;};
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Use struct vkd3d_string_buffer, initialize first_write for the new input varyings.
libs/vkd3d-shader/hlsl_codegen.c | 83 ++++++++++++++++++++++++++++++-- tests/hlsl-invalid.shader_test | 11 +++++ 2 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e9f3699..ca38fe7 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -63,6 +63,83 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, stru list_add_after(&load->node.entry, &store->node.entry); }
+static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int field_offset, const char *semantic) +{ + struct vkd3d_string_buffer *name; + struct hlsl_ir_assignment *store; + struct hlsl_ir_constant *offset; + struct hlsl_ir_var *varying; + struct hlsl_ir_load *load; + + if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) + { + ctx->failed = true; + return; + } + vkd3d_string_buffer_printf(name, "<input-%s>", semantic); + if (!(varying = hlsl_new_var(vkd3d_strdup(name->buffer), type, var->loc, vkd3d_strdup(semantic), NULL))) + { + vkd3d_string_buffer_release(&ctx->string_buffers, name); + ctx->failed = true; + return; + } + vkd3d_string_buffer_release(&ctx->string_buffers, name); + varying->is_input_varying = 1; + list_add_head(&ctx->globals->vars, &varying->scope_entry); + + if (!(load = hlsl_new_var_load(varying, var->loc))) + { + ctx->failed = true; + return; + } + list_add_head(instrs, &load->node.entry); + + if (!(offset = hlsl_new_uint_constant(ctx, field_offset * 4, var->loc))) + { + ctx->failed = true; + return; + } + list_add_after(&load->node.entry, &offset->node.entry); + + if (!(store = hlsl_new_assignment(var, &offset->node, &load->node, 0, var->loc))) + { + ctx->failed = true; + return; + } + list_add_after(&offset->node.entry, &store->node.entry); +} + +static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int field_offset) +{ + struct hlsl_struct_field *field; + + LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + { + if (field->type->type == HLSL_CLASS_STRUCT) + prepend_input_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); + else if (field->semantic) + prepend_input_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset, field->semantic); + else + hlsl_error(ctx, field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Field '%s' is missing a semantic.", field->name); + } +} + +/* Split input varyings into two variables representing the varying and temp + * registers, and copy the former to the latter, so that writes to input + * varyings work. */ +static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) +{ + if (var->data_type->type == HLSL_CLASS_STRUCT) + prepend_input_struct_copy(ctx, instrs, var, var->data_type, 0); + else if (var->semantic) + prepend_input_copy(ctx, instrs, var, var->data_type, 0, var->semantic); + + var->is_input_varying = 0; +} + static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct list *instrs, void *context) { @@ -441,14 +518,12 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) { - if (var->is_uniform) + if (var->is_uniform || var->is_input_varying) var->first_write = 1; }
LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) { - if (var->is_input_varying) - var->first_write = 1; if (var->is_output_varying) var->last_read = UINT_MAX; } @@ -475,6 +550,8 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun { if (var->is_uniform) prepend_uniform_copy(ctx, entry_func->body, var); + if (var->is_input_varying) + prepend_input_var_copy(ctx, entry_func->body, var); }
while (transform_ir(ctx, fold_redundant_casts, entry_func->body, NULL)); diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index b30ff3d..59a0dbe 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -135,3 +135,14 @@ float4 main() : sv_target const float4 x; return x; } + +[pixel shader fail] +struct input +{ + float4 a; +}; + +float4 main(struct input i) : sv_target +{ + return i.a; +}
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 9 +++------ libs/vkd3d-shader/hlsl.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index daf354d..53b9db3 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -563,7 +563,6 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hl return NULL; decl->return_type = return_type; decl->parameters = parameters; - decl->semantic = semantic; decl->loc = loc;
if (!hlsl_type_is_void(return_type)) @@ -572,11 +571,12 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hl char name[28];
sprintf(name, "<retval-%p>", decl); - if (!(return_var = hlsl_new_synthetic_var(ctx, name, return_type, loc))) + if (!(return_var = hlsl_new_var(vkd3d_strdup(name), return_type, loc, semantic, NULL))) { vkd3d_free(decl); return NULL; } + list_add_tail(&ctx->globals->vars, &return_var->scope_entry); decl->return_var = return_var; }
@@ -1161,8 +1161,6 @@ void hlsl_dump_function(const struct hlsl_ir_function_decl *func) dump_ir_var(&buffer, param); vkd3d_string_buffer_printf(&buffer, "\n"); } - if (func->semantic) - vkd3d_string_buffer_printf(&buffer, "Function semantic: %s\n", func->semantic); if (func->body) dump_instr_list(&buffer, func->body);
@@ -1302,7 +1300,6 @@ void hlsl_free_instr(struct hlsl_ir_node *node)
static void free_function_decl(struct hlsl_ir_function_decl *decl) { - vkd3d_free((void *)decl->semantic); vkd3d_free(decl->parameters); hlsl_free_instr_list(decl->body); vkd3d_free(decl); @@ -1678,7 +1675,7 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d }
if (!hlsl_type_is_void(entry_func->return_type) - && entry_func->return_type->type != HLSL_CLASS_STRUCT && !entry_func->semantic) + && entry_func->return_type->type != HLSL_CLASS_STRUCT && !entry_func->return_var->semantic) hlsl_error(&ctx, entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, "Entry point "%s" is missing a return value semantic.", entry_point);
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index cc740ea..cf12f63 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -229,7 +229,6 @@ struct hlsl_ir_function_decl struct vkd3d_shader_location loc; struct rb_entry entry; struct hlsl_ir_function *func; - const char *semantic; struct list *parameters; struct list *body; };
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2: Use struct vkd3d_string_buffer, initialize last_read for the new output varyings.
libs/vkd3d-shader/hlsl_codegen.c | 86 +++++++++++++++++++++++++++++++- tests/hlsl-invalid.shader_test | 13 +++++ 2 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index ca38fe7..dbd591a 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -140,6 +140,83 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st var->is_input_varying = 0; }
+static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int field_offset, const char *semantic) +{ + struct vkd3d_string_buffer *name; + struct hlsl_ir_assignment *store; + struct hlsl_ir_constant *offset; + struct hlsl_ir_var *varying; + struct hlsl_ir_load *load; + + if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) + { + ctx->failed = true; + return; + } + vkd3d_string_buffer_printf(name, "<output-%s>", semantic); + if (!(varying = hlsl_new_var(vkd3d_strdup(name->buffer), type, var->loc, vkd3d_strdup(semantic), NULL))) + { + vkd3d_string_buffer_release(&ctx->string_buffers, name); + ctx->failed = true; + return; + } + vkd3d_string_buffer_release(&ctx->string_buffers, name); + varying->is_output_varying = 1; + list_add_head(&ctx->globals->vars, &varying->scope_entry); + + if (!(offset = hlsl_new_uint_constant(ctx, field_offset * 4, var->loc))) + { + ctx->failed = true; + return; + } + list_add_tail(instrs, &offset->node.entry); + + if (!(load = hlsl_new_load(var, &offset->node, type, var->loc))) + { + ctx->failed = true; + return; + } + list_add_after(&offset->node.entry, &load->node.entry); + + if (!(store = hlsl_new_assignment(varying, NULL, &load->node, 0, var->loc))) + { + ctx->failed = true; + return; + } + list_add_after(&load->node.entry, &store->node.entry); +} + +static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int field_offset) +{ + struct hlsl_struct_field *field; + + LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + { + if (field->type->type == HLSL_CLASS_STRUCT) + append_output_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); + else if (field->semantic) + append_output_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset, field->semantic); + else + hlsl_error(ctx, field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Field '%s' is missing a semantic.", field->name); + } +} + +/* Split output varyings into two variables representing the temp and varying + * registers, and copy the former to the latter, so that reads from output + * varyings work. */ +static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) +{ + if (var->data_type->type == HLSL_CLASS_STRUCT) + append_output_struct_copy(ctx, instrs, var, var->data_type, 0); + else if (var->semantic) + append_output_copy(ctx, instrs, var, var->data_type, 0, var->semantic); + + var->is_output_varying = 0; +} + static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct list *instrs, void *context) { @@ -520,12 +597,13 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl { if (var->is_uniform || var->is_input_varying) var->first_write = 1; + else if (var->is_output_varying) + var->last_read = UINT_MAX; }
LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) { - if (var->is_output_varying) - var->last_read = UINT_MAX; + var->first_write = 1; }
if (entry_func->return_var) @@ -552,7 +630,11 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun prepend_uniform_copy(ctx, entry_func->body, var); if (var->is_input_varying) prepend_input_var_copy(ctx, entry_func->body, var); + if (var->is_output_varying) + append_output_var_copy(ctx, entry_func->body, var); } + if (entry_func->return_var) + append_output_var_copy(ctx, entry_func->body, entry_func->return_var);
while (transform_ir(ctx, fold_redundant_casts, entry_func->body, NULL)); while (transform_ir(ctx, split_struct_copies, entry_func->body, NULL)); diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index 59a0dbe..0711d26 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -146,3 +146,16 @@ float4 main(struct input i) : sv_target { return i.a; } + +[pixel shader fail] +struct output +{ + float4 t : sv_target; + int a; +}; + +void main(out struct output o) +{ + o.t = float4(0, 0, 0, 0); + o.a = 0; +}
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com