diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 78b9b1537..df1f5d525 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -2350,6 +2350,26 @@ struct vkd3d_shader_d3dbc_source_info * This field is ignored for shader models 2 and higher. */ enum vkd3d_shader_resource_type texture_dimensions[6]; + + /** + * A mask indicating which samplers should be shadow (i.e. comparison-mode) + * samplers. When legacy Direct3D shaders are used with the Direct3D 8 and 9 + * APIs, this is implied by the format of the sampled resource; e.g. a + * D3DFMT_D24S8 texture implies shadow sampling, while a D3DFMT_A8R8G8B8 + * or D3DFMT_INTZ texture does not. + * This information is necessary when converting to other formats + * (e.g. SPIR-V, GLSL) which specify this in the shader. + * + * For example, if bit 1 is set (so the value is 0x2), this indicates that + * the sampler at bind point 1 (and no others) should be a shadow sampler. + * + * Bits in this mask corresponding to textures not used by the shader will + * be ignored. + * + * If this structure is not specified, no samplers will be considered to + * be shadow samplers. + */ + uint32_t shadow_samplers; }; /** diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 7812efa72..b2d4ec23c 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -946,17 +946,21 @@ static void d3dbc_add_combined_sampler_descriptor(struct vkd3d_shader_sm1_parser unsigned int sampler_idx, enum vkd3d_shader_resource_type resource_type) { struct vkd3d_shader_register_range range = {.first = sampler_idx, .last = sampler_idx}; + const struct vkd3d_shader_d3dbc_source_info *source_info = d3dbc->d3dbc_source_info; struct vsir_program *program = d3dbc->program; + struct vkd3d_shader_descriptor_info1 *d; if (!vsir_program_add_descriptor(program, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, sampler_idx, &range, resource_type, VSIR_DATA_F32)) vkd3d_shader_parser_error(&d3dbc->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Failed to create SRV descriptor for combined sampler %u.", sampler_idx); - if (!vsir_program_add_descriptor(program, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, - sampler_idx, &range, VKD3D_SHADER_RESOURCE_NONE, VSIR_DATA_UNUSED)) + if (!(d = vsir_program_add_descriptor(program, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, + sampler_idx, &range, VKD3D_SHADER_RESOURCE_NONE, VSIR_DATA_UNUSED))) vkd3d_shader_parser_error(&d3dbc->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Failed to create sampler descriptor for combined sampler %u.", sampler_idx); + else if (source_info && source_info->shadow_samplers & (1u << sampler_idx)) + d->flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE; } /* Read a parameter token from the input stream, and possibly a relative diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index a5e209ffa..2ba11d9de 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1680,6 +1680,7 @@ static enum vkd3d_result vsir_program_lower_texcrd(struct vsir_program *program, static enum vkd3d_result vsir_program_lower_texld_sm1(struct vsir_program *program, struct vkd3d_shader_instruction *ins, struct vkd3d_shader_message_context *message_context) { + const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = ins->src[0].reg.idx[0].offset; struct vkd3d_shader_src_param *srcs; @@ -1692,7 +1693,7 @@ static enum vkd3d_result vsir_program_lower_texld_sm1(struct vsir_program *progr return VKD3D_ERROR_NOT_IMPLEMENTED; } - if (!(srcs = vsir_program_get_src_params(program, 3))) + if (!(srcs = vsir_program_get_src_params(program, 4))) return VKD3D_ERROR_OUT_OF_MEMORY; /* Note we run before I/O normalization. */ @@ -1700,9 +1701,26 @@ static enum vkd3d_result vsir_program_lower_texld_sm1(struct vsir_program *progr vsir_src_param_init_resource(&srcs[1], idx, idx); vsir_src_param_init_sampler(&srcs[2], idx, idx); - ins->opcode = VSIR_OP_SAMPLE; - ins->src = srcs; - ins->src_count = 3; + sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); + if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) + { + enum vkd3d_shader_swizzle_component ref = vsir_swizzle_get_component(srcs[0].swizzle, 2); + + ins->opcode = VSIR_OP_SAMPLE_C; + ins->src = srcs; + ins->src_count = 4; + + srcs[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + srcs[3] = srcs[0]; + srcs[3].swizzle = vkd3d_shader_create_swizzle(ref, ref, ref, ref); + } + else + { + ins->opcode = VSIR_OP_SAMPLE; + ins->src = srcs; + ins->src_count = 3; + } return VKD3D_OK; } @@ -1762,6 +1780,7 @@ static enum vkd3d_result vsir_program_lower_texldp(struct vsir_program *program, static enum vkd3d_result vsir_program_lower_texld(struct vsir_program *program, struct vkd3d_shader_instruction *tex, struct vkd3d_shader_message_context *message_context) { + const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = tex->src[1].reg.idx[0].offset; struct vkd3d_shader_src_param *srcs; @@ -1775,7 +1794,21 @@ static enum vkd3d_result vsir_program_lower_texld(struct vsir_program *program, vsir_src_param_init_resource(&srcs[1], idx, idx); vsir_src_param_init_sampler(&srcs[2], idx, idx); - if (!tex->flags) + sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); + if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) + { + enum vkd3d_shader_swizzle_component ref = vsir_swizzle_get_component(srcs[0].swizzle, 2); + + tex->opcode = VSIR_OP_SAMPLE_C; + tex->src = srcs; + tex->src_count = 4; + + srcs[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + srcs[3] = srcs[0]; + srcs[3].swizzle = vkd3d_shader_create_swizzle(ref, ref, ref, ref); + } + else if (!tex->flags) { tex->opcode = VSIR_OP_SAMPLE; tex->src = srcs; @@ -1857,6 +1890,7 @@ static enum vkd3d_result vsir_program_lower_texldl(struct vsir_program *program, static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *ins) { + const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = ins->dst[0].reg.idx[0].offset; struct vkd3d_shader_src_param *srcs; @@ -1866,7 +1900,7 @@ static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, st /* We run before I/O normalization. */ VKD3D_ASSERT(program->normalisation_level < VSIR_NORMALISED_SM6); - if (!(srcs = vsir_program_get_src_params(program, 3))) + if (!(srcs = vsir_program_get_src_params(program, 4))) return VKD3D_ERROR_OUT_OF_MEMORY; vsir_src_param_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); @@ -1877,9 +1911,24 @@ static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, st vsir_src_param_init_resource(&srcs[1], idx, idx); vsir_src_param_init_sampler(&srcs[2], idx, idx); - ins->opcode = VSIR_OP_SAMPLE; - ins->src = srcs; - ins->src_count = 3; + sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); + if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) + { + ins->opcode = VSIR_OP_SAMPLE_C; + ins->src = srcs; + ins->src_count = 4; + + srcs[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + srcs[3] = srcs[0]; + srcs[3].swizzle = VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z); + } + else + { + ins->opcode = VSIR_OP_SAMPLE; + ins->src = srcs; + ins->src_count = 3; + } return VKD3D_OK; }