-- v2: vkd3d-shader/hlsl: Add support for sample index argument in Load().
From: Nikolay Sivov nsivov@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 7 +++++++ libs/vkd3d-shader/hlsl.h | 4 ++-- libs/vkd3d-shader/hlsl.y | 4 +++- libs/vkd3d-shader/hlsl_codegen.c | 2 ++ libs/vkd3d-shader/hlsl_sm4.c | 36 +++++++++++++++++++++++++++++--- tests/texture-load.shader_test | 15 +++++++++++++ 6 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 64d6e870..52116b77 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1241,6 +1241,7 @@ struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, return NULL; } hlsl_src_from_node(&load->coords, params->coords); + hlsl_src_from_node(&load->sample_index, params->sample_index); hlsl_src_from_node(&load->texel_offset, params->texel_offset); hlsl_src_from_node(&load->lod, params->lod); return load; @@ -2269,6 +2270,11 @@ static void dump_ir_resource_load(struct vkd3d_string_buffer *buffer, const stru dump_deref(buffer, &load->sampler); vkd3d_string_buffer_printf(buffer, ", coords = "); dump_src(buffer, &load->coords); + if (load->sample_index.node) + { + vkd3d_string_buffer_printf(buffer, ", sample index = "); + dump_src(buffer, &load->sample_index); + } if (load->texel_offset.node) { vkd3d_string_buffer_printf(buffer, ", offset = "); @@ -2498,6 +2504,7 @@ static void free_ir_resource_load(struct hlsl_ir_resource_load *load) hlsl_src_remove(&load->coords); hlsl_src_remove(&load->lod); hlsl_src_remove(&load->texel_offset); + hlsl_src_remove(&load->sample_index); vkd3d_free(load); }
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index ec0101e1..ca951b9c 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -586,7 +586,7 @@ struct hlsl_ir_resource_load struct hlsl_ir_node node; enum hlsl_resource_load_type load_type; struct hlsl_deref resource, sampler; - struct hlsl_src coords, lod, texel_offset; + struct hlsl_src coords, lod, sample_index, texel_offset; };
struct hlsl_ir_resource_store @@ -781,7 +781,7 @@ struct hlsl_resource_load_params struct hlsl_type *format; enum hlsl_resource_load_type type; struct hlsl_deref resource, sampler; - struct hlsl_ir_node *coords, *lod, *texel_offset; + struct hlsl_ir_node *coords, *lod, *sample_index, *texel_offset; };
static inline struct hlsl_ir_call *hlsl_ir_call(const struct hlsl_ir_node *node) diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index fd1eaf6e..7e4868be 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -3498,7 +3498,9 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl } if (multisampled) { - hlsl_fixme(ctx, loc, "Load() sampling index parameter."); + if (!(load_params.sample_index = add_implicit_conversion(ctx, instrs, params->args[1], + hlsl_get_scalar_type(ctx, HLSL_TYPE_INT), loc))) + return false; }
assert(offset_dim); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index ab598757..da23ea7f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2373,6 +2373,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop load->texel_offset.node->last_read = instr->index; if (load->lod.node) load->lod.node->last_read = instr->index; + if (load->sample_index.node) + load->sample_index.node->last_read = instr->index; break; } case HLSL_IR_RESOURCE_STORE: diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index f81be3e9..9db562da 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -336,6 +336,8 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) return D3D_SVT_TEXTURE1D; case HLSL_SAMPLER_DIM_2D: return D3D_SVT_TEXTURE2D; + case HLSL_SAMPLER_DIM_2DMS: + return D3D_SVT_TEXTURE2DMS; case HLSL_SAMPLER_DIM_3D: return D3D_SVT_TEXTURE3D; case HLSL_SAMPLER_DIM_CUBE: @@ -1464,14 +1466,16 @@ static void write_sm4_constant(struct hlsl_ctx *ctx, static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, const struct hlsl_ir_node *coords, - const struct hlsl_ir_node *texel_offset) + const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset) { bool uav = (resource_type->base_type == HLSL_TYPE_UAV); + bool multisampled = resource_type->base_type == HLSL_TYPE_TEXTURE + && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); struct sm4_instruction instr; unsigned int dim_count;
memset(&instr, 0, sizeof(instr)); - instr.opcode = uav ? VKD3D_SM5_OP_LD_UAV_TYPED : VKD3D_SM4_OP_LD; + instr.opcode = uav ? VKD3D_SM5_OP_LD_UAV_TYPED : (multisampled ? VKD3D_SM4_OP_LD2DMS : VKD3D_SM4_OP_LD);
if (texel_offset) { @@ -1503,6 +1507,31 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf
instr.src_count = 2;
+ if (multisampled) + { + if (sample_index->type == HLSL_IR_CONSTANT) + { + struct sm4_register *reg = &instr.srcs[2].reg; + struct hlsl_ir_constant *index; + + index = hlsl_ir_constant(sample_index); + + memset(&instr.srcs[2], 0, sizeof(instr.srcs[2])); + instr.srcs[2].swizzle_type = VKD3D_SM4_SWIZZLE_NONE; + reg->type = VKD3D_SM4_RT_IMMCONST; + reg->dim = VKD3D_SM4_DIMENSION_SCALAR; + reg->immconst_uint[0] = index->value[0].u; + } + else if (ctx->profile->major_version == 4 && ctx->profile->minor_version == 0) + { + hlsl_error(ctx, &sample_index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Expected literal sample index."); + } + else + sm4_src_from_node(&instr.srcs[2], sample_index, 0); + + ++instr.src_count; + } + write_sm4_instruction(buffer, &instr); }
@@ -2229,6 +2258,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, { const struct hlsl_type *resource_type = load->resource.var->data_type; const struct hlsl_ir_node *texel_offset = load->texel_offset.node; + const struct hlsl_ir_node *sample_index = load->sample_index.node; const struct hlsl_ir_node *coords = load->coords.node;
if (resource_type->type != HLSL_CLASS_OBJECT) @@ -2268,7 +2298,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, { case HLSL_RESOURCE_LOAD: write_sm4_ld(ctx, buffer, resource_type, &load->node, &load->resource, - coords, texel_offset); + coords, sample_index, texel_offset); break;
case HLSL_RESOURCE_SAMPLE: diff --git a/tests/texture-load.shader_test b/tests/texture-load.shader_test index 7d39fb65..8a223120 100644 --- a/tests/texture-load.shader_test +++ b/tests/texture-load.shader_test @@ -35,3 +35,18 @@ probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8) probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0) + +[pixel shader] +Texture2DMS<float4, 1> t; + +float4 main(float4 pos : sv_position) : sv_target +{ + return t.Load(int3(pos.yx, 0), 0); +} + +[test] +draw quad +probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) +probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) +probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8) +probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0)
Giovanni Mascellani (@giomasce) commented about tests/texture-load.shader_test:
probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0)
+[pixel shader] +Texture2DMS<float4, 1> t;
+float4 main(float4 pos : sv_position) : sv_target +{
- return t.Load(int3(pos.yx, 0), 0);
+}
+[test] +draw quad +probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) +probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) +probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8) +probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0)
I meant, how hard is it to test this on an actually multisampled texture? Is there a reasonably simple way to create a multisampled texture with given content?
On Tue Apr 4 13:13:10 2023 +0000, Giovanni Mascellani wrote:
I meant, how hard is it to test this on an actually multisampled texture? Is there a reasonably simple way to create a multisampled texture with given content?
I don't know if you can do that directly. Maybe you can render to it to initialize, but there is no support for that in shader runner I believe. If anyone has an idea please let me know.
The goal would be to use sample count >1 and Load() with 0 and 1, with observable difference.
On Tue Apr 4 15:37:55 2023 +0000, Nikolay Sivov wrote:
I don't know if you can do that directly. Maybe you can render to it to initialize, but there is no support for that in shader runner I believe. If anyone has an idea please let me know. The goal would be to use sample count >1 and Load() with 0 and 1, with observable difference.
You can't just upload data to a multisampled texture, no, and I believe that sample positions aren't fixed either, so just rendering a triangle over half of a pixel is not going to give reliable results. It is possible to use a sample frequency shader (i.e. SV_SampleIndex), which would basically amount to porting test_multisample_rendering() to a shader_test, although that requires model 4.1.
Ultimately I think we do want to port more d3d12 (or d3d11, or d3d9) tests to use the shader-runner infrastructure, so that they can target multiple backends without having to be rewritten. But that is probably reasonable to leave for later.
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl_sm4.c:
static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, const struct hlsl_ir_node *coords,
const struct hlsl_ir_node *texel_offset)
const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset)
{ bool uav = (resource_type->base_type == HLSL_TYPE_UAV);
bool multisampled = resource_type->base_type == HLSL_TYPE_TEXTURE
&& (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY);
struct sm4_instruction instr; unsigned int dim_count;
memset(&instr, 0, sizeof(instr));
- instr.opcode = uav ? VKD3D_SM5_OP_LD_UAV_TYPED : VKD3D_SM4_OP_LD;
- instr.opcode = uav ? VKD3D_SM5_OP_LD_UAV_TYPED : (multisampled ? VKD3D_SM4_OP_LD2DMS : VKD3D_SM4_OP_LD);
Let's not nest ternary operators, please, that's a little hard to read.
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl_sm4.c:
index = hlsl_ir_constant(sample_index);
memset(&instr.srcs[2], 0, sizeof(instr.srcs[2]));
instr.srcs[2].swizzle_type = VKD3D_SM4_SWIZZLE_NONE;
reg->type = VKD3D_SM4_RT_IMMCONST;
reg->dim = VKD3D_SM4_DIMENSION_SCALAR;
reg->immconst_uint[0] = index->value[0].u;
}
else if (ctx->profile->major_version == 4 && ctx->profile->minor_version == 0)
{
hlsl_error(ctx, &sample_index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Expected literal sample index.");
}
else
sm4_src_from_node(&instr.srcs[2], sample_index, 0);
Unbalanced braces here.