From: Francisco Casas fcasas@codeweavers.com
Co-authored-by: Zebediah Figura zfigura@codeweavers.com
hlsl_new_synthetic_var_named() is introduced to create the new resources.
track_object_components_usage() must be called twice:
- One to detect that the same generic sampler isn't used in both tex2D() and tex3D().
- One after the lower_combined_samples() pass so that the object components usage of the new textures is initialized correctly. --- libs/vkd3d-shader/hlsl.c | 48 ++++++++++++ libs/vkd3d-shader/hlsl.h | 4 + libs/vkd3d-shader/hlsl_codegen.c | 99 ++++++++++++++++++++++-- libs/vkd3d-shader/tpf.c | 13 ++-- tests/hlsl-combined-samplers.shader_test | 30 +++---- tests/shader_runner.c | 2 + 6 files changed, 169 insertions(+), 27 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index b68ff5f2..378c9ab0 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -449,6 +449,25 @@ void hlsl_write_component_name(struct hlsl_ctx *ctx, struct vkd3d_string_buffer } }
+void hlsl_write_deref_path(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + const struct hlsl_deref *deref) +{ + const struct hlsl_type *type = deref->var->data_type; + unsigned int element_index, i; + + vkd3d_string_buffer_printf(buffer, "%s", deref->var->name); + + for (i = 0; i < deref->path_len; ++i) + { + element_index = hlsl_ir_constant(deref->path[i].node)->value.u[0].u; + if (type->class == HLSL_CLASS_STRUCT) + vkd3d_string_buffer_printf(buffer, ".%s", type->e.record.fields[element_index].name); + else + vkd3d_string_buffer_printf(buffer, "[%u]", element_index); + type = hlsl_get_element_type_from_path_index(ctx, type, deref->path[i].node); + } +} + static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, unsigned int path_len) { @@ -1059,6 +1078,35 @@ bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struc return true; }
+void hlsl_strip_deref_suffix(struct hlsl_ctx *ctx, struct hlsl_deref *deref, unsigned int at) +{ + unsigned int i; + + assert(at <= deref->path_len); + + for (i = at; i < deref->path_len; ++i) + hlsl_src_remove(&deref->path[i]); + deref->path_len = at; +} + +void hlsl_strip_deref_prefix(struct hlsl_ctx *ctx, struct hlsl_deref *deref, unsigned int at) +{ + unsigned int i; + + assert(at <= deref->path_len); + + if (at == 0) + return; + + for (i = 0; i < deref->path_len; ++i) + { + hlsl_src_remove(&deref->path[i]); + if (i < deref->path_len - at) + hlsl_src_from_node(&deref->path[i], deref->path[i + at].node); + } + deref->path_len = deref->path_len - at; +} + void hlsl_cleanup_deref(struct hlsl_deref *deref) { unsigned int i; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index b7117f0f..5281412a 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1064,6 +1064,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *chain); bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other); +void hlsl_strip_deref_suffix(struct hlsl_ctx *ctx, struct hlsl_deref *deref, unsigned int at); +void hlsl_strip_deref_prefix(struct hlsl_ctx *ctx, struct hlsl_deref *deref, unsigned int at);
void hlsl_cleanup_deref(struct hlsl_deref *deref); void hlsl_cleanup_semantic(struct hlsl_semantic *semantic); @@ -1206,6 +1208,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere
void hlsl_write_component_name(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_var *var, unsigned int index); +void hlsl_write_deref_path(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + const struct hlsl_deref *deref);
bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 9344b193..239f686e 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1981,6 +1981,88 @@ static bool remove_trivial_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *i return true; }
+/* 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) +{ + unsigned int i, k, path_len_to_sampler_array = 0; + struct hlsl_deref deref_to_sampler_array; + struct hlsl_ir_resource_load *sample; + struct hlsl_type *sampler_array_type; + struct vkd3d_string_buffer *name; + struct hlsl_ir_var *var; + + if (instr->type != HLSL_IR_RESOURCE_LOAD) + return false; + sample = hlsl_ir_resource_load(instr); + if (sample->load_type != HLSL_RESOURCE_SAMPLE || sample->sampler.var) + return false; + + /* Find the corresponding sampler array (or single sample component) in the path. */ + sampler_array_type = sample->resource.var->data_type; + for (i = 0; i <= sample->resource.path_len; ++i) + { + if (hlsl_type_is_resource(sampler_array_type)) + { + path_len_to_sampler_array = i; + break; + } + assert(i < sample->resource.path_len); + sampler_array_type = hlsl_get_element_type_from_path_index(ctx, sampler_array_type, sample->resource.path[i].node); + } + assert(hlsl_type_get_regset(sampler_array_type) == HLSL_REGSET_SAMPLERS); + + hlsl_copy_deref(ctx, &deref_to_sampler_array, &sample->resource); + hlsl_strip_deref_suffix(ctx, &deref_to_sampler_array, path_len_to_sampler_array); + + if (!(name = hlsl_get_string_buffer(ctx))) + return false; + vkd3d_string_buffer_printf(name, "<resource>"); + hlsl_write_deref_path(ctx, name, &deref_to_sampler_array); + + TRACE("Lowering to separate resource %s.\n", debugstr_a(name->buffer)); + + if (!(var = hlsl_get_var(ctx->globals, name->buffer))) + { + struct hlsl_type *data_type = hlsl_new_texture_type(ctx, sample->sampling_dim, + ctx->builtin_types.vector[HLSL_TYPE_FLOAT][4 - 1], 0); + unsigned int array_dims = sample->resource.path_len - path_len_to_sampler_array; + + /* Create (possibly multi-dimensional) texture array type with the same dims as the sampler array. */ + for (i = 0; i < array_dims; ++i) + { + struct hlsl_type *arr_type = sampler_array_type; + + for (k = 1; k < array_dims - i; ++k) + { + assert(arr_type->class == HLSL_CLASS_ARRAY); + arr_type = arr_type->e.array.type; + } + data_type = hlsl_new_array_type(ctx, data_type, hlsl_type_element_count(arr_type)); + } + + if (!(var = hlsl_new_synthetic_var_named(ctx, name->buffer, data_type, &instr->loc))) + { + hlsl_release_string_buffer(ctx, name); + hlsl_cleanup_deref(&deref_to_sampler_array); + return false; + } + var->is_uniform = 1; + + list_add_before(&sample->resource.var->extern_entry, &var->extern_entry); + } + hlsl_release_string_buffer(ctx, name); + hlsl_cleanup_deref(&deref_to_sampler_array); + + hlsl_copy_deref(ctx, &sample->sampler, &sample->resource); + sample->resource.var = var; + hlsl_strip_deref_prefix(ctx, &sample->resource, path_len_to_sampler_array); + assert(hlsl_deref_get_type(ctx, &sample->resource)->base_type == HLSL_TYPE_TEXTURE); + assert(hlsl_deref_get_type(ctx, &sample->sampler)->base_type == HLSL_TYPE_SAMPLER); + + return true; +} + /* Lower DIV to RCP + MUL. */ static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { @@ -3348,7 +3430,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx)
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;
buffer = var1->buffer; @@ -3359,7 +3441,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) { 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;
if (var1 == var2 || var1->buffer != var2->buffer) @@ -3409,7 +3491,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
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) var->buffer = ctx->params_buffer; @@ -3927,6 +4009,14 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry } while (progress);
+ hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); + hlsl_transform_ir(ctx, track_object_components_usage, 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) { hlsl_transform_ir(ctx, lower_division, body, NULL); @@ -3940,9 +4030,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, validate_static_object_references, body, NULL); - hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); - /* TODO: move forward, remove when no longer needed */ hlsl_transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index a807a166..7e9e1cfb 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3225,7 +3225,10 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) { var = extern_resources[i];
- string_offset = put_string(&buffer, var->name); + if (!strncmp(var->name, "<resource>", strlen("<resource>"))) + string_offset = put_string(&buffer, var->name + strlen("<resource>")); + else + string_offset = put_string(&buffer, var->name); set_u32(&buffer, resources_offset + i * 8 * sizeof(uint32_t), string_offset); }
@@ -4973,11 +4976,9 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx,
case HLSL_RESOURCE_SAMPLE: case HLSL_RESOURCE_SAMPLE_LOD_BIAS: - if (!load->sampler.var) - { - hlsl_fixme(ctx, &load->node.loc, "SM4 combined sample expression."); - return; - } + /* Combined sample expressions were lowered. */ + assert(load->sampler.var); + write_sm4_sample(ctx, buffer, load); break;
diff --git a/tests/hlsl-combined-samplers.shader_test b/tests/hlsl-combined-samplers.shader_test index b9677749..d013c92d 100644 --- a/tests/hlsl-combined-samplers.shader_test +++ b/tests/hlsl-combined-samplers.shader_test @@ -31,7 +31,7 @@ size (1, 1) 4.0 4.0 4.0 1.0
-[pixel shader todo] +[pixel shader] sampler sam;
float4 main() : sv_target @@ -40,11 +40,11 @@ float4 main() : sv_target }
[test] -todo draw quad -todo probe all rgba (0, 0, 0, 1) +draw quad +probe all rgba (0, 0, 0, 1)
-[pixel shader todo] +[pixel shader] Texture2D tex; sampler sam;
@@ -55,11 +55,11 @@ float4 main() : sv_target }
[test] -todo draw quad +draw quad todo probe all rgba (10, 10, 10, 11)
-[pixel shader todo] +[pixel shader] Texture2D tex; sampler sam[2];
@@ -69,11 +69,11 @@ float4 main() : sv_target }
[test] -todo draw quad +draw quad todo probe all rgba (21, 21, 21, 11)
-[pixel shader todo] +[pixel shader] sampler sam0; sampler sam1; sampler sam2; @@ -85,11 +85,11 @@ float4 main() : sv_target }
[test] -todo draw quad -todo probe all rgba (102, 102, 102, 111) +draw quad +probe all rgba (102, 102, 102, 111)
-[pixel shader todo] +[pixel shader] Texture2D tex[2][2]; sampler sam;
@@ -100,7 +100,7 @@ float4 main() : sv_target }
[test] -todo draw quad +draw quad todo probe all rgba (104, 104, 104, 111)
@@ -108,7 +108,7 @@ todo probe all rgba (104, 104, 104, 111) shader model >= 5.0
-[pixel shader todo] +[pixel shader] struct { Texture2D tex; @@ -121,5 +121,5 @@ float4 main() : sv_target }
[test] -todo draw quad -todo probe all rgba (10, 10, 10, 11) +draw quad +probe all rgba (10, 10, 10, 11) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index b51145c7..de2a2608 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1208,6 +1208,8 @@ out:
START_TEST(shader_runner) { + fflush(stdout); + parse_args(argc, argv);
#if defined(VKD3D_CROSSTEST)