diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 32825b75..2482efc5 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1865,7 +1865,7 @@ struct sm1_instruction D3DSHADER_PARAM_SRCMOD_TYPE mod; unsigned int swizzle; uint32_t reg; - } srcs[3]; + } srcs[4]; unsigned int src_count; unsigned int has_dst; @@ -2573,6 +2573,8 @@ static void write_sm1_resource_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_ { const struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); struct hlsl_ir_node *coords = load->coords.node; + struct hlsl_ir_node *ddx = load->ddx.node; + struct hlsl_ir_node *ddy = load->ddy.node; unsigned int sampler_offset, reg_id; struct sm1_instruction sm1_instr; @@ -2613,6 +2615,20 @@ static void write_sm1_resource_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_ sm1_instr.opcode |= VKD3DSI_TEXLD_BIAS << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; break; + case HLSL_RESOURCE_SAMPLE_GRAD: + sm1_instr.opcode = D3DSIO_TEXLDD; + + sm1_instr.srcs[2].type = D3DSPR_TEMP; + sm1_instr.srcs[2].reg = ddx->reg.id; + sm1_instr.srcs[2].swizzle = hlsl_swizzle_from_writemask(ddx->reg.writemask); + + sm1_instr.srcs[3].type = D3DSPR_TEMP; + sm1_instr.srcs[3].reg = ddy->reg.id; + sm1_instr.srcs[3].swizzle = hlsl_swizzle_from_writemask(ddy->reg.writemask); + + sm1_instr.src_count += 2; + break; + default: hlsl_fixme(ctx, &instr->loc, "Resource load type %u.", load->load_type); return; diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2dfb9f58..da3b1b1e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4279,6 +4279,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx, static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc, const char *name, enum hlsl_sampler_dim dim) { + unsigned int sampler_dim = hlsl_sampler_dim_count(dim); struct hlsl_resource_load_params load_params = { 0 }; const struct hlsl_type *sampler_type; struct hlsl_ir_node *coords, *sample; @@ -4290,11 +4291,6 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * return false; } - if (params->args_count == 4) - { - hlsl_fixme(ctx, loc, "Samples with gradients are not implemented."); - } - sampler_type = params->args[0]->data_type; if (sampler_type->class != HLSL_CLASS_SAMPLER || (sampler_type->sampler_dim != dim && sampler_type->sampler_dim != HLSL_SAMPLER_DIM_GENERIC)) @@ -4318,12 +4314,12 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * else load_params.type = HLSL_RESOURCE_SAMPLE_LOD_BIAS; - if (!(c = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(X, Y, Z, W), hlsl_sampler_dim_count(dim), params->args[1], loc))) + if (!(c = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(X, Y, Z, W), sampler_dim, params->args[1], loc))) return false; hlsl_block_add_instr(params->instrs, c); - if (!(coords = add_implicit_conversion(ctx, params->instrs, c, hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, - hlsl_sampler_dim_count(dim)), loc))) + if (!(coords = add_implicit_conversion(ctx, params->instrs, c, + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) { return false; } @@ -4350,14 +4346,13 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * if (hlsl_version_ge(ctx, 4, 0)) { - unsigned int count = hlsl_sampler_dim_count(dim); struct hlsl_ir_node *divisor; - if (!(divisor = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(W, W, W, W), count, coords, loc))) + if (!(divisor = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(W, W, W, W), sampler_dim, coords, loc))) return false; hlsl_block_add_instr(params->instrs, divisor); - if (!(coords = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(X, Y, Z, W), count, coords, loc))) + if (!(coords = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(X, Y, Z, W), sampler_dim, coords, loc))) return false; hlsl_block_add_instr(params->instrs, coords); @@ -4371,12 +4366,34 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * load_params.type = HLSL_RESOURCE_SAMPLE_PROJ; } } + else if (params->args_count == 4) /* Gradient sampling. */ + { + if (!(coords = add_implicit_conversion(ctx, params->instrs, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + { + return false; + } + + if (!(load_params.ddx = add_implicit_conversion(ctx, params->instrs, params->args[2], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + { + return false; + } + + if (!(load_params.ddy = add_implicit_conversion(ctx, params->instrs, params->args[3], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + { + return false; + } + + load_params.type = HLSL_RESOURCE_SAMPLE_GRAD; + } else { load_params.type = HLSL_RESOURCE_SAMPLE; if (!(coords = add_implicit_conversion(ctx, params->instrs, params->args[1], - hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, hlsl_sampler_dim_count(dim)), loc))) + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) { return false; } diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e0d6e5dd..33845b0d 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2565,11 +2565,11 @@ static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *in case HLSL_RESOURCE_RESINFO: case HLSL_RESOURCE_SAMPLE_CMP: case HLSL_RESOURCE_SAMPLE_CMP_LZ: - case HLSL_RESOURCE_SAMPLE_GRAD: case HLSL_RESOURCE_SAMPLE_INFO: return false; case HLSL_RESOURCE_SAMPLE: + case HLSL_RESOURCE_SAMPLE_GRAD: case HLSL_RESOURCE_SAMPLE_LOD: case HLSL_RESOURCE_SAMPLE_LOD_BIAS: case HLSL_RESOURCE_SAMPLE_PROJ: diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 5f99be63..e5432cb3 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1899,13 +1899,42 @@ static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_pr ins->src_count = 3; break; + case VKD3DSIH_TEXLDD: + if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(srcs, 0, sizeof(*srcs) * 5); + + ins->opcode = VKD3DSIH_SAMPLE_GRAD; + + srcs[0] = ins->src[0]; + + srcs[1].reg.type = VKD3DSPR_RESOURCE; + srcs[1].reg.idx[0] = ins->src[1].reg.idx[0]; + srcs[1].reg.idx[1] = ins->src[1].reg.idx[0]; + srcs[1].reg.idx_count = 2; + srcs[1].reg.data_type = VKD3D_DATA_RESOURCE; + srcs[1].reg.dimension = VSIR_DIMENSION_VEC4; + srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; + + srcs[2].reg.type = VKD3DSPR_SAMPLER; + srcs[2].reg.idx[0] = ins->src[1].reg.idx[0]; + srcs[2].reg.idx[1] = ins->src[1].reg.idx[0]; + srcs[2].reg.idx_count = 2; + srcs[2].reg.data_type = VKD3D_DATA_SAMPLER; + + srcs[3] = ins->src[2]; + srcs[4] = ins->src[3]; + + ins->src = srcs; + ins->src_count = 5; + break; + case VKD3DSIH_TEXBEM: case VKD3DSIH_TEXBEML: case VKD3DSIH_TEXCOORD: case VKD3DSIH_TEXDEPTH: case VKD3DSIH_TEXDP3: case VKD3DSIH_TEXDP3TEX: - case VKD3DSIH_TEXLDD: case VKD3DSIH_TEXLDL: case VKD3DSIH_TEXM3x2PAD: case VKD3DSIH_TEXM3x2TEX: diff --git a/tests/hlsl/sample-grad.shader_test b/tests/hlsl/sample-grad.shader_test index aa77d248..c51e7cac 100644 --- a/tests/hlsl/sample-grad.shader_test +++ b/tests/hlsl/sample-grad.shader_test @@ -1,5 +1,6 @@ [require] -shader model >= 4.0 +shader model >= 3.0 +options: backcompat [sampler 0] filter linear linear linear @@ -14,6 +15,29 @@ levels 2 0.0 0.0 1.0 0.0 +[pixel shader fail(sm>=6)] +sampler s; +float4 grad; + +float4 main() : sv_target +{ + return tex2D(s, float2(0.5, 0.5), grad.xy, grad.zw); +} + +[test] +uniform 0 float4 0.0 0.0 0.0 0.0 +todo(glsl) draw quad +probe (0,0) rgba (1.0, 0.0, 1.0, 0.0) +uniform 0 float4 1.0 1.0 1.0 1.0 +todo(glsl) draw quad +probe (0,0) rgba (0.0, 0.0, 1.0, 0.0) +uniform 0 float4 2.0 2.0 2.0 2.0 +todo(glsl) draw quad +probe (0,0) rgba (0.0, 0.0, 1.0, 0.0) + +[require] +shader model >= 4.0 + [pixel shader] sampler s; Texture2D t;