vkd3d-shader/hlsl: Parse packoffset().

This commit is contained in:
Francisco Casas
2023-02-22 14:53:17 -03:00
committed by Alexandre Julliard
parent 9b70971696
commit 4aca335f42
Notes: Alexandre Julliard 2023-04-04 22:35:22 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/106
4 changed files with 129 additions and 24 deletions

View File

@@ -342,12 +342,17 @@ struct hlsl_attribute
#define HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT 0 #define HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT 0
/* Reservation of a specific register to a variable, field, or buffer, written in the HLSL source /* Reservation of a register and/or an offset for objects inside constant buffers, to be used as a
* using the register(·) syntax */ * starting point of their allocation. They are available through the register(·) and the
* packoffset(·) syntaxes, respectivelly.
* The costant buffer offset is measured register components. */
struct hlsl_reg_reservation struct hlsl_reg_reservation
{ {
char reg_type; char reg_type;
unsigned int reg_index; unsigned int reg_index;
char offset_type;
unsigned int offset_index;
}; };
struct hlsl_ir_var struct hlsl_ir_var
@@ -360,8 +365,7 @@ struct hlsl_ir_var
struct hlsl_buffer *buffer; struct hlsl_buffer *buffer;
/* Bitfield for storage modifiers (type modifiers are stored in data_type->modifiers). */ /* Bitfield for storage modifiers (type modifiers are stored in data_type->modifiers). */
unsigned int storage_modifiers; unsigned int storage_modifiers;
/* Optional register to be used as a starting point for the variable allocation, specified /* Optional reservations of registers and/or offsets for variables within constant buffers. */
* by the user via the register(·) syntax. */
struct hlsl_reg_reservation reg_reservation; struct hlsl_reg_reservation reg_reservation;
/* Item entry in hlsl_scope.vars. Specifically hlsl_ctx.globals.vars if the variable is global. */ /* Item entry in hlsl_scope.vars. Specifically hlsl_ctx.globals.vars if the variable is global. */

View File

@@ -95,6 +95,7 @@ matrix {return KW_MATRIX; }
namespace {return KW_NAMESPACE; } namespace {return KW_NAMESPACE; }
nointerpolation {return KW_NOINTERPOLATION; } nointerpolation {return KW_NOINTERPOLATION; }
out {return KW_OUT; } out {return KW_OUT; }
packoffset {return KW_PACKOFFSET; }
pass {return KW_PASS; } pass {return KW_PASS; }
PixelShader {return KW_PIXELSHADER; } PixelShader {return KW_PIXELSHADER; }
precise {return KW_PRECISE; } precise {return KW_PRECISE; }

View File

