diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 5d83ce3c8..a6b464748 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -4859,6 +4859,7 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil ctx->input_control_point_count = UINT_MAX; ctx->max_vertex_count = 0; ctx->input_primitive_type = VKD3D_PT_UNDEFINED; + ctx->output_topology_type = VKD3D_PT_UNDEFINED; return true; } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 967433d03..e918c9034 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1213,6 +1213,8 @@ struct hlsl_ctx unsigned int max_vertex_count; /* The input primitive type of a geometry shader. */ enum vkd3d_primitive_type input_primitive_type; + /* The output topology type of a geometry shader. */ + enum vkd3d_primitive_type output_topology_type; /* In some cases we generate opcodes by parsing an HLSL function and then * invoking it. If not NULL, this field is the name of the function that we diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 392dda886..3454e0194 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -7583,6 +7583,64 @@ static void validate_and_record_prim_type(struct hlsl_ctx *ctx, struct hlsl_ir_v ctx->input_primitive_param = var; } +static void validate_and_record_stream_outputs(struct hlsl_ctx *ctx) +{ + static const enum vkd3d_primitive_type prim_types[] = + { + [HLSL_STREAM_OUTPUT_POINT_STREAM] = VKD3D_PT_POINTLIST, + [HLSL_STREAM_OUTPUT_LINE_STREAM] = VKD3D_PT_LINESTRIP, + [HLSL_STREAM_OUTPUT_TRIANGLE_STREAM] = VKD3D_PT_TRIANGLESTRIP, + }; + + bool reported_non_point_multistream = false, reported_nonzero_index = false, reported_invalid_index = false; + enum hlsl_so_object_type so_type; + const struct hlsl_type *type; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->bind_count[HLSL_REGSET_STREAM_OUTPUTS]) + continue; + + type = hlsl_get_stream_output_type(var->data_type); + so_type = type->e.so.so_type; + + VKD3D_ASSERT(so_type < ARRAY_SIZE(prim_types)); + + if (ctx->output_topology_type == VKD3D_PT_UNDEFINED) + { + ctx->output_topology_type = prim_types[so_type]; + } + else + { + if ((so_type != HLSL_STREAM_OUTPUT_POINT_STREAM || ctx->output_topology_type != VKD3D_PT_POINTLIST) + && !reported_non_point_multistream) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Multiple output streams are only allowed with PointStream objects."); + reported_non_point_multistream = true; + } + } + + if (var->regs[HLSL_REGSET_STREAM_OUTPUTS].index && hlsl_version_lt(ctx, 5, 0) && !reported_nonzero_index) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE, + "Multiple output streams are only supported in shader model 5.0 or higher."); + reported_nonzero_index = true; + } + + if (var->regs[HLSL_REGSET_STREAM_OUTPUTS].index >= VKD3D_MAX_STREAM_COUNT && !reported_invalid_index) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SIZE, + "Output stream index %u exceeds the maximum index %u.", + var->regs[HLSL_REGSET_STREAM_OUTPUTS].index, VKD3D_MAX_STREAM_COUNT - 1); + reported_invalid_index = true; + } + } + + /* TODO: check that maxvertexcount * outputdatasize <= 1024. */ +} + static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *body) { struct hlsl_ir_node *instr, *next; @@ -11995,7 +12053,7 @@ static void sm4_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl { program->input_control_point_count = ctx->input_control_point_count; program->input_primitive = ctx->input_primitive_type; - program->output_topology = VKD3D_PT_UNDEFINED; /* TODO: obtain from stream output parameters. */ + program->output_topology = ctx->output_topology_type; program->vertices_out_count = ctx->max_vertex_count; } @@ -13285,8 +13343,6 @@ static void process_entry_function(struct hlsl_ctx *ctx, hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, "Stream output parameter \"%s\" must be declared as \"inout\".", var->name); - /* TODO: check that maxvertexcount * component_count(element_type) <= 1024. */ - prepend_uniform_copy(ctx, body, var); } else @@ -13402,7 +13458,10 @@ static void process_entry_function(struct hlsl_ctx *ctx, sort_synthetic_separated_samplers_first(ctx); if (profile->type == VKD3D_SHADER_TYPE_GEOMETRY) + { allocate_stream_outputs(ctx); + validate_and_record_stream_outputs(ctx); + } if (profile->major_version < 4) {