vkd3d-shader/hlsl: Record default values for uniforms and constant buffers.

This commit is contained in:
Francisco Casas 2024-04-08 16:15:20 -04:00 committed by Henri Verbeet
parent 1fe7a6581b
commit e8dbc36bd2
Notes: Henri Verbeet 2024-06-11 16:55:09 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/787
7 changed files with 147 additions and 44 deletions

View File

@ -794,6 +794,9 @@ static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct f
case HLSL_CLASS_MATRIX: case HLSL_CLASS_MATRIX:
case HLSL_CLASS_STRUCT: case HLSL_CLASS_STRUCT:
/* FIXME: write actual initial value */ /* FIXME: write actual initial value */
if (var->default_values)
hlsl_fixme(fx->ctx, &var->loc, "Write default values.\n");
offset = put_u32(buffer, 0); offset = put_u32(buffer, 0);
for (uint32_t i = 1; i < size / sizeof(uint32_t); ++i) for (uint32_t i = 1; i < size / sizeof(uint32_t); ++i)
@ -1010,6 +1013,8 @@ static void write_fx_4_numeric_variable(struct hlsl_ir_var *var, bool shared, st
{ {
/* FIXME: write default value */ /* FIXME: write default value */
set_u32(buffer, value_offset, 0); set_u32(buffer, value_offset, 0);
if (var->default_values)
hlsl_fixme(fx->ctx, &var->loc, "Write default values.\n");
put_u32(buffer, 0); /* Annotations count */ put_u32(buffer, 0); /* Annotations count */
if (has_annotations(var)) if (has_annotations(var))

View File

@ -167,6 +167,8 @@ void hlsl_free_var(struct hlsl_ir_var *decl)
for (k = 0; k <= HLSL_REGSET_LAST_OBJECT; ++k) for (k = 0; k <= HLSL_REGSET_LAST_OBJECT; ++k)
vkd3d_free((void *)decl->objects_usage[k]); vkd3d_free((void *)decl->objects_usage[k]);
vkd3d_free(decl->default_values);
for (i = 0; i < decl->state_block_count; ++i) for (i = 0; i < decl->state_block_count; ++i)
hlsl_free_state_block(decl->state_blocks[i]); hlsl_free_state_block(decl->state_blocks[i]);
vkd3d_free(decl->state_blocks); vkd3d_free(decl->state_blocks);
@ -1247,6 +1249,7 @@ struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const cha
list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry);
else else
list_add_tail(&ctx->globals->vars, &var->scope_entry); list_add_tail(&ctx->globals->vars, &var->scope_entry);
var->is_synthetic = true;
} }
return var; return var;
} }
@ -3086,6 +3089,33 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl
vkd3d_string_buffer_cleanup(&buffer); vkd3d_string_buffer_cleanup(&buffer);
} }
void hlsl_dump_var_default_values(const struct hlsl_ir_var *var)
{
unsigned int k, component_count = hlsl_type_component_count(var->data_type);
struct vkd3d_string_buffer buffer;
vkd3d_string_buffer_init(&buffer);
if (!var->default_values)
{
vkd3d_string_buffer_printf(&buffer, "var \"%s\" has no default values.\n", var->name);
vkd3d_string_buffer_trace(&buffer);
vkd3d_string_buffer_cleanup(&buffer);
return;
}
vkd3d_string_buffer_printf(&buffer, "var \"%s\" default values:", var->name);
for (k = 0; k < component_count; ++k)
{
if (k % 4 == 0)
vkd3d_string_buffer_printf(&buffer, "\n ");
vkd3d_string_buffer_printf(&buffer, " 0x%08x", var->default_values[k].value.u);
}
vkd3d_string_buffer_printf(&buffer, "\n");
vkd3d_string_buffer_trace(&buffer);
vkd3d_string_buffer_cleanup(&buffer);
}
void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new) void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new)
{ {
struct hlsl_src *src, *next; struct hlsl_src *src, *next;

View File

@ -396,6 +396,14 @@ struct hlsl_reg_reservation
unsigned int offset_index; unsigned int offset_index;
}; };
union hlsl_constant_value_component
{
uint32_t u;
int32_t i;
float f;
double d;
};
struct hlsl_ir_var struct hlsl_ir_var
{ {
struct hlsl_type *data_type; struct hlsl_type *data_type;
@ -418,6 +426,15 @@ struct hlsl_ir_var
/* Scope that contains annotations for this variable. */ /* Scope that contains annotations for this variable. */
struct hlsl_scope *annotations; struct hlsl_scope *annotations;
/* Array of default values the variable was initialized with, one for each component.
* Only for variables that need it, such as uniforms and variables inside constant buffers.
* This pointer is NULL for others. */
struct hlsl_default_value
{
/* Default value, in case the component is a numeric value. */
union hlsl_constant_value_component value;
} *default_values;
/* A dynamic array containing the state block on the variable's declaration, if any. /* A dynamic array containing the state block on the variable's declaration, if any.
* An array variable may contain multiple state blocks. * An array variable may contain multiple state blocks.
* A technique pass will always contain one. * A technique pass will always contain one.
@ -460,6 +477,7 @@ struct hlsl_ir_var
uint32_t is_uniform : 1; uint32_t is_uniform : 1;
uint32_t is_param : 1; uint32_t is_param : 1;
uint32_t is_separated_resource : 1; uint32_t is_separated_resource : 1;
uint32_t is_synthetic : 1;
}; };
/* This struct is used to represent assignments in state block entries: /* This struct is used to represent assignments in state block entries:
@ -775,13 +793,7 @@ struct hlsl_ir_constant
struct hlsl_ir_node node; struct hlsl_ir_node node;
struct hlsl_constant_value struct hlsl_constant_value
{ {
union hlsl_constant_value_component union hlsl_constant_value_component u[4];
{
uint32_t u;
int32_t i;
float f;
double d;
} u[4];
} value; } value;
/* Constant register of type 'c' where the constant value is stored for SM1. */ /* Constant register of type 'c' where the constant value is stored for SM1. */
struct hlsl_reg reg; struct hlsl_reg reg;
@ -1249,6 +1261,7 @@ void hlsl_block_cleanup(struct hlsl_block *block);
bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const struct hlsl_block *src_block); bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const struct hlsl_block *src_block);
void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func); void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func);
void hlsl_dump_var_default_values(const struct hlsl_ir_var *var);
void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body);
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func,