@@ -983,6 +983,9 @@ static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields,
hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Illegal initializer on a struct field."); hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Illegal initializer on a struct field.");
free_parse_initializer(&v->initializer); free_parse_initializer(&v->initializer);
} }
if (v->reg_reservation.offset_type)
hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"packoffset() is not allowed inside struct definitions.");
vkd3d_free(v); vkd3d_free(v);
} }
vkd3d_free(defs); vkd3d_free(defs);
@@ -1063,7 +1066,12 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters
hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER,
"Parameter '%s' is declared as both \"out\" and \"uniform\".", param->name); "Parameter '%s' is declared as both \"out\" and \"uniform\".", param->name);
if (!(var = hlsl_new_var(ctx, param->name, param->type, loc, &param->semantic, param->modifiers, &param->reg_reservation))) if (param->reg_reservation.offset_type)
hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"packoffset() is not allowed on function parameters.");
if (!(var = hlsl_new_var(ctx, param->name, param->type, loc, &param->semantic, param->modifiers,
&param->reg_reservation)))
return false; return false;
var->is_param = 1; var->is_param = 1;
@@ -1093,6 +1101,52 @@ static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string)
return reservation; return reservation;
} }
static struct hlsl_reg_reservation parse_packoffset(struct hlsl_ctx *ctx, const char *reg_string,
const char *swizzle, const struct vkd3d_shader_location *loc)
{
struct hlsl_reg_reservation reservation = {0};
char *endptr;
reservation.offset_index = strtoul(reg_string + 1, &endptr, 10);
if (*endptr)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"Invalid packoffset() syntax.");
return reservation;
}
reservation.offset_type = reg_string[0];
if (reservation.offset_type != 'c')
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"Only 'c' registers are allowed in packoffset().");
return reservation;
}
reservation.offset_index *= 4;
if (swizzle)
{
if (strlen(swizzle) != 1)
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"Invalid packoffset() component \"%s\".", swizzle);
if (swizzle[0] == 'x' || swizzle[0] == 'r')
reservation.offset_index += 0;
else if (swizzle[0] == 'y' || swizzle[0] == 'g')
reservation.offset_index += 1;
else if (swizzle[0] == 'z' || swizzle[0] == 'b')
reservation.offset_index += 2;
else if (swizzle[0] == 'w' || swizzle[0] == 'a')
reservation.offset_index += 3;
else
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"Invalid packoffset() component \"%s\".", swizzle);
}
return reservation;
}
static struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, static struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs,
const char *name, const struct hlsl_func_parameters *parameters) const char *name, const struct hlsl_func_parameters *parameters)
{ {
@@ -2043,6 +2097,13 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t
var->buffer = ctx->cur_buffer; var->buffer = ctx->cur_buffer;
if (var->buffer == ctx->globals_buffer)
{
if (var->reg_reservation.offset_type)
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"packoffset() is only allowed inside constant buffer declarations.");
}
if (ctx->cur_scope == ctx->globals) if (ctx->cur_scope == ctx->globals)
{ {
local = false; local = false;
@@ -3846,6 +3907,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type
%token KW_NAMESPACE %token KW_NAMESPACE
%token KW_NOINTERPOLATION %token KW_NOINTERPOLATION
%token KW_OUT %token KW_OUT
%token KW_PACKOFFSET
%token KW_PASS %token KW_PASS
%token KW_PIXELSHADER %token KW_PIXELSHADER
%token KW_PRECISE %token KW_PRECISE
@@ -3999,6 +4061,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type
%type <parameters> parameters %type <parameters> parameters
%type <reg_reservation> register_opt %type <reg_reservation> register_opt
%type <reg_reservation> packoffset_opt
%type <sampler_dim> texture_type texture_ms_type uav_type %type <sampler_dim> texture_type texture_ms_type uav_type
@@ -4351,6 +4414,9 @@ func_prototype_no_attrs:
if ($7.reg_reservation.reg_type) if ($7.reg_reservation.reg_type)
FIXME("Unexpected register reservation for a function.\n"); FIXME("Unexpected register reservation for a function.\n");
if ($7.reg_reservation.offset_type)
hlsl_error(ctx, &@5, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
"packoffset() is not allowed on functions.");
if (($$.decl = get_func_decl(&ctx->functions, $3, &$5))) if (($$.decl = get_func_decl(&ctx->functions, $3, &$5)))
{ {
@@ -4478,17 +4544,24 @@ colon_attribute:
{ {
$$.semantic.name = NULL; $$.semantic.name = NULL;
$$.reg_reservation.reg_type = 0; $$.reg_reservation.reg_type = 0;
$$.reg_reservation.offset_type = 0;
} }
| semantic | semantic
{ {
$$.semantic = $1; $$.semantic = $1;
$$.reg_reservation.reg_type = 0; $$.reg_reservation.reg_type = 0;
$$.reg_reservation.offset_type = 0;
} }
| register_opt | register_opt
{ {
$$.semantic.name = NULL; $$.semantic.name = NULL;
$$.reg_reservation = $1; $$.reg_reservation = $1;
} }
| packoffset_opt
{
$$.semantic.name = NULL;
$$.reg_reservation = $1;
}
semantic: semantic:
':' any_identifier ':' any_identifier
@@ -4518,6 +4591,21 @@ register_opt:
vkd3d_free($6); vkd3d_free($6);
} }
packoffset_opt:
':' KW_PACKOFFSET '(' any_identifier ')'
{
$$ = parse_packoffset(ctx, $4, NULL, &@$);
vkd3d_free($4);
}
| ':' KW_PACKOFFSET '(' any_identifier '.' any_identifier ')'
{
$$ = parse_packoffset(ctx, $4, $6, &@$);
vkd3d_free($4);
vkd3d_free($6);
}
parameters: parameters:
scope_start scope_start
{ {

View File

@@ -23,6 +23,18 @@ probe all rgba (1.0, 2.0, 3.0, 4.0)
shader model >= 4.0 shader model >= 4.0
[pixel shader fail]
cbuffer buffer
{
float4 a : packoffset(c1invalid_extra_chars);
}
float4 main() : sv_target
{
return 0;
}
% Respect register boundaries % Respect register boundaries
[pixel shader] [pixel shader]
cbuffer buffer cbuffer buffer
@@ -94,7 +106,7 @@ draw quad
probe all rgba (0.0, 4.0, 5.0, 6.0) probe all rgba (0.0, 4.0, 5.0, 6.0)
[pixel shader fail] [pixel shader fail todo]
// Elements cannot overlap if buffer is used. // Elements cannot overlap if buffer is used.
cbuffer buffer cbuffer buffer
{ {
@@ -109,7 +121,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
// Elements can overlap if buffer is not used. // Elements can overlap if buffer is not used.
cbuffer buffer cbuffer buffer
{ {
@@ -123,7 +135,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
cbuffer buffer cbuffer buffer
{ {
float4 a : packoffset(c1); float4 a : packoffset(c1);
@@ -139,11 +151,11 @@ float4 main() : sv_target
uniform 0 float4 1.0 2.0 3.0 4.0 uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 5.0 6.0 7.0 8.0 uniform 4 float4 5.0 6.0 7.0 8.0
uniform 8 float4 9.0 10.0 11.0 12.0 uniform 8 float4 9.0 10.0 11.0 12.0
todo draw quad draw quad
todo probe all rgba (509, 610, 711, 812) todo probe all rgba (509, 610, 711, 812)
[pixel shader todo] [pixel shader]
struct apple struct apple
{ {
float2 a; float2 a;
@@ -167,11 +179,11 @@ uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0 uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0 uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0 uniform 12 float4 12.0 13.0 14.0 15.0
todo draw quad draw quad
todo probe all rgba (12468.0, 13509.0, 14010.0, 15011.0) todo probe all rgba (12468.0, 13509.0, 14010.0, 15011.0)
[pixel shader todo] [pixel shader]
cbuffer buffer cbuffer buffer
{ {
float2 c : packoffset(c0.y); float2 c : packoffset(c0.y);
@@ -184,11 +196,11 @@ float4 main() : sv_target
[test] [test]
uniform 0 float4 1.0 2.0 3.0 4.0 uniform 0 float4 1.0 2.0 3.0 4.0
todo draw quad draw quad
todo probe all rgba (2.0, 3.0, 2.0, 3.0) todo probe all rgba (2.0, 3.0, 2.0, 3.0)
[pixel shader fail] [pixel shader fail todo]
// Elements must respect register boundaries. // Elements must respect register boundaries.
cbuffer buffer cbuffer buffer
{ {
@@ -201,7 +213,7 @@ float4 main() : sv_target
} }
[pixel shader fail] [pixel shader fail todo]
// Matrices must be aligned. // Matrices must be aligned.
cbuffer buffer cbuffer buffer
{ {
@@ -214,7 +226,7 @@ float4 main() : sv_target
} }
[pixel shader fail] [pixel shader fail todo]
// Arrays must be aligned. // Arrays must be aligned.
cbuffer buffer cbuffer buffer
{ {
@@ -227,7 +239,7 @@ float4 main() : sv_target
} }
[pixel shader fail] [pixel shader fail todo]
// Structs must be aligned. // Structs must be aligned.
struct apple struct apple
{ {
@@ -245,7 +257,7 @@ float4 main() : sv_target
} }
[pixel shader fail] [pixel shader fail todo]
// Invalid offset on unused buffer. // Invalid offset on unused buffer.
cbuffer buffer cbuffer buffer
{ {
@@ -258,7 +270,7 @@ float4 main() : sv_target
} }
[pixel shader fail] [pixel shader fail todo]
// Invalid offset on unused variable. // Invalid offset on unused variable.
cbuffer buffer cbuffer buffer
{ {
@@ -272,7 +284,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
cbuffer buffer cbuffer buffer
{ {
float4 a : packoffset(c1); float4 a : packoffset(c1);
@@ -289,11 +301,11 @@ float4 main() : sv_target
uniform 0 float 1.0 uniform 0 float 1.0
uniform 1 float 2.0 uniform 1 float 2.0
uniform 4 float4 5.0 6.0 7.0 8.0 uniform 4 float4 5.0 6.0 7.0 8.0
todo draw quad draw quad
todo probe all rgba (512.0, 612.0, 712.0, 812.0) todo probe all rgba (512.0, 612.0, 712.0, 812.0)
[pixel shader fail] [pixel shader fail todo]
// packoffset cannot be used unless all elements use it. // packoffset cannot be used unless all elements use it.
cbuffer buffer cbuffer buffer
{ {
@@ -307,7 +319,7 @@ float4 main() : sv_target
} }
[pixel shader todo] [pixel shader]
cbuffer buffer cbuffer buffer
{ {
float2 c : packoffset(c0.b); float2 c : packoffset(c0.b);
@@ -320,7 +332,7 @@ float4 main() : sv_target
[test] [test]
uniform 0 float4 1.0 2.0 3.0 4.0 uniform 0 float4 1.0 2.0 3.0 4.0
todo draw quad draw quad
todo probe all rgba (3.0, 4.0, 3.0, 4.0) todo probe all rgba (3.0, 4.0, 3.0, 4.0)