Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 6 +++++- tests/hlsl-duplicate-modifiers.shader_test | 11 +++++++++++ tests/hlsl-invalid.shader_test | 17 +++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/hlsl-duplicate-modifiers.shader_test
diff --git a/Makefile.am b/Makefile.am index e8537864..5b3c4ff0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,7 @@ vkd3d_shader_tests = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ + tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-invalid.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \ @@ -256,6 +257,7 @@ XFAIL_TESTS = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ + tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \ tests/hlsl-nested-arrays.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 828b19a4..513c4512 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -659,9 +659,13 @@ static struct hlsl_type *apply_type_modifiers(struct hlsl_ctx *ctx, struct hlsl_ if (!(new_type = hlsl_type_clone(ctx, type, default_majority))) return NULL;
- new_type->modifiers = add_modifiers(ctx, new_type->modifiers, *modifiers, loc); + new_type->modifiers |= *modifiers; *modifiers &= ~HLSL_TYPE_MODIFIERS_MASK;
+ if ((new_type->modifiers & HLSL_MODIFIER_ROW_MAJOR) && (new_type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, + "'row_major' and 'column_major' modifiers are mutually exclusive."); + if (new_type->type == HLSL_CLASS_MATRIX) new_type->reg_size = (hlsl_type_is_row_major(new_type) ? new_type->dimy : new_type->dimx) * 4; return new_type; diff --git a/tests/hlsl-duplicate-modifiers.shader_test b/tests/hlsl-duplicate-modifiers.shader_test new file mode 100644 index 00000000..6491701a --- /dev/null +++ b/tests/hlsl-duplicate-modifiers.shader_test @@ -0,0 +1,11 @@ +[pixel shader] +typedef const precise row_major float2x2 mat_t; +float4 main() : sv_target +{ + const precise row_major mat_t mat = float2x2(0.1, 0.2, 0.3, 0.4); + return mat; +} + +[test] +draw quad +probe all rgba (0.1, 0.2, 0.3, 0.4) diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index 72055989..f6a7ffd3 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -219,3 +219,20 @@ float4 main(void) : sv_target in float f; return 0; } + +[pixel shader fail] +const const float4 c; + +float4 main() : sv_target +{ + return float4(0, 0, 0, 0); +} + +[pixel shader fail] +typedef row_major float4x4 mat_t; +column_major mat_t m; + +float4 main() : sv_target +{ + return float4(0, 0, 0, 0); +}
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 16 ++++++++++++---- libs/vkd3d-shader/hlsl.h | 3 +-- libs/vkd3d-shader/hlsl.y | 20 +++----------------- tests/hlsl-invalid.shader_test | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 721458eb..72703bc9 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -98,6 +98,13 @@ void hlsl_free_var(struct hlsl_ir_var *decl) vkd3d_free(decl); }
+static bool hlsl_type_is_row_major(const struct hlsl_type *type) +{ + /* Default to column-major if the majority isn't explicitly set, which can + * happen for anonymous nodes. */ + return !!(type->modifiers & HLSL_MODIFIER_ROW_MAJOR); +} + struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hlsl_type_class type_class, enum hlsl_base_type base_type, unsigned dimx, unsigned dimy) { @@ -276,7 +283,8 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 return true; }
-struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, unsigned int default_majority) +struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, + unsigned int default_majority, unsigned int modifiers) { struct hlsl_struct_field *old_field, *field; struct hlsl_type *type; @@ -297,14 +305,14 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, u type->base_type = old->base_type; type->dimx = old->dimx; type->dimy = old->dimy; - type->modifiers = old->modifiers; + type->modifiers = old->modifiers | modifiers; if (!(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK)) type->modifiers |= default_majority; type->sampler_dim = old->sampler_dim; switch (old->type) { case HLSL_CLASS_ARRAY: - type->e.array.type = hlsl_type_clone(ctx, old->e.array.type, default_majority); + type->e.array.type = hlsl_type_clone(ctx, old->e.array.type, default_majority, modifiers); type->e.array.elements_count = old->e.array.elements_count; type->reg_size = type->e.array.elements_count * type->e.array.type->reg_size; break; @@ -336,7 +344,7 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, u return NULL; } field->loc = old_field->loc; - field->type = hlsl_type_clone(ctx, old_field->type, default_majority); + field->type = hlsl_type_clone(ctx, old_field->type, default_majority, modifiers); field->name = hlsl_strdup(ctx, old_field->name); if (old_field->semantic.name) { diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index e2ac0a77..f461a07f 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -676,9 +676,8 @@ void hlsl_pop_scope(struct hlsl_ctx *ctx) DECLSPEC_HIDDEN; bool hlsl_scope_add_type(struct hlsl_scope *scope, struct hlsl_type *type) DECLSPEC_HIDDEN;
struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, - unsigned int default_majority) DECLSPEC_HIDDEN; + unsigned int default_majority, unsigned int modifiers) DECLSPEC_HIDDEN; unsigned int hlsl_type_component_count(struct hlsl_type *type) DECLSPEC_HIDDEN; -bool hlsl_type_is_row_major(const struct hlsl_type *type) DECLSPEC_HIDDEN; bool hlsl_type_is_void(const struct hlsl_type *type) DECLSPEC_HIDDEN; bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2) DECLSPEC_HIDDEN;
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 513c4512..34cdb543 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -624,13 +624,6 @@ static struct hlsl_struct_field *get_struct_field(struct list *fields, const cha return NULL; }
-bool hlsl_type_is_row_major(const struct hlsl_type *type) -{ - /* Default to column-major if the majority isn't explicitly set, which can - * happen for anonymous nodes. */ - return !!(type->modifiers & HLSL_MODIFIER_ROW_MAJOR); -} - static struct hlsl_type *apply_type_modifiers(struct hlsl_ctx *ctx, struct hlsl_type *type, unsigned int *modifiers, struct vkd3d_shader_location loc) { @@ -656,18 +649,15 @@ static struct hlsl_type *apply_type_modifiers(struct hlsl_ctx *ctx, struct hlsl_ if (!default_majority && !(*modifiers & HLSL_TYPE_MODIFIERS_MASK)) return type;
- if (!(new_type = hlsl_type_clone(ctx, type, default_majority))) + if (!(new_type = hlsl_type_clone(ctx, type, default_majority, *modifiers & HLSL_TYPE_MODIFIERS_MASK))) return NULL;
- new_type->modifiers |= *modifiers; *modifiers &= ~HLSL_TYPE_MODIFIERS_MASK;
if ((new_type->modifiers & HLSL_MODIFIER_ROW_MAJOR) && (new_type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)) hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, "'row_major' and 'column_major' modifiers are mutually exclusive.");
- if (new_type->type == HLSL_CLASS_MATRIX) - new_type->reg_size = (hlsl_type_is_row_major(new_type) ? new_type->dimy : new_type->dimx) * 4; return new_type; }
@@ -721,7 +711,7 @@ static bool add_typedef(struct hlsl_ctx *ctx, DWORD modifiers, struct hlsl_type { if (!v->arrays.count) { - if (!(type = hlsl_type_clone(ctx, orig_type, 0))) + if (!(type = hlsl_type_clone(ctx, orig_type, 0, modifiers))) return false; } else @@ -737,12 +727,9 @@ static bool add_typedef(struct hlsl_ctx *ctx, DWORD modifiers, struct hlsl_type
vkd3d_free((void *)type->name); type->name = v->name; - type->modifiers |= modifiers;
if (type->type != HLSL_CLASS_MATRIX) check_invalid_matrix_modifiers(ctx, type->modifiers, v->loc); - else - type->reg_size = (hlsl_type_is_row_major(type) ? type->dimy : type->dimx) * 4;
if ((type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR) && (type->modifiers & HLSL_MODIFIER_ROW_MAJOR)) @@ -1294,9 +1281,8 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem list_add_tail(instrs, ©->node.entry);
/* Post increment/decrement expressions are considered const. */ - if (!(copy->node.data_type = hlsl_type_clone(ctx, copy->node.data_type, 0))) + if (!(copy->node.data_type = hlsl_type_clone(ctx, copy->node.data_type, 0, HLSL_MODIFIER_CONST))) return false; - copy->node.data_type->modifiers |= HLSL_MODIFIER_CONST; }
return true; diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index f6a7ffd3..a7364b1e 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -236,3 +236,17 @@ float4 main() : sv_target { return float4(0, 0, 0, 0); } + +[pixel shader fail] +typedef struct apple +{ + float a; +} apple_t; + +uniform const apple_t a; + +float4 main() : sv_target +{ + a.a = 1; + return a.a; +}
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 95 +++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 36 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 72703bc9..e5d08bfd 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -105,6 +105,54 @@ static bool hlsl_type_is_row_major(const struct hlsl_type *type) return !!(type->modifiers & HLSL_MODIFIER_ROW_MAJOR); }
+static unsigned int get_array_size(const struct hlsl_type *type) +{ + if (type->type == HLSL_CLASS_ARRAY) + return get_array_size(type->e.array.type) * type->e.array.elements_count; + return 1; +} + +static void hlsl_type_calculate_reg_size(struct hlsl_type *type) +{ + switch (type->type) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + type->reg_size = 4; + break; + + case HLSL_CLASS_MATRIX: + type->reg_size = 4 * (hlsl_type_is_row_major(type) ? type->dimy : type->dimx); + break; + + case HLSL_CLASS_ARRAY: + assert(type->e.array.type->reg_size); + type->reg_size = type->e.array.elements_count * type->e.array.type->reg_size; + break; + + case HLSL_CLASS_STRUCT: + { + struct hlsl_struct_field *field; + + type->dimx = 0; + type->reg_size = 0; + + LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + { + type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type); + + field->reg_offset = type->reg_size; + assert(field->type->reg_size); + type->reg_size += field->type->reg_size; + } + break; + } + + case HLSL_CLASS_OBJECT: + break; + } +} + struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hlsl_type_class type_class, enum hlsl_base_type base_type, unsigned dimx, unsigned dimy) { @@ -117,10 +165,7 @@ struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hls type->base_type = base_type; type->dimx = dimx; type->dimy = dimy; - if (type_class == HLSL_CLASS_MATRIX) - type->reg_size = (hlsl_type_is_row_major(type) ? dimy : dimx) * 4; - else - type->reg_size = 4; + hlsl_type_calculate_reg_size(type);
list_add_tail(&ctx->types, &type->entry);
@@ -129,31 +174,26 @@ struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hls
struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *basic_type, unsigned int array_size) { - struct hlsl_type *type = hlsl_new_type(ctx, NULL, HLSL_CLASS_ARRAY, HLSL_TYPE_FLOAT, 1, 1); + struct hlsl_type *type;
- if (!type) + if (!(type = hlsl_alloc(ctx, sizeof(*type)))) return NULL;
+ type->type = HLSL_CLASS_ARRAY; type->modifiers = basic_type->modifiers; type->e.array.elements_count = array_size; type->e.array.type = basic_type; - type->reg_size = basic_type->reg_size * array_size; type->dimx = basic_type->dimx; type->dimy = basic_type->dimy; - return type; -} + hlsl_type_calculate_reg_size(type);
-static DWORD get_array_size(const struct hlsl_type *type) -{ - if (type->type == HLSL_CLASS_ARRAY) - return get_array_size(type->e.array.type) * type->e.array.elements_count; - return 1; + list_add_tail(&ctx->types, &type->entry); + + return type; }
struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct list *fields) { - struct hlsl_struct_field *field; - unsigned int reg_size = 0; struct hlsl_type *type;
if (!(type = hlsl_alloc(ctx, sizeof(*type)))) @@ -161,17 +201,9 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, s type->type = HLSL_CLASS_STRUCT; type->base_type = HLSL_TYPE_VOID; type->name = name; - type->dimx = 0; type->dimy = 1; type->e.elements = fields; - - LIST_FOR_EACH_ENTRY(field, fields, struct hlsl_struct_field, entry) - { - field->reg_offset = reg_size; - reg_size += field->type->reg_size; - type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type); - } - type->reg_size = reg_size; + hlsl_type_calculate_reg_size(type);
list_add_tail(&ctx->types, &type->entry);
@@ -314,13 +346,10 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, case HLSL_CLASS_ARRAY: type->e.array.type = hlsl_type_clone(ctx, old->e.array.type, default_majority, modifiers); type->e.array.elements_count = old->e.array.elements_count; - type->reg_size = type->e.array.elements_count * type->e.array.type->reg_size; break;
case HLSL_CLASS_STRUCT: { - unsigned int reg_size = 0; - if (!(type->e.elements = hlsl_alloc(ctx, sizeof(*type->e.elements)))) { vkd3d_free((void *)type->name); @@ -351,23 +380,17 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, field->semantic.name = hlsl_strdup(ctx, old_field->semantic.name); field->semantic.index = old_field->semantic.index; } - field->reg_offset = reg_size; - reg_size += field->type->reg_size; list_add_tail(type->e.elements, &field->entry); } - type->reg_size = reg_size; break; }
- case HLSL_CLASS_MATRIX: - type->reg_size = (hlsl_type_is_row_major(type) ? type->dimy : type->dimx) * 4; - break; - default: - type->reg_size = 4; break; }
+ hlsl_type_calculate_reg_size(type); + list_add_tail(&ctx->types, &type->entry); return type; }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 47 ++++++++++++++++++++++++-------- libs/vkd3d-shader/hlsl_codegen.c | 8 ++++++ 2 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index e5d08bfd..2c09f903 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -112,23 +112,35 @@ static unsigned int get_array_size(const struct hlsl_type *type) return 1; }
-static void hlsl_type_calculate_reg_size(struct hlsl_type *type) +static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type *type) { + bool is_sm4 = (ctx->profile->major_version >= 4); + switch (type->type) { case HLSL_CLASS_SCALAR: case HLSL_CLASS_VECTOR: - type->reg_size = 4; + type->reg_size = is_sm4 ? type->dimx : 4; break;
case HLSL_CLASS_MATRIX: - type->reg_size = 4 * (hlsl_type_is_row_major(type) ? type->dimy : type->dimx); + if (hlsl_type_is_row_major(type)) + type->reg_size = is_sm4 ? (4 * (type->dimy - 1) + type->dimx) : (4 * type->dimy); + else + type->reg_size = is_sm4 ? (4 * (type->dimx - 1) + type->dimy) : (4 * type->dimx); break;
case HLSL_CLASS_ARRAY: - assert(type->e.array.type->reg_size); - type->reg_size = type->e.array.elements_count * type->e.array.type->reg_size; + { + unsigned int element_size = type->e.array.type->reg_size; + + assert(element_size); + if (is_sm4) + type->reg_size = (type->e.array.elements_count - 1) * align(element_size, 4) + element_size; + else + type->reg_size = type->e.array.elements_count * element_size; break; + }
case HLSL_CLASS_STRUCT: { @@ -139,11 +151,22 @@ static void hlsl_type_calculate_reg_size(struct hlsl_type *type)
LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { - type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type); + unsigned int field_size = field->type->reg_size; + + assert(field_size); + + /* Align to the next vec4 boundary if: + * (a) the type is a struct or array type, or + * (b) the type would cross a vec4 boundary; i.e. a vec3 and a + * vec1 can be packed together, but not a vec3 and a vec2. + */ + if (field->type->type > HLSL_CLASS_LAST_NUMERIC || (type->reg_size & 3) + field_size > 4) + type->reg_size = align(type->reg_size, 4);
field->reg_offset = type->reg_size; - assert(field->type->reg_size); - type->reg_size += field->type->reg_size; + type->reg_size += field_size; + + type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type); } break; } @@ -165,7 +188,7 @@ struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hls type->base_type = base_type; type->dimx = dimx; type->dimy = dimy; - hlsl_type_calculate_reg_size(type); + hlsl_type_calculate_reg_size(ctx, type);
list_add_tail(&ctx->types, &type->entry);
@@ -185,7 +208,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba type->e.array.type = basic_type; type->dimx = basic_type->dimx; type->dimy = basic_type->dimy; - hlsl_type_calculate_reg_size(type); + hlsl_type_calculate_reg_size(ctx, type);
list_add_tail(&ctx->types, &type->entry);
@@ -203,7 +226,7 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, s type->name = name; type->dimy = 1; type->e.elements = fields; - hlsl_type_calculate_reg_size(type); + hlsl_type_calculate_reg_size(ctx, type);
list_add_tail(&ctx->types, &type->entry);
@@ -389,7 +412,7 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, break; }
- hlsl_type_calculate_reg_size(type); + hlsl_type_calculate_reg_size(ctx, type);
list_add_tail(&ctx->types, &type->entry); return type; diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 79cae35e..2768f8ac 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -737,9 +737,17 @@ static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct liveness *liv
static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type) { + static const char writemask_offset[] = {'w','x','y','z'}; + if (type->reg_size > 4) + { + if (type->reg_size & 3) + return vkd3d_dbg_sprintf("%c%u-%c%u.%c", class, reg.id, class, + reg.id + (type->reg_size / 4), writemask_offset[type->reg_size & 3]); + return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class, reg.id + (type->reg_size / 4) - 1); + } return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask)); }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 21 +++-- libs/vkd3d-shader/hlsl.h | 5 ++ libs/vkd3d-shader/hlsl_codegen.c | 101 +++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 4 files changed, 121 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 2c09f903..0b8c660c 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -112,6 +112,18 @@ static unsigned int get_array_size(const struct hlsl_type *type) return 1; }
+unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset) +{ + /* Align to the next vec4 boundary if: + * (a) the type is a struct or array type, or + * (b) the type would cross a vec4 boundary; i.e. a vec3 and a + * vec1 can be packed together, but not a vec3 and a vec2. + */ + if (type->type > HLSL_CLASS_LAST_NUMERIC || (offset & 3) + type->reg_size > 4) + return align(offset, 4); + return offset; +} + static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type *type) { bool is_sm4 = (ctx->profile->major_version >= 4); @@ -155,14 +167,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
assert(field_size);
- /* Align to the next vec4 boundary if: - * (a) the type is a struct or array type, or - * (b) the type would cross a vec4 boundary; i.e. a vec3 and a - * vec1 can be packed together, but not a vec3 and a vec2. - */ - if (field->type->type > HLSL_CLASS_LAST_NUMERIC || (type->reg_size & 3) + field_size > 4) - type->reg_size = align(type->reg_size, 4); - + type->reg_size = hlsl_type_get_sm4_offset(field->type, type->reg_size); field->reg_offset = type->reg_size; type->reg_size += field_size;
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index f461a07f..b62e7818 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -228,6 +228,7 @@ struct hlsl_ir_var struct list scope_entry, param_entry, extern_entry;
unsigned int first_write, last_read; + unsigned int buffer_offset; struct hlsl_reg reg;
uint32_t is_input_semantic : 1; @@ -431,6 +432,9 @@ struct hlsl_buffer const char *name; struct hlsl_reg_reservation reservation; struct list entry; + + unsigned size, used_size; + struct hlsl_reg reg; };
struct hlsl_ctx @@ -678,6 +682,7 @@ bool hlsl_scope_add_type(struct hlsl_scope *scope, struct hlsl_type *type) DECLS struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, unsigned int default_majority, unsigned int modifiers) DECLSPEC_HIDDEN; unsigned int hlsl_type_component_count(struct hlsl_type *type) DECLSPEC_HIDDEN; +unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset) DECLSPEC_HIDDEN; bool hlsl_type_is_void(const struct hlsl_type *type) DECLSPEC_HIDDEN; bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2) DECLSPEC_HIDDEN;
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2768f8ac..6336ddfc 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1115,6 +1115,105 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) } }
+static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint32_t index) +{ + const struct hlsl_buffer *buffer; + + LIST_FOR_EACH_ENTRY(buffer, &ctx->buffers, const struct hlsl_buffer, entry) + { + if (buffer->used_size && buffer->reservation.type == 'b' && buffer->reservation.index == index) + return buffer; + } + return NULL; +} + +static void calculate_buffer_offset(struct hlsl_ir_var *var) +{ + struct hlsl_buffer *buffer = var->buffer; + + buffer->size = hlsl_type_get_sm4_offset(var->data_type, buffer->size); + + var->buffer_offset = buffer->size; + TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name); + buffer->size += var->data_type->reg_size; + if (var->last_read) + buffer->used_size = buffer->size; +} + +static void allocate_buffers(struct hlsl_ctx *ctx) +{ + struct hlsl_buffer *buffer, *params_buffer; + struct hlsl_ir_var *var; + uint32_t index = 0; + + if (!(params_buffer = hlsl_new_buffer(ctx, HLSL_BUFFER_CONSTANT, + hlsl_strdup(ctx, "$Params"), NULL, ctx->location))) + return; + + /* The $Globals and $Params buffers should be allocated first, before all + * explicit buffers. */ + list_remove(¶ms_buffer->entry); + list_add_head(&ctx->buffers, ¶ms_buffer->entry); + list_remove(&ctx->globals_buffer->entry); + list_add_head(&ctx->buffers, &ctx->globals_buffer->entry); + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (var->is_uniform) + { + if (var->is_param) + var->buffer = params_buffer; + + calculate_buffer_offset(var); + } + } + + LIST_FOR_EACH_ENTRY(buffer, &ctx->buffers, struct hlsl_buffer, entry) + { + if (!buffer->used_size) + continue; + + if (buffer->type == HLSL_BUFFER_CONSTANT) + { + if (buffer->reservation.type == 'b') + { + const struct hlsl_buffer *reserved_buffer = get_reserved_buffer(ctx, buffer->reservation.index); + + if (reserved_buffer && reserved_buffer != buffer) + { + hlsl_error(ctx, buffer->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, + "Multiple buffers bound to cb%u.", buffer->reservation.index); + hlsl_note(ctx, reserved_buffer->loc, VKD3D_SHADER_LOG_ERROR, + "Buffer %s is already bound to cb%u.", reserved_buffer->name, buffer->reservation.index); + } + + buffer->reg.id = buffer->reservation.index; + buffer->reg.allocated = true; + TRACE("Allocated reserved %s to cb%u.\n", buffer->name, index); + } + else if (!buffer->reservation.type) + { + while (get_reserved_buffer(ctx, index)) + ++index; + + buffer->reg.id = index; + buffer->reg.allocated = true; + TRACE("Allocated %s to cb%u.\n", buffer->name, index); + ++index; + } + else + { + hlsl_error(ctx, buffer->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "Constant buffers must be allocated to register type 'b'."); + } + } + else + { + FIXME("Allocate registers for texture buffers.\n"); + } + } +} + static unsigned int map_swizzle(unsigned int swizzle, unsigned int writemask) { unsigned int i, ret = 0; @@ -2062,6 +2161,8 @@ int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun allocate_temp_registers(ctx, entry_func); if (ctx->profile->major_version < 4) allocate_const_registers(ctx, entry_func); + else + allocate_buffers(ctx); allocate_semantic_registers(ctx);
if (ctx->result) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6d756e40..b2c89c0c 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -107,6 +107,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX = 5012, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC = 5013, VKD3D_SHADER_ERROR_HLSL_INVALID_RETURN = 5014, + VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS = 5015, + VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION = 5016,
VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, };
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Thu, Jun 24, 2021 at 7:15 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.c | 21 +++-- libs/vkd3d-shader/hlsl.h | 5 ++ libs/vkd3d-shader/hlsl_codegen.c | 101 +++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 4 files changed, 121 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2768f8ac..6336ddfc 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1115,6 +1115,105 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) } }
+static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint32_t index) +{
- const struct hlsl_buffer *buffer;
- LIST_FOR_EACH_ENTRY(buffer, &ctx->buffers, const struct hlsl_buffer, entry)
- {
if (buffer->used_size && buffer->reservation.type == 'b' && buffer->reservation.index == index)
return buffer;
- }
- return NULL;
+}
+static void calculate_buffer_offset(struct hlsl_ir_var *var) +{
- struct hlsl_buffer *buffer = var->buffer;
- buffer->size = hlsl_type_get_sm4_offset(var->data_type, buffer->size);
- var->buffer_offset = buffer->size;
- TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name);
- buffer->size += var->data_type->reg_size;
- if (var->last_read)
buffer->used_size = buffer->size;
+}
+static void allocate_buffers(struct hlsl_ctx *ctx) +{
- struct hlsl_buffer *buffer, *params_buffer;
- struct hlsl_ir_var *var;
- uint32_t index = 0;
- if (!(params_buffer = hlsl_new_buffer(ctx, HLSL_BUFFER_CONSTANT,
hlsl_strdup(ctx, "$Params"), NULL, ctx->location)))
return;
- /* The $Globals and $Params buffers should be allocated first, before all
* explicit buffers. */
- list_remove(¶ms_buffer->entry);
- list_add_head(&ctx->buffers, ¶ms_buffer->entry);
- list_remove(&ctx->globals_buffer->entry);
- list_add_head(&ctx->buffers, &ctx->globals_buffer->entry);
I find the split in the creation of $Globals and $Params a tiny bit annoying. Right now $Globals is created in hlsl_ctx_init() (which also means that there should be no need to explicitly put it at the top of the buffers list here AFAIU) while $Params is created right here, after parsing. If the point is just to make sure that $Params is the second buffer in the list, list_add_after() should make it a bit more compact and explicit. In theory you could add an assert() if you want to make sure that $Globals is at the head of the list, although probably it would be even better if both these special buffers were created together, in the same place. Unless I'm missing something?
On 6/28/21 4:40 AM, Matteo Bruni wrote:
On Thu, Jun 24, 2021 at 7:15 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.c | 21 +++-- libs/vkd3d-shader/hlsl.h | 5 ++ libs/vkd3d-shader/hlsl_codegen.c | 101 +++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 4 files changed, 121 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2768f8ac..6336ddfc 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1115,6 +1115,105 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) } }
+static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint32_t index) +{
- const struct hlsl_buffer *buffer;
- LIST_FOR_EACH_ENTRY(buffer, &ctx->buffers, const struct hlsl_buffer, entry)
- {
if (buffer->used_size && buffer->reservation.type == 'b' && buffer->reservation.index == index)
return buffer;
- }
- return NULL;
+}
+static void calculate_buffer_offset(struct hlsl_ir_var *var) +{
- struct hlsl_buffer *buffer = var->buffer;
- buffer->size = hlsl_type_get_sm4_offset(var->data_type, buffer->size);
- var->buffer_offset = buffer->size;
- TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name);
- buffer->size += var->data_type->reg_size;
- if (var->last_read)
buffer->used_size = buffer->size;
+}
+static void allocate_buffers(struct hlsl_ctx *ctx) +{
- struct hlsl_buffer *buffer, *params_buffer;
- struct hlsl_ir_var *var;
- uint32_t index = 0;
- if (!(params_buffer = hlsl_new_buffer(ctx, HLSL_BUFFER_CONSTANT,
hlsl_strdup(ctx, "$Params"), NULL, ctx->location)))
return;
- /* The $Globals and $Params buffers should be allocated first, before all
* explicit buffers. */
- list_remove(¶ms_buffer->entry);
- list_add_head(&ctx->buffers, ¶ms_buffer->entry);
- list_remove(&ctx->globals_buffer->entry);
- list_add_head(&ctx->buffers, &ctx->globals_buffer->entry);
I find the split in the creation of $Globals and $Params a tiny bit annoying. Right now $Globals is created in hlsl_ctx_init() (which also means that there should be no need to explicitly put it at the top of the buffers list here AFAIU) while $Params is created right here, after parsing. If the point is just to make sure that $Params is the second buffer in the list, list_add_after() should make it a bit more compact and explicit. In theory you could add an assert() if you want to make sure that $Globals is at the head of the list, although probably it would be even better if both these special buffers were created together, in the same place. Unless I'm missing something?
I forgot that list_add_after() exists :-/
Anyway, I think the only reason I didn't bother with creating the same place is that $Params isn't needed (and in fact can't be used) until codegen, and so I'd save a bit of space in hlsl_ctx.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com