vkd3d-shader/hlsl: Lower combined samplers to separate sampler and texture objects for SM4.

Co-authored-by: Francisco Casas <fcasas@codeweavers.com>
This commit is contained in:
Zebediah Figura
2023-05-29 21:59:17 -04:00
committed by Alexandre Julliard
parent 15ea5ff9db
commit a55973d695
Notes: Alexandre Julliard 2023-07-17 23:25:21 +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/209
5 changed files with 126 additions and 27 deletions

View File

@@ -673,6 +673,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba
type->e.array.type = basic_type; type->e.array.type = basic_type;
type->dimx = basic_type->dimx; type->dimx = basic_type->dimx;
type->dimy = basic_type->dimy; type->dimy = basic_type->dimy;
type->sampler_dim = basic_type->sampler_dim;
hlsl_type_calculate_reg_size(ctx, type); hlsl_type_calculate_reg_size(ctx, type);
list_add_tail(&ctx->types, &type->entry); list_add_tail(&ctx->types, &type->entry);

View File

@@ -422,6 +422,7 @@ struct hlsl_ir_var
uint32_t is_output_semantic : 1; uint32_t is_output_semantic : 1;
uint32_t is_uniform : 1; uint32_t is_uniform : 1;
uint32_t is_param : 1; uint32_t is_param : 1;
uint32_t is_separated_resource : 1;
}; };
/* Sized array of variables representing a function's parameters. */ /* Sized array of variables representing a function's parameters. */

View File

