From 52b81f42eb30b7d65c312353cd37372351f95d30 Mon Sep 17 00:00:00 2001 From: Francisco Casas Date: Thu, 7 Nov 2024 21:02:43 -0300 Subject: [PATCH] vkd3d-shader/hlsl: Store SM4 HLSL_RESOURCE_LOADs in the vsir program. --- libs/vkd3d-shader/hlsl_codegen.c | 144 +++++++++++++++++++++++++++++++ libs/vkd3d-shader/tpf.c | 104 ++++------------------ 2 files changed, 160 insertions(+), 88 deletions(-) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index b6ea5345..cc0b0016 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -8898,6 +8898,145 @@ static bool sm4_generate_vsir_instr_resource_store(struct hlsl_ctx *ctx, return true; } +static bool sm4_generate_vsir_validate_texel_offset_aoffimmi(const struct hlsl_ir_node *texel_offset) +{ + struct hlsl_ir_constant *offset; + + VKD3D_ASSERT(texel_offset); + if (texel_offset->type != HLSL_IR_CONSTANT) + return false; + offset = hlsl_ir_constant(texel_offset); + + if (offset->value.u[0].i < -8 || offset->value.u[0].i > 7) + return false; + if (offset->node.data_type->dimx > 1 && (offset->value.u[1].i < -8 || offset->value.u[1].i > 7)) + return false; + if (offset->node.data_type->dimx > 2 && (offset->value.u[2].i < -8 || offset->value.u[2].i > 7)) + return false; + return true; +} + +static void sm4_generate_vsir_encode_texel_offset_as_aoffimmi( + struct vkd3d_shader_instruction *ins, const struct hlsl_ir_node *texel_offset) +{ + struct hlsl_ir_constant *offset; + + if (!texel_offset) + return; + offset = hlsl_ir_constant(texel_offset); + + ins->texel_offset.u = offset->value.u[0].i; + ins->texel_offset.v = 0; + ins->texel_offset.w = 0; + if (offset->node.data_type->dimx > 1) + ins->texel_offset.v = offset->value.u[1].i; + if (offset->node.data_type->dimx > 2) + ins->texel_offset.w = offset->value.u[2].i; +} + +static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, + struct vsir_program *program, const struct hlsl_ir_resource_load *load) +{ + const struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, &load->resource); + bool uav = (hlsl_deref_get_regset(ctx, &load->resource) == HLSL_REGSET_UAVS); + const struct vkd3d_shader_version *version = &program->shader_version; + bool raw = resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER; + const struct hlsl_ir_node *sample_index = load->sample_index.node; + const struct hlsl_ir_node *texel_offset = load->texel_offset.node; + const struct hlsl_ir_node *coords = load->coords.node; + unsigned int coords_writemask = VKD3DSP_WRITEMASK_ALL; + const struct hlsl_deref *resource = &load->resource; + const struct hlsl_ir_node *instr = &load->node; + enum hlsl_sampler_dim dim = load->sampling_dim; + struct vkd3d_shader_instruction *ins; + enum vkd3d_shader_opcode opcode; + bool multisampled; + + VKD3D_ASSERT(load->load_type == HLSL_RESOURCE_LOAD); + + multisampled = resource_type->class == HLSL_CLASS_TEXTURE + && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS + || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); + + if (uav) + opcode = VKD3DSIH_LD_UAV_TYPED; + else if (raw) + opcode = VKD3DSIH_LD_RAW; + else + opcode = multisampled ? VKD3DSIH_LD2DMS : VKD3DSIH_LD; + + if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 2 + multisampled))) + return false; + + if (texel_offset && !sm4_generate_vsir_validate_texel_offset_aoffimmi(texel_offset)) + { + hlsl_error(ctx, &texel_offset->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TEXEL_OFFSET, + "Offset must resolve to integer literal in the range -8 to 7."); + return false; + } + sm4_generate_vsir_encode_texel_offset_as_aoffimmi(ins, texel_offset); + + vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); + + if (!uav) + { + /* Mipmap level is in the last component in the IR, but needs to be in + * the W component in the instruction. */ + unsigned int dim_count = hlsl_sampler_dim_count(dim); + + if (dim_count == 1) + coords_writemask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_3; + if (dim_count == 2) + coords_writemask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_3; + } + + vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, coords_writemask); + + if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + &ins->src[1], resource, ins->dst[0].write_mask, &instr->loc)) + return false; + + if (multisampled) + { + if (sample_index->type == HLSL_IR_CONSTANT) + vsir_src_from_hlsl_constant_value(&ins->src[2], ctx, + &hlsl_ir_constant(sample_index)->value, VKD3D_DATA_INT, 1, 0); + else if (version->major == 4 && version->minor == 0) + hlsl_error(ctx, &sample_index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Expected literal sample index."); + else + vsir_src_from_hlsl_node(&ins->src[2], ctx, sample_index, VKD3DSP_WRITEMASK_ALL); + } + return true; +} + +static bool sm4_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, + struct vsir_program *program, const struct hlsl_ir_resource_load *load) +{ + if (load->sampler.var && !load->sampler.var->is_uniform) + { + hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); + return false; + } + + if (!load->resource.var->is_uniform) + { + hlsl_fixme(ctx, &load->node.loc, "Load from non-uniform resource variable."); + return false; + } + + switch (load->load_type) + { + case HLSL_RESOURCE_LOAD: + return sm4_generate_vsir_instr_ld(ctx, program, load); + + case HLSL_RESOURCE_SAMPLE_PROJ: + vkd3d_unreachable(); + + default: + return false; + } +} + static void sm4_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct vsir_program *program) { struct vkd3d_string_buffer *dst_type_string; @@ -8948,6 +9087,11 @@ static void sm4_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *blo sm4_generate_vsir_block(ctx, &hlsl_ir_loop(instr)->body, program); break; + case HLSL_IR_RESOURCE_LOAD: + if (sm4_generate_vsir_instr_resource_load(ctx, program, hlsl_ir_resource_load(instr))) + replace_instr_with_last_vsir_instr(ctx, program, instr); + break; + case HLSL_IR_RESOURCE_STORE: if (sm4_generate_vsir_instr_resource_store(ctx, program, hlsl_ir_resource_store(instr))) replace_instr_with_last_vsir_instr(ctx, program, instr); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index e1ca5d6f..1a752a2a 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -5034,88 +5034,6 @@ static void write_sm4_ret(const struct tpf_compiler *tpf) write_sm4_instruction(tpf, &instr); } -static void write_sm4_ld(const struct tpf_compiler *tpf, const struct hlsl_ir_node *dst, - const struct hlsl_deref *resource, const struct hlsl_ir_node *coords, - const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset, - enum hlsl_sampler_dim dim) -{ - const struct hlsl_type *resource_type = hlsl_deref_get_type(tpf->ctx, resource); - bool multisampled = resource_type->class == HLSL_CLASS_TEXTURE - && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); - bool uav = (hlsl_deref_get_regset(tpf->ctx, resource) == HLSL_REGSET_UAVS); - const struct vkd3d_shader_version *version = &tpf->program->shader_version; - bool raw = resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER; - unsigned int coords_writemask = VKD3DSP_WRITEMASK_ALL; - struct sm4_instruction instr; - - memset(&instr, 0, sizeof(instr)); - if (uav) - instr.opcode = VKD3D_SM5_OP_LD_UAV_TYPED; - else if (raw) - instr.opcode = VKD3D_SM5_OP_LD_RAW; - else - instr.opcode = multisampled ? VKD3D_SM4_OP_LD2DMS : VKD3D_SM4_OP_LD; - - if (texel_offset) - { - if (!encode_texel_offset_as_aoffimmi(&instr, texel_offset)) - { - hlsl_error(tpf->ctx, &texel_offset->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TEXEL_OFFSET, - "Offset must resolve to integer literal in the range -8 to 7."); - return; - } - } - - sm4_dst_from_node(&instr.dsts[0], dst); - instr.dst_count = 1; - - if (!uav) - { - /* Mipmap level is in the last component in the IR, but needs to be in the W - * component in the instruction. */ - unsigned int dim_count = hlsl_sampler_dim_count(dim); - - if (dim_count == 1) - coords_writemask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_3; - if (dim_count == 2) - coords_writemask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_3; - } - - sm4_src_from_node(tpf, &instr.srcs[0], coords, coords_writemask); - - sm4_src_from_deref(tpf, &instr.srcs[1], resource, instr.dsts[0].write_mask, &instr); - - instr.src_count = 2; - - if (multisampled) - { - if (sample_index->type == HLSL_IR_CONSTANT) - { - struct vkd3d_shader_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])); - reg->type = VKD3DSPR_IMMCONST; - reg->dimension = VSIR_DIMENSION_SCALAR; - reg->u.immconst_u32[0] = index->value.u[0].u; - } - else if (version->major == 4 && version->minor == 0) - { - hlsl_error(tpf->ctx, &sample_index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Expected literal sample index."); - } - else - { - sm4_src_from_node(tpf, &instr.srcs[2], sample_index, 0); - } - - ++instr.src_count; - } - - write_sm4_instruction(tpf, &instr); -} - static void write_sm4_sample(const struct tpf_compiler *tpf, const struct hlsl_ir_resource_load *load) { const struct hlsl_ir_node *texel_offset = load->texel_offset.node; @@ -5374,7 +5292,6 @@ static void write_sm4_gather(const struct tpf_compiler *tpf, const struct hlsl_i static void write_sm4_resource_load(const struct tpf_compiler *tpf, const struct hlsl_ir_resource_load *load) { 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 (load->sampler.var && !load->sampler.var->is_uniform) @@ -5391,11 +5308,6 @@ static void write_sm4_resource_load(const struct tpf_compiler *tpf, const struct switch (load->load_type) { - case HLSL_RESOURCE_LOAD: - write_sm4_ld(tpf, &load->node, &load->resource, - coords, sample_index, texel_offset, load->sampling_dim); - break; - case HLSL_RESOURCE_SAMPLE: case HLSL_RESOURCE_SAMPLE_CMP: case HLSL_RESOURCE_SAMPLE_CMP_LZ: @@ -5435,6 +5347,7 @@ static void write_sm4_resource_load(const struct tpf_compiler *tpf, const struct write_sm4_resinfo(tpf, load); break; + case HLSL_RESOURCE_LOAD: case HLSL_RESOURCE_SAMPLE_PROJ: vkd3d_unreachable(); } @@ -5482,6 +5395,7 @@ static void write_sm4_switch(struct tpf_compiler *tpf, const struct hlsl_ir_swit static void tpf_simple_instruction(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { + struct sm4_instruction_modifier *modifier; const struct vkd3d_sm4_opcode_info *info; struct sm4_instruction instr = {0}; unsigned int dst_count, src_count; @@ -5527,6 +5441,16 @@ static void tpf_simple_instruction(struct tpf_compiler *tpf, const struct vkd3d_ for (unsigned int i = 0; i < ins->src_count; ++i) instr.srcs[i] = ins->src[i]; + if (ins->texel_offset.u || ins->texel_offset.v || ins->texel_offset.w) + { + VKD3D_ASSERT(instr.modifier_count < ARRAY_SIZE(instr.modifiers)); + modifier = &instr.modifiers[instr.modifier_count++]; + modifier->type = VKD3D_SM4_MODIFIER_AOFFIMMI; + modifier->u.aoffimmi.u = ins->texel_offset.u; + modifier->u.aoffimmi.v = ins->texel_offset.v; + modifier->u.aoffimmi.w = ins->texel_offset.w; + } + write_sm4_instruction(tpf, &instr); } @@ -5607,6 +5531,10 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ case VKD3DSIH_ISHL: case VKD3DSIH_ISHR: case VKD3DSIH_ITOF: + case VKD3DSIH_LD: + case VKD3DSIH_LD2DMS: + case VKD3DSIH_LD_RAW: + case VKD3DSIH_LD_UAV_TYPED: case VKD3DSIH_LOG: case VKD3DSIH_LTO: case VKD3DSIH_MAD: