vkd3d-shader/fx: Decompose function-style state assignments to individual states.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
Nikolay Sivov 2024-07-20 11:10:06 +02:00 committed by Henri Verbeet
parent d4c2a7f22b
commit a3f4785720
Notes: Henri Verbeet 2024-08-05 16:17:24 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/978
5 changed files with 276 additions and 53 deletions

View File

@ -99,6 +99,7 @@ vkd3d_shader_tests = \
tests/hlsl/dot.shader_test \ tests/hlsl/dot.shader_test \
tests/hlsl/duplicate-modifiers.shader_test \ tests/hlsl/duplicate-modifiers.shader_test \
tests/hlsl/effect-compile.shader_test \ tests/hlsl/effect-compile.shader_test \
tests/hlsl/effect-pass-states-fx_5.shader_test \
tests/hlsl/effect-shader-objects-fx_2.shader_test \ tests/hlsl/effect-shader-objects-fx_2.shader_test \
tests/hlsl/effect-shader-objects-fx_5.shader_test \ tests/hlsl/effect-shader-objects-fx_5.shader_test \
tests/hlsl/effect-technique-fx_2.shader_test \ tests/hlsl/effect-technique-fx_2.shader_test \

View File

@ -56,36 +56,79 @@ static void string_storage_destroy(struct rb_entry *entry, void *context)
vkd3d_free(string_entry); vkd3d_free(string_entry);
} }
struct state_block_function_info struct function_component
{
const char *name;
bool lhs_has_index;
unsigned int lhs_index;
};
static const struct state_block_function_info
{ {
const char *name; const char *name;
unsigned int min_args, max_args; unsigned int min_args, max_args;
const struct function_component components[3];
}
function_info[] =
{
{"SetBlendState", 3, 3, { { "AB_BlendFactor" }, { "AB_SampleMask" }, { "BlendState" } } },
{"SetDepthStencilState", 2, 2, { { "DS_StencilRef" }, { "DepthStencilState" } } },
{"SetRasterizerState", 1, 1, { { "RasterizerState" } } },
{"SetVertexShader", 1, 1, { { "VertexShader" } } },
{"SetDomainShader", 1, 1, { { "DomainShader" } } },
{"SetHullShader", 1, 1, { { "HullShader" } } },
{"SetGeometryShader", 1, 1, { { "GeometryShader" } } },
{"SetPixelShader", 1, 1, { { "PixelShader" } } },
{"SetComputeShader", 1, 1, { { "ComputeShader" } } },
{"OMSetRenderTargets", 2, 9 },
}; };
static const struct state_block_function_info *get_state_block_function_info(const char *name) static const struct state_block_function_info *get_state_block_function_info(const char *name)
{ {
static const struct state_block_function_info valid_functions[] = for (unsigned int i = 0; i < ARRAY_SIZE(function_info); ++i)
{ {
{"SetBlendState", 3, 3}, if (!strcmp(name, function_info[i].name))
{"SetDepthStencilState", 2, 2}, return &function_info[i];
{"SetRasterizerState", 1, 1},
{"SetVertexShader", 1, 1},
{"SetDomainShader", 1, 1},
{"SetHullShader", 1, 1},
{"SetGeometryShader", 1, 1},
{"SetPixelShader", 1, 1},
{"SetComputeShader", 1, 1},
{"OMSetRenderTargets", 2, 9},
};
for (unsigned int i = 0; i < ARRAY_SIZE(valid_functions); ++i)
{
if (!strcmp(name, valid_functions[i].name))
return &valid_functions[i];
} }
return NULL; return NULL;
} }
static void add_function_component(struct function_component **components, const char *name,
bool lhs_has_index, unsigned int lhs_index)
{
struct function_component *comp = *components;
comp->name = name;
comp->lhs_has_index = lhs_has_index;
comp->lhs_index = lhs_index;
*components = *components + 1;
}
static void get_state_block_function_components(const struct state_block_function_info *info,
struct function_component *components, unsigned int comp_count)
{
unsigned int i;
assert(comp_count >= info->max_args);
if (info->min_args == info->max_args)
{
const struct function_component *c = info->components;
for (i = 0; i < comp_count; ++i, ++c)
add_function_component(&components, c->name, c->lhs_has_index, c->lhs_index);
return;
}
if (!strcmp(info->name, "OMSetRenderTargets"))
{
for (i = 0; i < comp_count - 2; ++i)
add_function_component(&components, "RenderTargetView", true, i + 1);
add_function_component(&components, "DepthStencilView", true, 0);
add_function_component(&components, "RenderTargetView", true, 0);
}
}
bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry, bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry,
const struct vkd3d_shader_location *loc) const struct vkd3d_shader_location *loc)
{ {
@ -189,9 +232,6 @@ static uint32_t write_string(const char *string, struct fx_write_context *fx)
static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
{ {
if (var->state_block_count && var->state_blocks[0]->count)
hlsl_fixme(fx->ctx, &var->loc, "Write pass assignments.");
fx->ops->write_pass(var, fx); fx->ops->write_pass(var, fx);
} }
@ -230,6 +270,8 @@ static void write_fx_4_annotations(struct hlsl_scope *scope, struct fx_write_con
static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx); static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx);
static const char * get_fx_4_type_name(const struct hlsl_type *type); static const char * get_fx_4_type_name(const struct hlsl_type *type);
static void write_fx_4_annotation(struct hlsl_ir_var *var, struct fx_write_context *fx); static void write_fx_4_annotation(struct hlsl_ir_var *var, struct fx_write_context *fx);
static void write_fx_4_state_block(struct hlsl_ir_var *var, unsigned int block_index,
uint32_t count_offset, struct fx_write_context *fx);
static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx) static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx)
{ {
@ -374,15 +416,14 @@ static uint32_t write_fx_4_string(const char *string, struct fx_write_context *f
static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
{ {
struct vkd3d_bytecode_buffer *buffer = &fx->structured; struct vkd3d_bytecode_buffer *buffer = &fx->structured;
uint32_t name_offset; uint32_t name_offset, count_offset;
name_offset = write_string(var->name, fx); name_offset = write_string(var->name, fx);
put_u32(buffer, name_offset); put_u32(buffer, name_offset);
put_u32(buffer, 0); /* Assignment count. */ count_offset = put_u32(buffer, 0);
write_fx_4_annotations(var->annotations, fx); write_fx_4_annotations(var->annotations, fx);
write_fx_4_state_block(var, 0, count_offset, fx);
/* TODO: assignments */
} }
static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
@ -398,6 +439,9 @@ static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx
/* TODO: annotations */ /* TODO: annotations */
/* TODO: assignments */ /* TODO: assignments */
if (var->state_block_count && var->state_blocks[0]->count)
hlsl_fixme(fx->ctx, &var->loc, "Write pass assignments.");
/* For some reason every pass adds to the total shader object count. */ /* For some reason every pass adds to the total shader object count. */
fx->shader_count++; fx->shader_count++;
} }
@ -1348,6 +1392,17 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl
assignment_type = 1; assignment_type = 1;
break; break;
} }
case HLSL_IR_LOAD:
{
struct hlsl_ir_load *l = hlsl_ir_load(value);
if (l->src.path_len)
hlsl_fixme(ctx, &var->loc, "Indexed access in RHS values is not implemented.");
value_offset = write_fx_4_string(l->src.var->name, fx);
assignment_type = 2;
break;
}
default: default:
hlsl_fixme(ctx, &var->loc, "Unsupported assignment type for state %s.", entry->name); hlsl_fixme(ctx, &var->loc, "Unsupported assignment type for state %s.", entry->name);
} }
@ -1424,8 +1479,31 @@ enum state_property_component_type
FX_FLOAT, FX_FLOAT,
FX_UINT, FX_UINT,
FX_UINT8, FX_UINT8,
FX_DS_STATE,
}; };
static inline bool is_object_fx_type(enum state_property_component_type type)
{
switch (type)
{
case FX_DS_STATE:
return true;
default:
return false;
}
}
static inline enum hlsl_type_class hlsl_type_class_from_fx_type(enum state_property_component_type type)
{
switch (type)
{
case FX_DS_STATE:
return HLSL_CLASS_DEPTH_STENCIL_STATE;
default:
vkd3d_unreachable();
}
}
static inline enum hlsl_base_type hlsl_type_from_fx_type(enum state_property_component_type type) static inline enum hlsl_base_type hlsl_type_from_fx_type(enum state_property_component_type type)
{ {
switch (type) switch (type)
@ -1551,6 +1629,9 @@ static void resolve_fx_4_state_block_values(struct hlsl_ir_var *var, struct hlsl
} }
states[] = states[] =
{ {
{ "DepthStencilState", HLSL_CLASS_PASS, HLSL_CLASS_SCALAR, FX_DS_STATE, 1, 1 },
{ "DS_StencilRef", HLSL_CLASS_PASS, HLSL_CLASS_SCALAR, FX_UINT, 1, 9 },
{ "FillMode", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_UINT, 1, 12, fill_values }, { "FillMode", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_UINT, 1, 12, fill_values },
{ "CullMode", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_UINT, 1, 13, cull_values }, { "CullMode", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_UINT, 1, 13, cull_values },
{ "FrontCounterClockwise", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_BOOL, 1, 14 }, { "FrontCounterClockwise", HLSL_CLASS_RASTERIZER_STATE, HLSL_CLASS_SCALAR, FX_BOOL, 1, 14 },
@ -1596,6 +1677,7 @@ static void resolve_fx_4_state_block_values(struct hlsl_ir_var *var, struct hlsl
const struct state *state = NULL; const struct state *state = NULL;
struct hlsl_ctx *ctx = fx->ctx; struct hlsl_ctx *ctx = fx->ctx;
enum hlsl_base_type base_type; enum hlsl_base_type base_type;
struct hlsl_ir_load *load;
unsigned int i; unsigned int i;
for (i = 0; i < ARRAY_SIZE(states); ++i) for (i = 0; i < ARRAY_SIZE(states); ++i)
@ -1632,6 +1714,32 @@ static void resolve_fx_4_state_block_values(struct hlsl_ir_var *var, struct hlsl
/* Now cast and run folding again. */ /* Now cast and run folding again. */
if (is_object_fx_type(state->type))
{
node = entry->args->node;
switch (node->type)
{
case HLSL_IR_LOAD:
load = hlsl_ir_load(node);
if (load->src.path_len)
hlsl_fixme(ctx, &ctx->location, "Arrays are not supported for RHS.");
if (load->src.var->data_type->class != hlsl_type_class_from_fx_type(state->type))
{
hlsl_error(ctx, &ctx->location, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Type mismatch for the %s state value",
entry->name);
}
break;
default:
hlsl_fixme(ctx, &ctx->location, "Unhandled node type for object-typed field.");
}
return;
}
base_type = hlsl_type_from_fx_type(state->type); base_type = hlsl_type_from_fx_type(state->type);
switch (state->class) switch (state->class)
{ {
@ -1676,29 +1784,75 @@ static void resolve_fx_4_state_block_values(struct hlsl_ir_var *var, struct hlsl
} }
} }
static void write_fx_4_state_object_initializer(struct hlsl_ir_var *var, struct fx_write_context *fx) static unsigned int decompose_fx_4_state_block(struct hlsl_ir_var *var, struct hlsl_state_block *block,
unsigned int entry_index, struct fx_write_context *fx)
{ {
uint32_t elements_count = hlsl_get_multiarray_size(var->data_type), i, j; struct hlsl_state_block_entry *entry = block->entries[entry_index];
struct vkd3d_bytecode_buffer *buffer = &fx->structured; const struct state_block_function_info *info;
uint32_t count_offset, count; struct function_component components[9];
struct hlsl_ctx *ctx = fx->ctx;
unsigned int i;
for (i = 0; i < elements_count; ++i) if (!entry->is_function_call)
return 1;
if (!(info = get_state_block_function_info(entry->name)))
return 1;
/* For single argument case simply replace the name. */
if (info->min_args == info->max_args && info->min_args == 1)
{ {
vkd3d_free(entry->name);
entry->name = hlsl_strdup(ctx, info->components[0].name);
return 1;
}
if (!vkd3d_array_reserve((void **)&block->entries, &block->capacity, block->count + entry->args_count - 1,
sizeof(*block->entries)))
return 1;
if (entry_index != block->count - 1)
{
memmove(&block->entries[entry_index + entry->args_count], &block->entries[entry_index + 1],
(entry->args_count - 1) * sizeof(*block->entries));
}
block->count += entry->args_count - 1;
get_state_block_function_components(info, components, entry->args_count);
for (i = 0; i < entry->args_count; ++i)
{
const struct function_component *comp = &components[i];
unsigned int arg_index = (i + 1) % entry->args_count;
block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, comp->name,
comp->lhs_has_index, comp->lhs_index, arg_index);
}
hlsl_free_state_block_entry(entry);
return entry->args_count - 1;
}
static void write_fx_4_state_block(struct hlsl_ir_var *var, unsigned int block_index,
uint32_t count_offset, struct fx_write_context *fx)
{
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
struct hlsl_state_block *block; struct hlsl_state_block *block;
uint32_t i, count = 0;
count_offset = put_u32(buffer, 0);
count = 0;
if (var->state_blocks) if (var->state_blocks)
{ {
block = var->state_blocks[i]; block = var->state_blocks[block_index];
for (j = 0; j < block->count; ++j) for (i = 0; i < block->count;)
{ {
struct hlsl_state_block_entry *entry = block->entries[j]; i += decompose_fx_4_state_block(var, block, i, fx);
}
for (i = 0; i < block->count; ++i)
{
struct hlsl_state_block_entry *entry = block->entries[i];
/* Skip if property is reassigned later. This will use the last assignment. */ /* Skip if property is reassigned later. This will use the last assignment. */
if (state_block_contains_state(entry->name, j + 1, block)) if (state_block_contains_state(entry->name, i + 1, block))
continue; continue;
/* Resolve special constant names and property names. */ /* Resolve special constant names and property names. */
@ -1710,6 +1864,19 @@ static void write_fx_4_state_object_initializer(struct hlsl_ir_var *var, struct
} }
set_u32(buffer, count_offset, count); set_u32(buffer, count_offset, count);
}
static void write_fx_4_state_object_initializer(struct hlsl_ir_var *var, struct fx_write_context *fx)
{
uint32_t elements_count = hlsl_get_multiarray_size(var->data_type), i;
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
uint32_t count_offset;
for (i = 0; i < elements_count; ++i)
{
count_offset = put_u32(buffer, 0);
write_fx_4_state_block(var, i, count_offset, fx);
} }
} }

View File

@ -134,7 +134,7 @@ struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name)
return hlsl_get_var(scope->upper, name); return hlsl_get_var(scope->upper, name);
} }
static void free_state_block_entry(struct hlsl_state_block_entry *entry) void hlsl_free_state_block_entry(struct hlsl_state_block_entry *entry)
{ {
unsigned int i; unsigned int i;
@ -153,7 +153,7 @@ void hlsl_free_state_block(struct hlsl_state_block *state_block)
VKD3D_ASSERT(state_block); VKD3D_ASSERT(state_block);
for (k = 0; k < state_block->count; ++k) for (k = 0; k < state_block->count; ++k)
free_state_block_entry(state_block->entries[k]); hlsl_free_state_block_entry(state_block->entries[k]);
vkd3d_free(state_block->entries); vkd3d_free(state_block->entries);
vkd3d_free(state_block); vkd3d_free(state_block);
} }
@ -2081,6 +2081,43 @@ static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx,
return hlsl_new_stateblock_constant(ctx, constant->name, &constant->node.loc); return hlsl_new_stateblock_constant(ctx, constant->name, &constant->node.loc);
} }
struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx,
struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index,
unsigned int lhs_index, unsigned int arg_index)
{
struct hlsl_state_block_entry *entry;
struct clone_instr_map map = { 0 };
if (!(entry = hlsl_alloc(ctx, sizeof(*entry))))
return NULL;
entry->name = hlsl_strdup(ctx, name);
entry->lhs_has_index = lhs_has_index;
entry->lhs_index = lhs_index;
if (!(entry->instrs = hlsl_alloc(ctx, sizeof(*entry->instrs))))
{
hlsl_free_state_block_entry(entry);
return NULL;
}
entry->args_count = 1;
if (!(entry->args = hlsl_alloc(ctx, sizeof(*entry->args) * entry->args_count)))
{
hlsl_free_state_block_entry(entry);
return NULL;
}
hlsl_block_init(entry->instrs);
if (!clone_block(ctx, entry->instrs, src->instrs, &map))
{
hlsl_free_state_block_entry(entry);
return NULL;
}
clone_src(&map, entry->args, &src->args[arg_index]);
vkd3d_free(map.instrs);
return entry;
}
void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c) void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c)
{ {
hlsl_block_cleanup(&c->body); hlsl_block_cleanup(&c->body);

View File

@ -1308,6 +1308,9 @@ void hlsl_dump_var_default_values(const struct hlsl_ir_var *var);
bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry, bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry,
const struct vkd3d_shader_location *loc); const struct vkd3d_shader_location *loc);
struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx,
struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index,
unsigned int lhs_index, unsigned int arg_index);
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,
@ -1331,6 +1334,7 @@ void hlsl_free_attribute(struct hlsl_attribute *attr);
void hlsl_free_instr(struct hlsl_ir_node *node); void hlsl_free_instr(struct hlsl_ir_node *node);
void hlsl_free_instr_list(struct list *list); void hlsl_free_instr_list(struct list *list);
void hlsl_free_state_block(struct hlsl_state_block *state_block); void hlsl_free_state_block(struct hlsl_state_block *state_block);
void hlsl_free_state_block_entry(struct hlsl_state_block_entry *state_block_entry);
void hlsl_free_type(struct hlsl_type *type); void hlsl_free_type(struct hlsl_type *type);
void hlsl_free_var(struct hlsl_ir_var *decl); void hlsl_free_var(struct hlsl_ir_var *decl);

View File

@ -0,0 +1,14 @@
[require]
shader model >= 5.0
shader model < 6.0
[effect]
DepthStencilState ds;
technique11
{
pass
{
SetDepthStencilState(ds, 123);
}
}