@@ -2067,6 +2067,97 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir
return false; return false;
} }
/* Lower combined samples and sampler variables to synthesized separated textures and samplers.
* That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */
static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
{
struct hlsl_ir_resource_load *load;
struct vkd3d_string_buffer *name;
struct hlsl_ir_var *var;
unsigned int i;
if (instr->type != HLSL_IR_RESOURCE_LOAD)
return false;
load = hlsl_ir_resource_load(instr);
switch (load->load_type)
{
case HLSL_RESOURCE_LOAD:
case HLSL_RESOURCE_GATHER_RED:
case HLSL_RESOURCE_GATHER_GREEN:
case HLSL_RESOURCE_GATHER_BLUE:
case HLSL_RESOURCE_GATHER_ALPHA:
case HLSL_RESOURCE_SAMPLE_CMP:
case HLSL_RESOURCE_SAMPLE_CMP_LZ:
case HLSL_RESOURCE_SAMPLE_GRAD:
return false;
case HLSL_RESOURCE_SAMPLE:
case HLSL_RESOURCE_SAMPLE_LOD:
case HLSL_RESOURCE_SAMPLE_LOD_BIAS:
break;
}
if (load->sampler.var)
return false;
if (!hlsl_type_is_resource(load->resource.var->data_type))
{
hlsl_fixme(ctx, &instr->loc, "Lower combined samplers within structs.");
return false;
}
assert(hlsl_type_get_regset(load->resource.var->data_type) == HLSL_REGSET_SAMPLERS);
if (!(name = hlsl_get_string_buffer(ctx)))
return false;
vkd3d_string_buffer_printf(name, "<resource>%s", load->resource.var->name);
TRACE("Lowering to separate resource %s.\n", debugstr_a(name->buffer));
if (!(var = hlsl_get_var(ctx->globals, name->buffer)))
{
struct hlsl_type *texture_array_type = hlsl_new_texture_type(ctx, load->sampling_dim,
hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4), 0);
/* Create (possibly multi-dimensional) texture array type with the same dims as the sampler array. */
struct hlsl_type *arr_type = load->resource.var->data_type;
for (i = 0; i < load->resource.path_len; ++i)
{
assert(arr_type->class == HLSL_CLASS_ARRAY);
texture_array_type = hlsl_new_array_type(ctx, texture_array_type, arr_type->e.array.elements_count);
arr_type = arr_type->e.array.type;
}
if (!(var = hlsl_new_synthetic_var_named(ctx, name->buffer, texture_array_type, &instr->loc, false)))
{
hlsl_release_string_buffer(ctx, name);
return false;
}
var->is_uniform = 1;
var->is_separated_resource = true;
list_add_tail(&ctx->extern_vars, &var->extern_entry);
}
hlsl_release_string_buffer(ctx, name);
if (load->sampling_dim != var->data_type->sampler_dim)
{
hlsl_error(ctx, &load->node.loc, VKD3D_SHADER_ERROR_HLSL_INCONSISTENT_SAMPLER,
"Cannot split combined samplers from \"%s\" if they have different usage dimensions.",
load->resource.var->name);
hlsl_note(ctx, &var->loc, VKD3D_SHADER_LOG_ERROR, "First use as combined sampler is here.");
return false;
}
hlsl_copy_deref(ctx, &load->sampler, &load->resource);
load->resource.var = var;
assert(hlsl_deref_get_type(ctx, &load->resource)->base_type == HLSL_TYPE_TEXTURE);
assert(hlsl_deref_get_type(ctx, &load->sampler)->base_type == HLSL_TYPE_SAMPLER);
return true;
}
/* Lower DIV to RCP + MUL. */ /* Lower DIV to RCP + MUL. */
static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
{ {
@@ -3582,7 +3673,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx)
LIST_FOR_EACH_ENTRY(var1, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) LIST_FOR_EACH_ENTRY(var1, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{ {
if (!var1->is_uniform || var1->data_type->class == HLSL_CLASS_OBJECT) if (!var1->is_uniform || hlsl_type_is_resource(var1->data_type))
continue; continue;
buffer = var1->buffer; buffer = var1->buffer;
@@ -3593,7 +3684,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx)
{ {
unsigned int var1_reg_size, var2_reg_size; unsigned int var1_reg_size, var2_reg_size;
if (!var2->is_uniform || var2->data_type->class == HLSL_CLASS_OBJECT) if (!var2->is_uniform || hlsl_type_is_resource(var2->data_type))
continue; continue;
if (var1 == var2 || var1->buffer != var2->buffer) if (var1 == var2 || var1->buffer != var2->buffer)
@@ -3643,7 +3734,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{ {
if (var->is_uniform && var->data_type->class != HLSL_CLASS_OBJECT) if (var->is_uniform && !hlsl_type_is_resource(var->data_type))
{ {
if (var->is_param) if (var->is_param)
var->buffer = ctx->params_buffer; var->buffer = ctx->params_buffer;
@@ -4193,6 +4284,12 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL);
hlsl_transform_ir(ctx, lower_int_dot, body, NULL); hlsl_transform_ir(ctx, lower_int_dot, body, NULL);
hlsl_transform_ir(ctx, validate_static_object_references, body, NULL);
hlsl_transform_ir(ctx, track_object_components_sampler_dim, body, NULL);
if (profile->major_version >= 4)
hlsl_transform_ir(ctx, lower_combined_samples, body, NULL);
hlsl_transform_ir(ctx, track_object_components_usage, body, NULL);
if (profile->major_version < 4) if (profile->major_version < 4)
{ {
hlsl_transform_ir(ctx, lower_division, body, NULL); hlsl_transform_ir(ctx, lower_division, body, NULL);
@@ -4206,10 +4303,6 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
hlsl_transform_ir(ctx, lower_abs, body, NULL); hlsl_transform_ir(ctx, lower_abs, body, NULL);
} }
hlsl_transform_ir(ctx, validate_static_object_references, body, NULL);
hlsl_transform_ir(ctx, track_object_components_sampler_dim, body, NULL);
hlsl_transform_ir(ctx, track_object_components_usage, body, NULL);
/* TODO: move forward, remove when no longer needed */ /* TODO: move forward, remove when no longer needed */
transform_derefs(ctx, replace_deref_path_with_offset, body); transform_derefs(ctx, replace_deref_path_with_offset, body);
while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));

View File

@@ -3005,6 +3005,13 @@ static void sm4_free_extern_resources(struct extern_resource *extern_resources,
vkd3d_free(extern_resources); vkd3d_free(extern_resources);
} }
static const char *string_skip_tag(const char *string)
{
if (!strncmp(string, "<resource>", strlen("<resource>")))
return string + strlen("<resource>");
return string;
}
static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count)
{ {
bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0; bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0;
@@ -3053,7 +3060,7 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
*count = 0; *count = 0;
return NULL; return NULL;
} }
if (!(name = hlsl_strdup(ctx, name_buffer->buffer))) if (!(name = hlsl_strdup(ctx, string_skip_tag(name_buffer->buffer))))
{ {
sm4_free_extern_resources(extern_resources, *count); sm4_free_extern_resources(extern_resources, *count);
*count = 0; *count = 0;
@@ -3092,7 +3099,7 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
return NULL; return NULL;
} }
if (!(name = hlsl_strdup(ctx, var->name))) if (!(name = hlsl_strdup(ctx, string_skip_tag(var->name))))
{ {
sm4_free_extern_resources(extern_resources, *count); sm4_free_extern_resources(extern_resources, *count);
*count = 0; *count = 0;
@@ -5070,11 +5077,8 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx,
case HLSL_RESOURCE_SAMPLE_LOD: case HLSL_RESOURCE_SAMPLE_LOD:
case HLSL_RESOURCE_SAMPLE_LOD_BIAS: case HLSL_RESOURCE_SAMPLE_LOD_BIAS:
case HLSL_RESOURCE_SAMPLE_GRAD: case HLSL_RESOURCE_SAMPLE_GRAD:
if (!load->sampler.var) /* Combined sample expressions were lowered. */
{ assert(load->sampler.var);
hlsl_fixme(ctx, &load->node.loc, "SM4 combined sample expression.");
return;
}
write_sm4_sample(ctx, buffer, load); write_sm4_sample(ctx, buffer, load);
break; break;

View File

@@ -35,7 +35,7 @@ size (1, 1)
4.0 4.0 4.0 1.0 4.0 4.0 4.0 1.0
[pixel shader todo] [pixel shader]
sampler sam; sampler sam;
float4 main() : sv_target float4 main() : sv_target
@@ -44,12 +44,12 @@ float4 main() : sv_target
} }
[test] [test]
todo draw quad draw quad
todo probe all rgba (0, 0, 0, 1) probe all rgba (0, 0, 0, 1)
% Textures for new separated samplers are allocated before regular textures. % Textures for new separated samplers are allocated before regular textures.
[pixel shader todo] [pixel shader]
Texture2D tex; Texture2D tex;
sampler sam; sampler sam;
@@ -59,11 +59,11 @@ float4 main() : sv_target
} }
[test] [test]
todo draw quad draw quad
todo probe all rgba (10, 10, 10, 11) todo probe all rgba (10, 10, 10, 11)
[pixel shader todo] [pixel shader]
Texture2D tex; Texture2D tex;
sampler sam[2]; sampler sam[2];
@@ -73,11 +73,11 @@ float4 main() : sv_target
} }
[test] [test]
todo draw quad draw quad
todo probe all rgba (21, 21, 21, 11) todo probe all rgba (21, 21, 21, 11)
[pixel shader todo] [pixel shader]
sampler sam0; sampler sam0;
sampler sam1; sampler sam1;
sampler sam2; sampler sam2;
@@ -89,11 +89,11 @@ float4 main() : sv_target
} }
[test] [test]
todo draw quad draw quad
todo probe all rgba (12, 12, 12, 111) probe all rgba (12, 12, 12, 111)
[pixel shader todo] [pixel shader]
Texture2D tex[2][2]; Texture2D tex[2][2];
sampler sam; sampler sam;
@@ -104,13 +104,13 @@ float4 main() : sv_target
} }
[test] [test]
todo draw quad draw quad
todo probe all rgba (104, 104, 104, 111) todo probe all rgba (104, 104, 104, 111)
% Sampler arrays with components that have different usage dimensions are only forbidden in SM4 upwards. % Sampler arrays with components that have different usage dimensions are only forbidden in SM4 upwards.
% However, tex2D and tex1D are considered the same dimension for these purposes. % However, tex2D and tex1D are considered the same dimension for these purposes.
[pixel shader fail todo] [pixel shader fail]
sampler sam[2]; sampler sam[2];
float4 main() : sv_target float4 main() : sv_target