View File

@ -1286,13 +1286,13 @@ static struct hlsl_block *make_block(struct hlsl_ctx *ctx, struct hlsl_ir_node *
return block; return block;
} }
static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block, static union hlsl_constant_value_component evaluate_static_expression(struct hlsl_ctx *ctx,
const struct vkd3d_shader_location *loc) struct hlsl_block *block, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc)
{ {
union hlsl_constant_value_component ret = {0};
struct hlsl_ir_constant *constant; struct hlsl_ir_constant *constant;
struct hlsl_ir_node *node; struct hlsl_ir_node *node;
struct hlsl_block expr; struct hlsl_block expr;
unsigned int ret = 0;
struct hlsl_src src; struct hlsl_src src;
LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry) LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry)
@ -1305,29 +1305,32 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str
case HLSL_IR_LOAD: case HLSL_IR_LOAD:
case HLSL_IR_INDEX: case HLSL_IR_INDEX:
continue; continue;
case HLSL_IR_STORE:
if (hlsl_ir_store(node)->lhs.var->is_synthetic)
break;
/* fall-through */
case HLSL_IR_CALL: case HLSL_IR_CALL:
case HLSL_IR_IF: case HLSL_IR_IF:
case HLSL_IR_LOOP: case HLSL_IR_LOOP:
case HLSL_IR_JUMP: case HLSL_IR_JUMP:
case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_RESOURCE_LOAD:
case HLSL_IR_RESOURCE_STORE: case HLSL_IR_RESOURCE_STORE:
case HLSL_IR_STORE:
case HLSL_IR_SWITCH: case HLSL_IR_SWITCH:
case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_STATEBLOCK_CONSTANT:
hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"Expected literal expression."); "Expected literal expression.");
break;
} }
} }
if (!hlsl_clone_block(ctx, &expr, &ctx->static_initializers)) if (!hlsl_clone_block(ctx, &expr, &ctx->static_initializers))
return 0; return ret;
hlsl_block_add_block(&expr, block); hlsl_block_add_block(&expr, block);
if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), dst_type, loc))
hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc))
{ {
hlsl_block_cleanup(&expr); hlsl_block_cleanup(&expr);
return 0; return ret;
} }
/* Wrap the node into a src to allow the reference to survive the multiple const passes. */ /* Wrap the node into a src to allow the reference to survive the multiple const passes. */
@ -1339,7 +1342,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str
if (node->type == HLSL_IR_CONSTANT) if (node->type == HLSL_IR_CONSTANT)
{ {
constant = hlsl_ir_constant(node); constant = hlsl_ir_constant(node);
ret = constant->value.u[0].u; ret = constant->value.u[0];
} }
else else
{ {
@ -1352,6 +1355,15 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str
return ret; return ret;
} }
static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block,
const struct vkd3d_shader_location *loc)
{
union hlsl_constant_value_component res;
res = evaluate_static_expression(ctx, block, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc);
return res.u;
}
static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2)
{ {
/* Scalar vars can be converted to pretty much everything */ /* Scalar vars can be converted to pretty much everything */
@ -2087,12 +2099,27 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i
dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index); dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index);
if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) if (dst->default_values)
return; {
struct hlsl_default_value default_value = {0};
if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) if (!hlsl_clone_block(ctx, &block, instrs))
return; return;
hlsl_block_add_block(instrs, &block); default_value.value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc);
dst->default_values[*store_index] = default_value;
hlsl_block_cleanup(&block);
}
else
{
if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc)))
return;
if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv))
return;
hlsl_block_add_block(instrs, &block);
}
++*store_index; ++*store_index;
} }
@ -2348,6 +2375,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
{ {
struct parse_variable_def *v, *v_next; struct parse_variable_def *v, *v_next;
struct hlsl_block *initializers; struct hlsl_block *initializers;
unsigned int component_count;
struct hlsl_ir_var *var; struct hlsl_ir_var *var;
struct hlsl_type *type; struct hlsl_type *type;
@ -2371,6 +2399,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
} }
type = var->data_type; type = var->data_type;
component_count = hlsl_type_component_count(type);
var->state_blocks = v->state_blocks; var->state_blocks = v->state_blocks;
var->state_block_count = v->state_block_count; var->state_block_count = v->state_block_count;
@ -2379,28 +2408,39 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
v->state_block_capacity = 0; v->state_block_capacity = 0;
v->state_blocks = NULL; v->state_blocks = NULL;
if (var->state_blocks && hlsl_type_component_count(type) != var->state_block_count) if (var->state_blocks && component_count != var->state_block_count)
{ {
hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Expected %u state blocks, but got %u.", "Expected %u state blocks, but got %u.", component_count, var->state_block_count);
hlsl_type_component_count(type), var->state_block_count);
free_parse_variable_def(v); free_parse_variable_def(v);
continue; continue;
} }
if (v->initializer.args_count) if (v->initializer.args_count)
{ {
bool is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer)
|| (var->storage_modifiers & HLSL_STORAGE_UNIFORM);
if (is_default_values_initializer)
{
assert(!var->default_values);
if (!(var->default_values = hlsl_calloc(ctx, component_count, sizeof(*var->default_values))))
{
free_parse_variable_def(v);
continue;
}
}
if (v->initializer.braces) if (v->initializer.braces)
{ {
unsigned int size = initializer_size(&v->initializer); unsigned int size = initializer_size(&v->initializer);
unsigned int store_index = 0; unsigned int store_index = 0;
unsigned int k; unsigned int k;
if (hlsl_type_component_count(type) != size) if (component_count != size)
{ {
hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Expected %u components in initializer, but got %u.", "Expected %u components in initializer, but got %u.", component_count, size);
hlsl_type_component_count(type), size);
free_parse_variable_def(v); free_parse_variable_def(v);
continue; continue;
} }
@ -2420,10 +2460,18 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
add_assignment(ctx, v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]); add_assignment(ctx, v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]);
} }
if (var->storage_modifiers & HLSL_STORAGE_STATIC) if (is_default_values_initializer)
{
hlsl_dump_var_default_values(var);
}
else if (var->storage_modifiers & HLSL_STORAGE_STATIC)
{
hlsl_block_add_block(&ctx->static_initializers, v->initializer.instrs); hlsl_block_add_block(&ctx->static_initializers, v->initializer.instrs);
}
else else
{
hlsl_block_add_block(initializers, v->initializer.instrs); hlsl_block_add_block(initializers, v->initializer.instrs);
}
} }
else if (var->storage_modifiers & HLSL_STORAGE_STATIC) else if (var->storage_modifiers & HLSL_STORAGE_STATIC)
{ {
@ -5718,8 +5766,7 @@ hlsl_prog:
| hlsl_prog buffer_declaration buffer_body | hlsl_prog buffer_declaration buffer_body
| hlsl_prog declaration_statement | hlsl_prog declaration_statement
{ {
if (!list_empty(&$2->instrs)) hlsl_block_add_block(&ctx->static_initializers, $2);
hlsl_fixme(ctx, &@2, "Uniform initializer.");
destroy_block($2); destroy_block($2);
} }
| hlsl_prog preproc_directive | hlsl_prog preproc_directive

View File

@ -218,6 +218,14 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block,
uniform->is_uniform = 1; uniform->is_uniform = 1;
uniform->is_param = temp->is_param; uniform->is_param = temp->is_param;
uniform->buffer = temp->buffer; uniform->buffer = temp->buffer;
if (temp->default_values)
{
/* Transfer default values from the temp to the uniform. */
assert(!uniform->default_values);
assert(hlsl_type_component_count(temp->data_type) == hlsl_type_component_count(uniform->data_type));
uniform->default_values = temp->default_values;
temp->default_values = NULL;
}
if (!(new_name = hlsl_sprintf_alloc(ctx, "<temp-%s>", temp->name))) if (!(new_name = hlsl_sprintf_alloc(ctx, "<temp-%s>", temp->name)))
return; return;

View File

@ -1,7 +1,7 @@
% Note that, except for effects, default values do not affect the execution. % Note that, except for effects, default values do not affect the execution.
% The default values are intended to be obtained using reflection. % The default values are intended to be obtained using reflection.
[pixel shader todo] [pixel shader]
float2 a = {1, 2}; float2 a = {1, 2};
float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8}; float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8};
@ -17,7 +17,7 @@ if(sm<4) uniform 8 float4 10 20 0 0
if(sm>=4) uniform 0 float4 10 20 0 0 if(sm>=4) uniform 0 float4 10 20 0 0
if(sm>=4) uniform 4 float4 10 30 50 70 if(sm>=4) uniform 4 float4 10 30 50 70
if(sm>=4) uniform 8 float4 20 40 60 80 if(sm>=4) uniform 8 float4 20 40 60 80
todo(sm<6) draw quad todo(glsl) draw quad
probe all rgba (10, 20, 50, 60) probe all rgba (10, 20, 50, 60)
@ -28,7 +28,7 @@ float4 b = a; // initial value must be a literal expression.
float4 main() : sv_target { return 0; } float4 main() : sv_target { return 0; }
[pixel shader fail(sm<6) todo] [pixel shader fail(sm<6)]
float a = 7; float a = 7;
float4 b = {1, 2, a, 4}; // initial value must be a literal expression. float4 b = {1, 2, a, 4}; // initial value must be a literal expression.
@ -49,7 +49,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
static const float a = 7; static const float a = 7;
float4 b = {1, 2, a, 4}; // static constant values are allowed on the initializer. float4 b = {1, 2, a, 4}; // static constant values are allowed on the initializer.
@ -57,11 +57,11 @@ float4 main() : sv_target { return b; }
[test] [test]
uniform 0 float4 10.0 20.0 30.0 40.0 uniform 0 float4 10.0 20.0 30.0 40.0
todo(sm<6) draw quad todo(glsl) draw quad
probe all rgba (10, 20, 30, 40) probe all rgba (10, 20, 30, 40)
[pixel shader todo] [pixel shader]
float4 a = {3, 5, float2(4, 4)}; // numeric type initializers are allowed. float4 a = {3, 5, float2(4, 4)}; // numeric type initializers are allowed.
float4 main() : sv_target float4 main() : sv_target
@ -71,11 +71,11 @@ float4 main() : sv_target
[test] [test]
uniform 0 float4 10.0 20.0 30.0 40.0 uniform 0 float4 10.0 20.0 30.0 40.0
todo(sm<6) draw quad todo(glsl) draw quad
probe all rgba (20, 40, 60, 80) probe all rgba (20, 40, 60, 80)
[pixel shader todo] [pixel shader]
int4 a[2] = {10, 20, float3x2(1, 2, 3, 4, 5, 6)}; // matrix numeric type initializers are allowed. int4 a[2] = {10, 20, float3x2(1, 2, 3, 4, 5, 6)}; // matrix numeric type initializers are allowed.
float4 main() : sv_target float4 main() : sv_target
@ -88,11 +88,11 @@ if(sm<4) uniform 0 float4 10 20 30 40
if(sm<4) uniform 4 float4 50 60 70 80 if(sm<4) uniform 4 float4 50 60 70 80
if(sm>=4) uniform 0 int4 10 20 30 40 if(sm>=4) uniform 0 int4 10 20 30 40
if(sm>=4) uniform 4 int4 50 60 70 80 if(sm>=4) uniform 4 int4 50 60 70 80
todo(sm<6) draw quad todo(glsl) draw quad
probe all rgba (100, 120, 140, 160) probe all rgba (100, 120, 140, 160)
[pixel shader todo] [pixel shader]
struct apple struct apple
{ {
float3 a[2]; float3 a[2];
@ -111,7 +111,7 @@ if(sm<4) uniform 8 float4 70 90 0 0
if(sm<4) uniform 12 float4 80 100 0 0 if(sm<4) uniform 12 float4 80 100 0 0
if(sm>=4) uniform 8 int4 70 90 0 0 if(sm>=4) uniform 8 int4 70 90 0 0
if(sm>=4) uniform 12 int4 80 100 0 0 if(sm>=4) uniform 12 int4 80 100 0 0
todo(sm<6) draw quad todo(glsl) draw quad
probe all rgba (70, 80, 90, 100) probe all rgba (70, 80, 90, 100)
@ -148,7 +148,7 @@ cbuffer buff
float4 main() : sv_target { return 0; } float4 main() : sv_target { return 0; }
[pixel shader fail(sm<6) todo] [pixel shader fail(sm<6)]
cbuffer buff cbuffer buff
{ {
float a = 7; float a = 7;
@ -236,7 +236,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
static const float3x2 mat = {10, 20, 30, 40, 50, 60}; static const float3x2 mat = {10, 20, 30, 40, 50, 60};
static const float4 array[2] = {1, 2, 3, 4, 5, 6, 7, 8}; static const float4 array[2] = {1, 2, 3, 4, 5, 6, 7, 8};
static const int idx = 1; static const int idx = 1;

View File

@ -8,7 +8,7 @@ float4 main() : sv_target
return 0; return 0;
} }
[pixel shader todo] [pixel shader]
typedef float4 sTring; typedef float4 sTring;
sTring var = float4(1, 2, 3, 4); sTring var = float4(1, 2, 3, 4);