Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/private/vkd3d_common.h | 14 +++ include/vkd3d_d3dcommon.idl | 37 ++++++ libs/vkd3d-shader/hlsl.h | 6 + libs/vkd3d-shader/hlsl_codegen.c | 59 ++++++--- libs/vkd3d-shader/hlsl_sm4.c | 200 ++++++++++++++++++++++++++++++- 5 files changed, 300 insertions(+), 16 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 46a39b4d..18cc3cab 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -170,6 +170,20 @@ static inline int ascii_tolower(int c) return ascii_isupper(c) ? c - 'A' + 'a' : c; }
+static inline int ascii_strncasecmp(const char *a, const char *b, size_t n) +{ + int c_a, c_b; + + while (n--) + { + c_a = ascii_tolower(*a++); + c_b = ascii_tolower(*b++); + if (c_a != c_b || !c_a) + return c_a - c_b; + } + return 0; +} + static inline int ascii_strcasecmp(const char *a, const char *b) { int c_a, c_b; diff --git a/include/vkd3d_d3dcommon.idl b/include/vkd3d_d3dcommon.idl index ed6f2705..4859d145 100644 --- a/include/vkd3d_d3dcommon.idl +++ b/include/vkd3d_d3dcommon.idl @@ -88,6 +88,43 @@ typedef enum D3D_CBUFFER_TYPE D3D_CT_RESOURCE_BIND_INFO, } D3D_CBUFFER_TYPE;
+typedef enum D3D_NAME +{ + D3D_NAME_UNDEFINED, + D3D_NAME_POSITION, + D3D_NAME_CLIP_DISTANCE, + D3D_NAME_CULL_DISTANCE, + D3D_NAME_RENDER_TARGET_ARRAY_INDEX, + D3D_NAME_VIEWPORT_ARRAY_INDEX, + D3D_NAME_VERTEX_ID, + D3D_NAME_PRIMITIVE_ID, + D3D_NAME_INSTANCE_ID, + D3D_NAME_IS_FRONT_FACE, + D3D_NAME_SAMPLE_INDEX, + D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR, + D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR, + D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR, + D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR, + D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR, + D3D_NAME_FINAL_LINE_DENSITY_TESSFACTOR, + D3D_NAME_BARYCENTRICS = 23, + D3D_NAME_SHADINGRATE, + D3D_NAME_CULLPRIMITIVE, + D3D_NAME_TARGET = 64, + D3D_NAME_DEPTH, + D3D_NAME_COVERAGE, + D3D_NAME_DEPTH_GREATER_EQUAL, + D3D_NAME_DEPTH_LESS_EQUAL, +} D3D_NAME; + +typedef enum D3D_REGISTER_COMPONENT_TYPE +{ + D3D_REGISTER_COMPONENT_UNKNOWN, + D3D_REGISTER_COMPONENT_UINT32, + D3D_REGISTER_COMPONENT_SINT32, + D3D_REGISTER_COMPONENT_FLOAT32, +} D3D_REGISTER_COMPONENT_TYPE; + typedef enum _D3D_SHADER_INPUT_FLAGS { D3D_SIF_USERPACKED = 0x01, diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 41c16b07..9860ed7a 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -22,7 +22,9 @@
#include "vkd3d_shader_private.h" #include "rbtree.h" +#include "vkd3d_d3dcommon.h" #include "vkd3d_d3dx9shader.h" +#include "sm4.h"
/* The general IR structure is inspired by Mesa GLSL hir, even though the code * ends up being quite different in practice. Anyway, here comes the relevant @@ -683,6 +685,10 @@ bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem bool hlsl_sm1_usage_from_semantic(const struct hlsl_semantic *semantic, D3DDECLUSAGE *usage, uint32_t *usage_idx); int hlsl_sm1_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out);
+bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, + const struct hlsl_semantic *semantic, bool output, D3D_NAME *usage); +bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, + bool output, enum vkd3d_sm4_register_type *type, uint32_t *reg); int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out);
int hlsl_lexer_compile(struct hlsl_ctx *ctx, const struct vkd3d_shader_code *hlsl); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index b5f7832f..939b356c 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1012,13 +1012,26 @@ static void allocate_temp_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functio
static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, unsigned int *counter, bool output) { + static const char *shader_names[] = + { + [VKD3D_SHADER_TYPE_PIXEL] = "Pixel", + [VKD3D_SHADER_TYPE_VERTEX] = "Vertex", + [VKD3D_SHADER_TYPE_GEOMETRY] = "Geometry", + [VKD3D_SHADER_TYPE_HULL] = "Hull", + [VKD3D_SHADER_TYPE_DOMAIN] = "Domain", + [VKD3D_SHADER_TYPE_COMPUTE] = "Compute", + }; + + unsigned int type; + uint32_t reg; + bool builtin; + assert(var->semantic.name);
if (ctx->profile->major_version < 4) { - D3DSHADER_PARAM_REGISTER_TYPE type; - uint32_t reg, usage_idx; D3DDECLUSAGE usage; + uint32_t usage_idx;
if (!hlsl_sm1_usage_from_semantic(&var->semantic, &usage, &usage_idx)) { @@ -1027,19 +1040,35 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var return; }
- if (hlsl_sm1_register_from_semantic(ctx, &var->semantic, output, &type, ®)) - { - TRACE("%s %s semantic %s[%u] matches predefined register %#x[%u].\n", - ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL ? "Pixel" : "Vertex", output ? "output" : "input", - var->semantic.name, var->semantic.index, type, reg); - } - else + if ((!output && !var->last_read) || (output && !var->first_write)) + return; + + builtin = hlsl_sm1_register_from_semantic(ctx, &var->semantic, output, &type, ®); + } + else + { + D3D_NAME usage; + + if (!hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage)) { - var->reg.allocated = true; - var->reg.id = (*counter)++; - var->reg.writemask = (1 << var->data_type->dimx) - 1; - TRACE("Allocated %s to %s.\n", var->name, debug_register(output ? 'o' : 'v', var->reg, var->data_type)); + hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Invalid semantic '%s'.", var->semantic.name); + return; } + builtin = hlsl_sm4_register_from_semantic(ctx, &var->semantic, output, &type, ®); + } + + if (builtin) + { + TRACE("%s %s semantic %s[%u] matches predefined register %#x[%u].\n", shader_names[ctx->profile->type], + output ? "output" : "input", var->semantic.name, var->semantic.index, type, reg); + } + else + { + var->reg.allocated = true; + var->reg.id = (*counter)++; + var->reg.writemask = (1 << var->data_type->dimx) - 1; + TRACE("Allocated %s to %s.\n", var->name, debug_register(output ? 'o' : 'v', var->reg, var->data_type)); } }
@@ -1050,9 +1079,9 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_input_semantic && var->last_read) + if (var->is_input_semantic) allocate_semantic_register(ctx, var, &input_counter, false); - if (var->is_output_semantic && var->first_write) + if (var->is_output_semantic) allocate_semantic_register(ctx, var, &output_counter, true); } } diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index 38c71626..894c513f 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -23,6 +23,201 @@ #include "vkd3d_d3dcommon.h" #include "sm4.h"
+bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, + bool output, enum vkd3d_sm4_register_type *type, uint32_t *reg) +{ + unsigned int i; + + static const struct + { + const char *semantic; + bool output; + enum vkd3d_shader_type shader_type; + enum vkd3d_sm4_register_type type; + bool has_idx; + } + register_table[] = + { + {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SM4_RT_PRIMID, false}, + + /* Put sv_target in this table, instead of letting it fall through to + * default varying allocation, so that the register index matches the + * usage index. */ + {"color", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_OUTPUT, true}, + {"depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_DEPTHOUT, false}, + {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_DEPTHOUT, false}, + {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_OUTPUT, true}, + }; + + for (i = 0; i < ARRAY_SIZE(register_table); ++i) + { + if (!ascii_strcasecmp(semantic->name, register_table[i].semantic) + && output == register_table[i].output + && ctx->profile->type == register_table[i].shader_type) + { + *type = register_table[i].type; + *reg = register_table[i].has_idx ? semantic->index : ~0u; + return true; + } + } + + return false; +} + +bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, + bool output, D3D_NAME *usage) +{ + unsigned int i; + + static const struct + { + const char *name; + bool output; + enum vkd3d_shader_type shader_type; + D3DDECLUSAGE usage; + } + semantics[] = + { + {"position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, + {"sv_position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, + {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, + + {"position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, + {"sv_position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, + {"sv_primitiveid", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, + + {"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, + {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, + + {"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, + {"depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, + {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, + {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, + + {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_UNDEFINED}, + + {"position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, + {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, + }; + + for (i = 0; i < ARRAY_SIZE(semantics); ++i) + { + if (!ascii_strcasecmp(semantic->name, semantics[i].name) + && output == semantics[i].output + && ctx->profile->type == semantics[i].shader_type + && !ascii_strncasecmp(semantic->name, "sv_", 3)) + { + *usage = semantics[i].usage; + return true; + } + } + + if (!ascii_strncasecmp(semantic->name, "sv_", 3)) + return false; + + *usage = D3D_NAME_UNDEFINED; + return true; +} + +static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, bool output) +{ + struct vkd3d_bytecode_buffer buffer = {0}; + struct vkd3d_string_buffer *string; + const struct hlsl_ir_var *var; + size_t count_position; + unsigned int i; + bool ret; + + count_position = put_u32(&buffer, 0); + put_u32(&buffer, 8); /* unknown */ + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + unsigned int width = (1u << var->data_type->dimx) - 1, use_mask; + enum vkd3d_sm4_register_type type; + uint32_t usage_idx, reg_idx; + D3D_NAME usage; + + if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) + continue; + + ret = hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); + assert(ret); + usage_idx = var->semantic.index; + + if (!hlsl_sm4_register_from_semantic(ctx, &var->semantic, output, &type, ®_idx)) + { + assert(var->reg.allocated); + type = VKD3D_SM4_RT_INPUT; + reg_idx = var->reg.id; + } + + use_mask = width; /* FIXME: accurately report use mask */ + if (output) + use_mask = 0xf ^ use_mask; + + /* Special pixel shader semantics (TARGET, DEPTH, COVERAGE). */ + if (usage >= 64) + usage = 0; + + put_u32(&buffer, 0); /* name */ + put_u32(&buffer, usage_idx); + put_u32(&buffer, usage); + switch (var->data_type->base_type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: + put_u32(&buffer, D3D_REGISTER_COMPONENT_FLOAT32); + break; + + case HLSL_TYPE_INT: + put_u32(&buffer, D3D_REGISTER_COMPONENT_SINT32); + break; + + case HLSL_TYPE_BOOL: + case HLSL_TYPE_UINT: + put_u32(&buffer, D3D_REGISTER_COMPONENT_UINT32); + break; + + default: + if ((string = hlsl_type_to_string(ctx, var->data_type))) + hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Invalid data type %s for semantic variable %s.", string->buffer, var->name); + hlsl_release_string_buffer(ctx, string); + put_u32(&buffer, D3D_REGISTER_COMPONENT_UNKNOWN); + } + put_u32(&buffer, reg_idx); + put_u32(&buffer, vkd3d_make_u16(width, use_mask)); + } + + i = 0; + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + const char *semantic = var->semantic.name; + size_t string_offset; + D3D_NAME usage; + + if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) + continue; + + hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); + + if (usage == D3D_NAME_TARGET && !ascii_strcasecmp(semantic, "color")) + string_offset = put_string(&buffer, "SV_Target"); + else if (usage == D3D_NAME_DEPTH && !ascii_strcasecmp(semantic, "depth")) + string_offset = put_string(&buffer, "SV_Depth"); + else if (usage == D3D_NAME_POSITION && !ascii_strcasecmp(semantic, "position")) + string_offset = put_string(&buffer, "SV_Position"); + else + string_offset = put_string(&buffer, semantic); + set_u32(&buffer, (2 + i++ * 6) * sizeof(uint32_t), string_offset); + } + + set_u32(&buffer, count_position, i); + + dxbc_writer_add_section(dxbc, output ? TAG_OSGN : TAG_ISGN, buffer.data, buffer.size); +} + static const struct hlsl_type *get_array_type(const struct hlsl_type *type) { if (type->type == HLSL_CLASS_ARRAY) @@ -386,10 +581,13 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun
dxbc_writer_init(&dxbc);
+ write_sm4_signature(ctx, &dxbc, false); + write_sm4_signature(ctx, &dxbc, true); write_sm4_rdef(ctx, &dxbc); write_sm4_shdr(ctx, &dxbc);
- ret = dxbc_writer_write(&dxbc, out); + if (!(ret = ctx->result)) + ret = dxbc_writer_write(&dxbc, out); for (i = 0; i < dxbc.section_count; ++i) vkd3d_free((void *)dxbc.sections[i].data); return ret;