vkd3d-shader/hlsl: Support input primitive arrays in geometry shaders.

This commit is contained in:
Shaun Ren
2025-03-13 14:31:28 -04:00
committed by Henri Verbeet
parent 2377db33db
commit 8af3173955
Notes: Henri Verbeet 2025-03-18 16:04:44 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Elizabeth Figura (@zfigura)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1431
4 changed files with 70 additions and 74 deletions

View File

@ -271,9 +271,9 @@ static bool types_are_semantic_equivalent(struct hlsl_ctx *ctx, const struct hls
if (ctx->profile->major_version < 4)
return true;
if (hlsl_type_is_patch_array(type1))
if (hlsl_type_is_primitive_array(type1))
{
return hlsl_type_is_patch_array(type2)
return hlsl_type_is_primitive_array(type2)
&& type1->e.array.array_type == type2->e.array.array_type
&& type1->e.array.elements_count == type2->e.array.elements_count
&& types_are_semantic_equivalent(ctx, type1->e.array.type, type2->e.array.type);
@ -295,8 +295,8 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
const char *prefix;
char *new_name;
if (hlsl_type_is_patch_array(type))
prefix = type->e.array.array_type == HLSL_ARRAY_PATCH_INPUT ? "inputpatch" : "outputpatch";
if (hlsl_type_is_primitive_array(type))
prefix = type->e.array.array_type == HLSL_ARRAY_PATCH_OUTPUT ? "outputpatch" : "inputprim";
else
prefix = output ? "output" : "input";
@ -307,9 +307,9 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
{
if (!ascii_strcasecmp(ext_var->name, new_name))
{
VKD3D_ASSERT(hlsl_type_is_patch_array(ext_var->data_type)
VKD3D_ASSERT(hlsl_type_is_primitive_array(ext_var->data_type)
|| ext_var->data_type->class <= HLSL_CLASS_VECTOR);
VKD3D_ASSERT(hlsl_type_is_patch_array(type) || type->class <= HLSL_CLASS_VECTOR);
VKD3D_ASSERT(hlsl_type_is_primitive_array(type) || type->class <= HLSL_CLASS_VECTOR);
if (output)
{
@ -383,7 +383,7 @@ static uint32_t combine_field_storage_modifiers(uint32_t modifiers, uint32_t fie
}
static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
struct hlsl_block *block, struct hlsl_ir_var *top_var, uint32_t patch_index, struct hlsl_ir_load *lhs,
struct hlsl_block *block, uint32_t prim_index, struct hlsl_ir_load *lhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index, bool force_align)
{
struct hlsl_type *type = lhs->node.data_type, *vector_type_src, *vector_type_dst;
@ -417,25 +417,25 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_dec
struct hlsl_ir_var *input;
struct hlsl_ir_load *load;
if (hlsl_type_is_patch_array(top_var->data_type))
if (hlsl_type_is_primitive_array(var->data_type))
{
struct hlsl_type *top_type = top_var->data_type;
struct hlsl_type *patch_type;
struct hlsl_deref patch_deref;
struct hlsl_type *prim_type_src;
struct hlsl_deref prim_deref;
struct hlsl_ir_node *idx;
if (!(patch_type = hlsl_new_array_type(ctx, vector_type_src, top_type->e.array.elements_count,
top_type->e.array.array_type)))
if (!(prim_type_src = hlsl_new_array_type(ctx, vector_type_src, var->data_type->e.array.elements_count,
var->data_type->e.array.array_type)))
return;
prim_type_src->modifiers = var->data_type->modifiers & HLSL_PRIMITIVE_MODIFIERS_MASK;
if (!(input = add_semantic_var(ctx, func, var, patch_type,
if (!(input = add_semantic_var(ctx, func, var, prim_type_src,
modifiers, semantic, semantic_index + i, false, force_align, loc)))
return;
hlsl_init_simple_deref_from_var(&patch_deref, input);
hlsl_init_simple_deref_from_var(&prim_deref, input);
idx = hlsl_block_add_uint_constant(ctx, block, patch_index, &var->loc);
idx = hlsl_block_add_uint_constant(ctx, block, prim_index, &var->loc);
if (!(load = hlsl_new_load_index(ctx, &patch_deref, idx, loc)))
if (!(load = hlsl_new_load_index(ctx, &prim_deref, idx, loc)))
return;
hlsl_block_add_instr(block, &load->node);
}
@ -468,7 +468,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_dec
}
static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
struct hlsl_block *block, struct hlsl_ir_var *top_var, uint32_t patch_index, struct hlsl_ir_load *lhs,
struct hlsl_block *block, uint32_t prim_index, struct hlsl_ir_load *lhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index, bool force_align)
{
struct vkd3d_shader_location *loc = &lhs->node.loc;
@ -494,8 +494,8 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_ir_func
element_modifiers = modifiers;
force_align = true;
if (hlsl_type_is_patch_array(type))
patch_index = i;
if (hlsl_type_is_primitive_array(type))
prim_index = i;
}
else
{
@ -520,13 +520,13 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_ir_func
return;
hlsl_block_add_instr(block, &element_load->node);
prepend_input_copy_recurse(ctx, func, block, top_var, patch_index, element_load,
prepend_input_copy_recurse(ctx, func, block, prim_index, element_load,
element_modifiers, semantic, elem_semantic_index, force_align);
}
}
else
{
prepend_input_copy(ctx, func, block, var, patch_index, lhs, modifiers, semantic, semantic_index, force_align);
prepend_input_copy(ctx, func, block, prim_index, lhs, modifiers, semantic, semantic_index, force_align);
}
}
@ -544,8 +544,8 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function
return;
hlsl_block_add_instr(&block, &load->node);
prepend_input_copy_recurse(ctx, func, &block, var, 0, load,
var->storage_modifiers, &var->semantic, var->semantic.index, false);
prepend_input_copy_recurse(ctx, func, &block, 0, load, var->storage_modifiers,
&var->semantic, var->semantic.index, false);
list_move_head(&func->body.instrs, &block.instrs);
}
@ -5754,7 +5754,7 @@ static enum vkd3d_shader_interpolation_mode sm4_get_interpolation_mode(struct hl
{HLSL_STORAGE_CENTROID | HLSL_STORAGE_LINEAR, VKD3DSIM_LINEAR_CENTROID},
};
if (hlsl_type_is_patch_array(type))
if (hlsl_type_is_primitive_array(type))
type = type->e.array.type;
VKD3D_ASSERT(hlsl_is_numeric_type(type));
@ -5785,7 +5785,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
[VKD3D_SHADER_TYPE_COMPUTE] = "Compute",
};
bool is_patch = hlsl_type_is_patch_array(var->data_type);
bool is_primitive = hlsl_type_is_primitive_array(var->data_type);
enum vkd3d_shader_register_type type;
struct vkd3d_shader_version version;
bool special_interpolation = false;
@ -5826,7 +5826,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
bool has_idx;
if (!sm4_sysval_semantic_from_semantic_name(&semantic, &version, ctx->semantic_compat_mapping, ctx->domain,
var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_patch))
var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_primitive))
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC,
"Invalid semantic '%s'.", var->semantic.name);
@ -5859,7 +5859,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
}
else
{
unsigned int component_count = is_patch
unsigned int component_count = is_primitive
? var->data_type->e.array.type->e.numeric.dimx : var->data_type->e.numeric.dimx;
int mode = (ctx->profile->major_version < 4)
? 0 : sm4_get_interpolation_mode(var->data_type, var->storage_modifiers);
@ -5878,7 +5878,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
static void allocate_semantic_registers(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func)
{
struct register_allocator in_patch_allocator = {0}, patch_constant_out_patch_allocator = {0};
struct register_allocator in_prim_allocator = {0}, patch_constant_out_patch_allocator = {0};
struct register_allocator input_allocator = {0}, output_allocator = {0};
bool is_vertex_shader = ctx->profile->type == VKD3D_SHADER_TYPE_VERTEX;
bool is_pixel_shader = ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL;
@ -5891,7 +5891,7 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx, struct hlsl_ir_fun
{
if (var->is_input_semantic)
{
if (hlsl_type_is_patch_array(var->data_type))
if (hlsl_type_is_primitive_array(var->data_type))
{
bool is_patch_constant_output_patch = ctx->is_patch_constant_func &&
var->data_type->e.array.array_type == HLSL_ARRAY_PATCH_OUTPUT;
@ -5900,7 +5900,7 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx, struct hlsl_ir_fun
allocate_semantic_register(ctx, var, &patch_constant_out_patch_allocator, false,
!is_vertex_shader);
else
allocate_semantic_register(ctx, var, &in_patch_allocator, false,
allocate_semantic_register(ctx, var, &in_prim_allocator, false,
!is_vertex_shader);
}
else
@ -6426,7 +6426,7 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref
*offset = deref->const_offset;
if (hlsl_type_is_patch_array(deref->var->data_type))
if (hlsl_type_is_primitive_array(deref->var->data_type))
return false;
if (offset_node)
@ -6472,7 +6472,7 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere
VKD3D_ASSERT(deref->data_type);
VKD3D_ASSERT(hlsl_is_numeric_type(deref->data_type));
if (!hlsl_type_is_patch_array(deref->var->data_type))
if (!hlsl_type_is_primitive_array(deref->var->data_type))
offset = hlsl_offset_from_deref_safe(ctx, deref);
ret.index += offset / 4;
@ -7122,8 +7122,8 @@ static void generate_vsir_signature_entry(struct hlsl_ctx *ctx, struct vsir_prog
struct shader_signature *signature, bool output, struct hlsl_ir_var *var)
{
enum vkd3d_shader_component_type component_type = VKD3D_SHADER_COMPONENT_VOID;
bool is_primitive = hlsl_type_is_primitive_array(var->data_type);
enum vkd3d_shader_sysval_semantic sysval = VKD3D_SHADER_SV_NONE;
bool is_patch = hlsl_type_is_patch_array(var->data_type);
unsigned int register_index, mask, use_mask;
const char *name = var->semantic.name;
enum vkd3d_shader_register_type type;
@ -7136,7 +7136,7 @@ static void generate_vsir_signature_entry(struct hlsl_ctx *ctx, struct vsir_prog
bool has_idx, ret;
ret = sm4_sysval_semantic_from_semantic_name(&sysval, &program->shader_version, ctx->semantic_compat_mapping,
ctx->domain, var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_patch);
ctx->domain, var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_primitive);
VKD3D_ASSERT(ret);
if (sysval == ~0u)
return;
@ -7497,7 +7497,7 @@ static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx,
static enum vkd3d_shader_register_type sm4_get_semantic_register_type(enum vkd3d_shader_type shader_type,
bool is_patch_constant_func, const struct hlsl_ir_var *var)
{
if (hlsl_type_is_patch_array(var->data_type))
if (hlsl_type_is_primitive_array(var->data_type))
{
VKD3D_ASSERT(var->is_input_semantic);
@ -7748,14 +7748,14 @@ static bool sm4_generate_vsir_reg_from_deref(struct hlsl_ctx *ctx, struct vsir_p
}
else if (var->is_input_semantic)
{
bool is_patch = hlsl_type_is_patch_array(var->data_type);
bool is_primitive = hlsl_type_is_primitive_array(var->data_type);
bool has_idx;
if (sm4_register_from_semantic_name(version, var->semantic.name, false, &reg->type, &has_idx))
{
unsigned int offset = hlsl_offset_from_deref_safe(ctx, deref);
VKD3D_ASSERT(!is_patch);
VKD3D_ASSERT(!is_primitive);
if (has_idx)
{
@ -7777,12 +7777,12 @@ static bool sm4_generate_vsir_reg_from_deref(struct hlsl_ctx *ctx, struct vsir_p
reg->type = sm4_get_semantic_register_type(version->type, ctx->is_patch_constant_func, var);
reg->dimension = VSIR_DIMENSION_VEC4;
reg->idx[is_patch ? 1 : 0].offset = hlsl_reg.id;
reg->idx_count = is_patch ? 2 : 1;
reg->idx[is_primitive ? 1 : 0].offset = hlsl_reg.id;
reg->idx_count = is_primitive ? 2 : 1;
*writemask = hlsl_reg.writemask;
}
if (is_patch)
if (is_primitive)
{
reg->idx[0].offset = deref->const_offset / 4;
if (deref->rel_offset.node)
@ -9110,7 +9110,7 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs
const struct hlsl_ir_var *var, struct hlsl_block *block, const struct vkd3d_shader_location *loc)
{
const struct vkd3d_shader_version *version = &program->shader_version;
const bool is_patch = hlsl_type_is_patch_array(var->data_type);
const bool is_primitive = hlsl_type_is_primitive_array(var->data_type);
const bool output = var->is_output_semantic;
enum vkd3d_shader_sysval_semantic semantic;
struct vkd3d_shader_dst_param *dst_param;
@ -9122,7 +9122,7 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs
bool has_idx;
sm4_sysval_semantic_from_semantic_name(&semantic, version, ctx->semantic_compat_mapping, ctx->domain,
var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_patch);
var->semantic.name, var->semantic.index, output, ctx->is_patch_constant_func, is_primitive);
if (semantic == ~0u)
semantic = VKD3D_SHADER_SV_NONE;
@ -9147,7 +9147,7 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs
default:
if (version->type == VKD3D_SHADER_TYPE_PIXEL)
opcode = VKD3DSIH_DCL_INPUT_PS_SIV;
else if (is_patch)
else if (is_primitive && version->type != VKD3D_SHADER_TYPE_GEOMETRY)
opcode = VKD3DSIH_DCL_INPUT;
else
opcode = VKD3DSIH_DCL_INPUT_SIV;
@ -9188,7 +9188,7 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs
}
else if (opcode == VKD3DSIH_DCL_INPUT || opcode == VKD3DSIH_DCL_INPUT_PS)
{
VKD3D_ASSERT(semantic == VKD3D_SHADER_SV_NONE || is_patch);
VKD3D_ASSERT(semantic == VKD3D_SHADER_SV_NONE || is_primitive);
dst_param = &ins->declaration.dst;
}
else
@ -9199,7 +9199,7 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs
dst_param = &ins->declaration.register_semantic.reg;
}
if (is_patch)
if (is_primitive)
{
VKD3D_ASSERT(has_idx);
vsir_register_init(&dst_param->reg, type, VKD3D_DATA_FLOAT, 2);
@ -11032,7 +11032,7 @@ static void generate_vsir_scan_global_flags(struct hlsl_ctx *ctx,
{
const struct hlsl_type *type = var->data_type;
if (hlsl_type_is_patch_array(type))
if (hlsl_type_is_primitive_array(type))
type = var->data_type->e.array.type;
/* Note that it doesn't matter if the semantic is unused or doesn't
@ -12606,12 +12606,6 @@ static void process_entry_function(struct hlsl_ctx *ctx,
}
validate_and_record_prim_type(ctx, var);
if (profile->type == VKD3D_SHADER_TYPE_GEOMETRY)
{
hlsl_fixme(ctx, &var->loc, "Input primitive parameters in geometry shaders.");
continue;
}
prepend_input_var_copy(ctx, entry_func, var);
}
else if (hlsl_get_stream_output_type(var->data_type))

View File

@ -3071,7 +3071,8 @@ static bool get_insidetessfactor_sysval_semantic(enum vkd3d_shader_sysval_semant
bool sm4_sysval_semantic_from_semantic_name(enum vkd3d_shader_sysval_semantic *sysval_semantic,
const struct vkd3d_shader_version *version, bool semantic_compat_mapping, enum vkd3d_tessellator_domain domain,
const char *semantic_name, unsigned int semantic_idx, bool output, bool is_patch_constant_func, bool is_patch)
const char *semantic_name, unsigned int semantic_idx, bool output,
bool is_patch_constant_func, bool is_primitive)
{
unsigned int i;
@ -3134,7 +3135,7 @@ bool sm4_sysval_semantic_from_semantic_name(enum vkd3d_shader_sysval_semantic *s
};
bool has_sv_prefix = !ascii_strncasecmp(semantic_name, "sv_", 3);
if (is_patch)
if (is_primitive)
{
VKD3D_ASSERT(!output);

View File

@ -1654,7 +1654,8 @@ bool sm4_register_from_semantic_name(const struct vkd3d_shader_version *version,
bool shader_sm4_is_scalar_register(const struct vkd3d_shader_register *reg);
bool sm4_sysval_semantic_from_semantic_name(enum vkd3d_shader_sysval_semantic *sysval_semantic,
const struct vkd3d_shader_version *version, bool semantic_compat_mapping, enum vkd3d_tessellator_domain domain,
const char *semantic_name, unsigned int semantic_idx, bool output, bool is_patch_constant_func, bool is_patch);
const char *semantic_name, unsigned int semantic_idx, bool output,
bool is_patch_constant_func, bool is_primitive);
int d3dbc_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t config_flags,
struct vkd3d_shader_message_context *message_context, struct vsir_program *program);

View File

@ -4,7 +4,7 @@ shader model >= 4.0
shader model < 6.0
geometry-shader
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -15,7 +15,7 @@ void main(point gs_data vin[1])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -26,7 +26,7 @@ void main(line gs_data vin[2])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -37,7 +37,7 @@ void main(triangle gs_data vin[3])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -48,7 +48,7 @@ void main(lineadj gs_data vin[4])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -60,7 +60,7 @@ void main(triangleadj gs_data vin[6])
}
% InputPatch is not supported in SM < 5.
[geometry shader fail(sm<5) todo(sm>=5)]
[geometry shader fail(sm<5)]
struct gs_data
{
float4 pos : SV_POSITION;
@ -85,7 +85,7 @@ void main(point gs_data vin)
% InputPatch types take precedence over geometry primitive modifiers.
% However, the specified primitive modifiers restrict the sizes of the patches for entry point parameters.
[geometry shader fail(sm<5) todo(sm>=5)]
[geometry shader fail(sm<5)]
struct gs_data
{
float4 pos : SV_POSITION;
@ -107,7 +107,7 @@ void main(line InputPatch<gs_data, 3> vin)
{
}
[geometry shader fail(sm<5) todo(sm>=5)]
[geometry shader fail(sm<5)]
struct gs_data
{
float4 pos : SV_POSITION;
@ -170,7 +170,7 @@ void main(gs_data2 data2, line gs_data vin[2])
}
% Multiple input parameters are allowed. They must have the same primitive types and dimensions.
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -191,7 +191,7 @@ void main(line gs_data data[2], line gs_data2 data2[2], line gs_data3 data3[2])
{
}
[geometry shader fail todo]
[geometry shader fail]
struct gs_data
{
float4 pos : SV_POSITION;
@ -212,7 +212,7 @@ void main(line gs_data data[2], triangle gs_data2 data2[3], line gs_data3 data3[
{
}
[geometry shader fail(sm<5) todo(sm>=5)]
[geometry shader fail(sm<5)]
struct gs_data
{
float4 pos : SV_POSITION;
@ -276,7 +276,7 @@ void main(InputPatch<gs_data, 3> data, InputPatch<gs_data2, 3> data2, triangle g
}
% Geometry input parameters can be written to.
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -354,7 +354,7 @@ void main(point gs_data vin[1])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float val : VAL;
@ -365,7 +365,7 @@ void main(point gs_data vin[1])
{
}
[geometry shader todo]
[geometry shader]
struct gs_data
{
float val : VAL;
@ -389,7 +389,7 @@ void main(point gs_data vin[1])
% Any single-element objects that contain a stream output object
% are considered valid stream output objects.
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -411,7 +411,7 @@ void main(inout TriangleStream<gs_data> vout[2], point gs_data vin[1])
{
}
[geometry shader fail(sm<5) todo]
[geometry shader fail(sm<5) todo(sm<5)]
struct gs_data
{
float4 pos : SV_POSITION;
@ -482,7 +482,7 @@ void main(inout TriangleStream<gs_data> vout, point gs_data vin[1])
}
% Output streams must be declared as inout.
[geometry shader todo]
[geometry shader]
struct gs_data
{
float4 pos : SV_POSITION;
@ -528,7 +528,7 @@ void main(out gs_data data, point gs_data vin[1], inout TriangleStream<gs_data>
data.pos = 0;
}
[geometry shader fail todo]
[geometry shader fail]
struct gs_data
{
float4 pos : SV_POSITION;