diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index bda9bc72f5673e6d7e679a2b1081e34a47f53140..f28ca418898a18fd9caf05ec5ad8085530e6d49f 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1566,6 +1566,7 @@ D3DXPARAMETER_CLASS hlsl_sm1_class(const struct hlsl_type *type) case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: break; } @@ -1673,6 +1674,7 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type) case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: break; } diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index cb42551ee8b64e7bc74da6c1aefc4f782dbc4a0b..31156f059ebe3867f57d2b534aab56dd6ad32df7 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -761,6 +761,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co case HLSL_CLASS_PASS: case HLSL_CLASS_TECHNIQUE: case HLSL_CLASS_CONSTANT_BUFFER: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: case HLSL_CLASS_STREAM_OUTPUT: vkd3d_unreachable(); @@ -1291,6 +1292,7 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type case HLSL_CLASS_HULL_SHADER: case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: + case HLSL_CLASS_PATCH: return false; case HLSL_CLASS_EFFECT_GROUP: diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 3be9ba9979b98dc1c8d066922d1ab8506ff64fb8..692e254a142db8fbef54642bb56495deed696d94 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -288,6 +288,7 @@ bool hlsl_type_is_shader(const struct hlsl_type *type) case HLSL_CLASS_CONSTANT_BUFFER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_VOID: case HLSL_CLASS_NULL: return false; @@ -436,6 +437,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: break; } @@ -521,6 +523,7 @@ static bool type_is_single_component(const struct hlsl_type *type) case HLSL_CLASS_STRUCT: case HLSL_CLASS_ARRAY: case HLSL_CLASS_CONSTANT_BUFFER: + case HLSL_CLASS_PATCH: return false; case HLSL_CLASS_EFFECT_GROUP: @@ -682,6 +685,7 @@ unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_ty case HLSL_CLASS_VOID: case HLSL_CLASS_SCALAR: case HLSL_CLASS_CONSTANT_BUFFER: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: case HLSL_CLASS_STREAM_OUTPUT: vkd3d_unreachable(); @@ -876,6 +880,9 @@ struct hlsl_type *hlsl_get_element_type_from_path_index(struct hlsl_ctx *ctx, co return type->e.record.fields[c->value.u[0].u].type; } + case HLSL_CLASS_PATCH: + return type->e.patch.type; + default: vkd3d_unreachable(); } @@ -987,6 +994,25 @@ struct hlsl_type *hlsl_new_cb_type(struct hlsl_ctx *ctx, struct hlsl_type *forma return type; } +struct hlsl_type *hlsl_new_patch_type(struct hlsl_ctx *ctx, enum hlsl_patch_kind kind, + struct hlsl_type *format, unsigned int control_points_count) +{ + struct hlsl_type *type; + + if (!(type = hlsl_alloc(ctx, sizeof(*type)))) + return NULL; + type->modifiers = HLSL_MODIFIER_CONST; + type->class = HLSL_CLASS_PATCH; + type->dimx = format->dimx; + type->dimy = format->dimy; + type->e.patch.kind = kind; + type->e.patch.type = format; + type->e.patch.control_points_count = control_points_count; + hlsl_type_calculate_reg_size(ctx, type); + list_add_tail(&ctx->types, &type->entry); + return type; +} + static const char * get_case_insensitive_typename(const char *name) { static const char *const names[] = @@ -1099,6 +1125,7 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type) case HLSL_CLASS_HULL_SHADER: case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: return 1; @@ -1172,6 +1199,10 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 return t1->e.array.elements_count == t2->e.array.elements_count && hlsl_types_are_equal(t1->e.array.type, t2->e.array.type); + case HLSL_CLASS_PATCH: + return t1->e.patch.control_points_count == t2->e.patch.control_points_count + && hlsl_types_are_equal(t1->e.patch.type, t2->e.patch.type); + case HLSL_CLASS_TECHNIQUE: return t1->e.version == t2->e.version; @@ -1298,6 +1329,17 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, type->e.version = old->e.version; break; + case HLSL_CLASS_PATCH: + if (!(type->e.patch.type = hlsl_type_clone(ctx, old->e.patch.type, default_majority, modifiers))) + { + vkd3d_free((void *)type->name); + vkd3d_free(type); + return NULL; + } + type->e.patch.control_points_count = old->e.patch.control_points_count; + type->e.patch.kind = old->e.patch.kind; + break; + default: break; } @@ -2876,6 +2918,18 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru } return string; + case HLSL_CLASS_PATCH: + if (type->e.patch.kind == HLSL_PATCH_KIND_INPUT) + vkd3d_string_buffer_printf(string, "InputPatch"); + else + vkd3d_string_buffer_printf(string, "OutputPatch"); + if ((inner_string = hlsl_type_to_string(ctx, type->e.patch.type))) + { + vkd3d_string_buffer_printf(string, "<%s, %u>", inner_string->buffer, type->e.patch.control_points_count); + hlsl_release_string_buffer(ctx, inner_string); + } + return string; + case HLSL_CLASS_DEPTH_STENCIL_STATE: case HLSL_CLASS_DEPTH_STENCIL_VIEW: case HLSL_CLASS_EFFECT_GROUP: @@ -4474,6 +4528,7 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil hlsl_block_add_instr(&ctx->static_initializers, ctx->error_instr); ctx->domain = VKD3D_TESSELLATOR_DOMAIN_INVALID; + ctx->input_control_point_count = 1; ctx->output_control_point_count = UINT_MAX; ctx->output_primitive = 0; ctx->partitioning = 0; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 4dbc04139519303ad8111aee661091f9d5be471e..1ff00deceea4712a84a74caeb48e003e1b764b77 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -105,6 +105,7 @@ enum hlsl_type_class HLSL_CLASS_CONSTANT_BUFFER, HLSL_CLASS_BLEND_STATE, HLSL_CLASS_STREAM_OUTPUT, + HLSL_CLASS_PATCH, HLSL_CLASS_VOID, HLSL_CLASS_NULL, HLSL_CLASS_ERROR, @@ -149,6 +150,12 @@ enum hlsl_so_object_type HLSL_STREAM_OUTPUT_TRIANGLE_STREAM, }; +enum hlsl_patch_kind +{ + HLSL_PATCH_KIND_INPUT, + HLSL_PATCH_KIND_OUTPUT, +}; + enum hlsl_regset { HLSL_REGSET_SAMPLERS, @@ -225,6 +232,13 @@ struct hlsl_type /* The type is a rasteriser-ordered view. */ bool rasteriser_ordered; } resource; + /* Additional information if type is HLSL_CLASS_PATCH. */ + struct + { + enum hlsl_patch_kind kind; + struct hlsl_type *type; + unsigned int control_points_count; + } patch; /* Additional field to distinguish object types. Currently used only for technique types. */ unsigned int version; /* Additional information if type is HLSL_CLASS_STREAM_OUTPUT. */ @@ -1133,6 +1147,9 @@ struct hlsl_ctx enum vkd3d_shader_tessellator_partitioning partitioning; struct hlsl_ir_function_decl *patch_constant_func; + unsigned int input_control_point_count; + struct hlsl_type *input_control_point_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 * are currently parsing, "mangled" with an internal prefix to avoid @@ -1590,6 +1607,8 @@ struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_ struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, bool rasteriser_ordered); struct hlsl_type *hlsl_new_cb_type(struct hlsl_ctx *ctx, struct hlsl_type *format); +struct hlsl_type *hlsl_new_patch_type(struct hlsl_ctx *ctx, enum hlsl_patch_kind kind, struct hlsl_type *format, + unsigned int control_points_count); struct hlsl_ir_node *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned int n, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_null_constant(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc); diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l index 31fb30521e97393823b4d565af621e6f804d0e5c..605a9abaa930e4987b4c211647eea3d4942218ff 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -104,6 +104,7 @@ if {return KW_IF; } in {return KW_IN; } inline {return KW_INLINE; } inout {return KW_INOUT; } +InputPatch {return KW_INPUTPATCH; } LineStream {return KW_LINESTREAM; } linear {return KW_LINEAR; } matrix {return KW_MATRIX; } @@ -112,6 +113,7 @@ nointerpolation {return KW_NOINTERPOLATION; } noperspective {return KW_NOPERSPECTIVE; } NULL {return KW_NULL; } out {return KW_OUT; } +OutputPatch {return KW_OUTPUTPATCH; } packoffset {return KW_PACKOFFSET; } pass {return KW_PASS; } PixelShader {return KW_PIXELSHADER; } diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 03a2f38e4e9aa897f2450fbf658de1f785a73baa..ec744a7cafe5eceeaa47c10d202567397e1c6490 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1072,6 +1072,8 @@ static bool add_array_access(struct hlsl_ctx *ctx, struct hlsl_block *block, str { if (expr_type->class == HLSL_CLASS_SCALAR) hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Scalar expressions cannot be array-indexed."); + else if (expr_type->class == HLSL_CLASS_PATCH) + hlsl_fixme(ctx, loc, "Patch array access."); else hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Expression cannot be array-indexed."); return false; @@ -2745,6 +2747,12 @@ static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) "packoffset() is only allowed inside constant buffer declarations."); } + if (type->class == HLSL_CLASS_PATCH && !v->initializer.args_count) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_INITIALIZER, + "Patch variable \"%s\" is missing an initializer.", var->name); + } + if (ctx->cur_scope == ctx->globals) { local = false; @@ -6554,6 +6562,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, enum hlsl_buffer_type buffer_type; enum hlsl_sampler_dim sampler_dim; enum hlsl_so_object_type so_type; + enum hlsl_patch_kind patch_kind; struct hlsl_attribute *attr; struct parse_attribute_list attr_list; struct hlsl_ir_switch_case *switch_case; @@ -6596,6 +6605,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %token KW_IN %token KW_INLINE %token KW_INOUT +%token KW_INPUTPATCH %token KW_LINEAR %token KW_LINESTREAM %token KW_MATRIX @@ -6604,6 +6614,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %token KW_NOPERSPECTIVE %token KW_NULL %token KW_OUT +%token KW_OUTPUTPATCH %token KW_PACKOFFSET %token KW_PASS %token KW_PIXELSHADER @@ -6785,6 +6796,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <reg_reservation> packoffset_reservation %type <sampler_dim> texture_type texture_ms_type uav_type rov_type +%type <patch_kind> patch_type %type <semantic> semantic @@ -7834,6 +7846,16 @@ resource_format: YYABORT; } +patch_type: + KW_INPUTPATCH + { + $$ = HLSL_PATCH_KIND_INPUT; + } + | KW_OUTPUTPATCH + { + $$ = HLSL_PATCH_KIND_OUTPUT; + } + type_no_void: KW_VECTOR '<' type ',' C_INTEGER '>' { @@ -7972,6 +7994,17 @@ type_no_void: { $$ = hlsl_new_stream_output_type(ctx, $1, $3); } + | patch_type '<' type ',' C_INTEGER '>' + { + if ($5 < 1) + { + hlsl_error(ctx, &@5, VKD3D_SHADER_ERROR_HLSL_INVALID_SIZE, + "Control point size %d is not positive.", $5); + YYABORT; + } + + $$ = hlsl_new_patch_type(ctx, $1, $3, $5); + } | KW_RWBYTEADDRESSBUFFER { $$ = hlsl_new_uav_type(ctx, HLSL_SAMPLER_DIM_RAW_BUFFER, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), false); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 1fbf670f0323f33d4a37909c2956336171908bb0..fbfa61d9a04ca6a685793d4c0e9a9faece1c7c04 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -160,9 +160,9 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der type = hlsl_deref_get_type(ctx, deref); - /* Instructions that directly refer to structs or arrays (instead of single-register components) + /* Instructions that directly refer to structs, arrays or patches (instead of single-register components) * are removed later by dce. So it is not a problem to just cleanup their derefs. */ - if (type->class == HLSL_CLASS_STRUCT || type->class == HLSL_CLASS_ARRAY) + if (type->class == HLSL_CLASS_STRUCT || type->class == HLSL_CLASS_ARRAY || type->class == HLSL_CLASS_PATCH) { hlsl_cleanup_deref(deref); return true; @@ -640,6 +640,30 @@ static void append_output_var_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function append_output_copy_recurse(ctx, func, load, var->storage_modifiers, &var->semantic, var->semantic.index, false); } +static void add_patch_vars(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, struct hlsl_ir_var *var) +{ + struct hlsl_type *type = var->data_type; + + VKD3D_ASSERT(type->e.patch.control_points_count > 0); + + if (ctx->input_control_point_count) + { + if (type->e.patch.control_points_count != ctx->input_control_point_count + || !hlsl_types_are_equal(type->e.patch.type, ctx->input_control_point_type)) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Patch type mismatch."); + return; + } + } + else + { + ctx->input_control_point_count = type->e.patch.control_points_count; + ctx->input_control_point_type = type->e.patch.type; + } + + /* TODO: Generate semantic variables from patch definition. */ +} + bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct hlsl_block *block, void *context) { @@ -1680,6 +1704,7 @@ static bool copy_propagation_transform_load(struct hlsl_ctx *ctx, case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: break; @@ -9409,8 +9434,10 @@ static void process_entry_function(struct hlsl_ctx *ctx, const struct hlsl_profile_info *profile = ctx->profile; struct hlsl_block static_initializers, global_uniforms; struct hlsl_block *const body = &entry_func->body; + bool is_patch_constant_func = entry_func == ctx->patch_constant_func; struct recursive_call_ctx recursive_call_ctx; struct hlsl_ir_var *var; + bool found_inputpatch, found_outputpatch; unsigned int i; if (!hlsl_clone_block(ctx, &static_initializers, &ctx->static_initializers)) @@ -9443,6 +9470,7 @@ static void process_entry_function(struct hlsl_ctx *ctx, lower_ir(ctx, lower_matrix_swizzles, body); lower_ir(ctx, lower_index_loads, body); + found_inputpatch = found_outputpatch = false; for (i = 0; i < entry_func->parameters.count; ++i) { var = entry_func->parameters.vars[i]; @@ -9453,12 +9481,65 @@ static void process_entry_function(struct hlsl_ctx *ctx, } else if ((var->storage_modifiers & HLSL_STORAGE_UNIFORM)) { - if (ctx->profile->type == VKD3D_SHADER_TYPE_HULL && entry_func == ctx->patch_constant_func) + if (ctx->profile->type == VKD3D_SHADER_TYPE_HULL && is_patch_constant_func) hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, "Patch constant function parameter \"%s\" cannot be uniform.", var->name); else prepend_uniform_copy(ctx, body, var); } + else if (hlsl_get_multiarray_element_type(var->data_type)->class == HLSL_CLASS_PATCH) + { + if (var->data_type->e.patch.kind == HLSL_PATCH_KIND_INPUT) + { + if (found_inputpatch) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH, + "Duplicate InputPatch parameter."); + continue; + } + found_inputpatch = true; + + if (profile->type != VKD3D_SHADER_TYPE_HULL && profile->type != VKD3D_SHADER_TYPE_GEOMETRY) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "InputPatch parameters are only supported in hull shaders and geometry shaders."); + continue; + } + + if (profile->type == VKD3D_SHADER_TYPE_GEOMETRY) + { + hlsl_fixme(ctx, &var->loc, "InputPatch parameter in geometry shaders."); + continue; + } + + add_patch_vars(ctx, entry_func, var); + } + else /* HLSL_PATCH_KIND_OUTPUT */ + { + if (found_outputpatch) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH, + "Duplicate OutputPatch parameter."); + continue; + } + found_outputpatch = true; + + if (!is_patch_constant_func && profile->type != VKD3D_SHADER_TYPE_DOMAIN) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "OutputPatch parameters are only supported in patch constant functions and domain shaders."); + continue; + } + + if (is_patch_constant_func) + { + hlsl_fixme(ctx, &var->loc, "OutputPatch parameter in patch constant functions."); + continue; + } + + add_patch_vars(ctx, entry_func, var); + } + } else { if (hlsl_get_multiarray_element_type(var->data_type)->class != HLSL_CLASS_STRUCT diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index e1ca5d6f0aca095b4ba4bc8d5edf6047427cd845..d32e65552103612194a7a40b60804b6c0a35436e 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3333,6 +3333,7 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STREAM_OUTPUT: + case HLSL_CLASS_PATCH: case HLSL_CLASS_NULL: break; } @@ -5772,7 +5773,7 @@ static void tpf_write_shdr(struct tpf_compiler *tpf, struct hlsl_ir_function_dec { tpf_write_hs_decls(tpf); - tpf_write_dcl_input_control_point_count(tpf, 1); /* TODO: Obtain from InputPatch */ + tpf_write_dcl_input_control_point_count(tpf, ctx->input_control_point_count); tpf_write_dcl_output_control_point_count(tpf, ctx->output_control_point_count); tpf_write_dcl_tessellator_domain(tpf, ctx->domain); tpf_write_dcl_tessellator_partitioning(tpf, ctx->partitioning); @@ -5780,7 +5781,7 @@ static void tpf_write_shdr(struct tpf_compiler *tpf, struct hlsl_ir_function_dec } else if (version->type == VKD3D_SHADER_TYPE_DOMAIN) { - tpf_write_dcl_input_control_point_count(tpf, 0); /* TODO: Obtain from OutputPatch */ + tpf_write_dcl_input_control_point_count(tpf, ctx->input_control_point_count); tpf_write_dcl_tessellator_domain(tpf, ctx->domain); } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b9f2b25c84c93aefea65b31adfed636620af919d..b09cd30566e09bacf0b58201575c6e039cf63438 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -163,6 +163,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE = 5039, + VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH = 5040, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301,