mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-12-15 08:03:30 -08:00
vkd3d-shader: Implement shader model 1.0-1.3 texture projection.
This commit is contained in:
committed by
Henri Verbeet
parent
44c80c60b8
commit
c50210f230
Notes:
Henri Verbeet
2025-11-20 18:37:00 +01:00
Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1814
@@ -221,6 +221,7 @@ vkd3d_shader_tests = \
|
||||
tests/hlsl/pow.shader_test \
|
||||
tests/hlsl/precise-modifier.shader_test \
|
||||
tests/hlsl/primitive-id.shader_test \
|
||||
tests/hlsl/ps1-projection.shader_test \
|
||||
tests/hlsl/ps1-sampler.shader_test \
|
||||
tests/hlsl/rasteriser-ordered-views.shader_test \
|
||||
tests/hlsl/rcp.shader_test \
|
||||
|
||||
@@ -1039,6 +1039,25 @@ enum vkd3d_shader_parameter_name
|
||||
VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_3,
|
||||
VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_4,
|
||||
VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_5,
|
||||
/**
|
||||
* A mask of projected textures.
|
||||
*
|
||||
* When this parameter is provided to a shader model 1.0-1.3 pixel shader,
|
||||
* for each nonzero bit of this mask, the corresponding texture will be
|
||||
* projected. That is, it will have its coordinates divided by their W
|
||||
* component before sampling.
|
||||
*
|
||||
* The default value is zero, i.e. no textures are projected.
|
||||
*
|
||||
* The data type for this parameter must be
|
||||
* VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32.
|
||||
*
|
||||
* Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this
|
||||
* version of vkd3d-shader.
|
||||
*
|
||||
* \since 1.19
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_PROJECTED_TEXTURE_MASK,
|
||||
|
||||
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
|
||||
};
|
||||
|
||||
@@ -1936,8 +1936,36 @@ static enum vkd3d_result vsir_program_lower_texldl(struct vsir_program *program,
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *ins)
|
||||
static bool is_texture_projected(const struct vsir_program *program,
|
||||
struct vkd3d_shader_message_context *message_context, unsigned int index)
|
||||
{
|
||||
const struct vkd3d_shader_parameter1 *parameter;
|
||||
|
||||
if (!(parameter = vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_PROJECTED_TEXTURE_MASK)))
|
||||
return false;
|
||||
|
||||
if (parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
|
||||
{
|
||||
vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
|
||||
"Unsupported projected texture mask parameter type %#x.", parameter->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32)
|
||||
{
|
||||
vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE,
|
||||
"Invalid projected texture mask parameter data type %#x.", parameter->data_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameter->u.immediate_constant.u.u32 & (1u << index);
|
||||
}
|
||||
|
||||
static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program,
|
||||
struct vsir_program_iterator *it, struct vkd3d_shader_message_context *message_context)
|
||||
{
|
||||
struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it);
|
||||
const struct vkd3d_shader_location location = ins->location;
|
||||
const struct vkd3d_shader_descriptor_info1 *sampler;
|
||||
unsigned int idx = ins->dst[0].reg.idx[0].offset;
|
||||
struct vkd3d_shader_src_param *srcs;
|
||||
@@ -1951,10 +1979,40 @@ static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, st
|
||||
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);
|
||||
srcs[0].reg.idx[0].offset = idx;
|
||||
srcs[0].reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
srcs[0].swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
if (is_texture_projected(program, message_context, idx))
|
||||
{
|
||||
struct vkd3d_shader_dst_param *dst = ins->dst;
|
||||
uint32_t coords = program->ssa_count++;
|
||||
|
||||
/* div sr0, t#, t#.w */
|
||||
|
||||
if (!vsir_program_iterator_insert_after(it, 1))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
ins = vsir_program_iterator_current(it);
|
||||
if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DIV, 1, 2))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
dst_param_init_ssa_float4(&ins->dst[0], coords);
|
||||
vsir_src_param_init(&ins->src[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1);
|
||||
ins->src[0].reg.idx[0].offset = idx;
|
||||
ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
ins->src[1] = ins->src[0];
|
||||
ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W);
|
||||
|
||||
ins = vsir_program_iterator_next(it);
|
||||
vsir_instruction_init(ins, &location, VSIR_OP_SAMPLE);
|
||||
ins->dst_count = 1;
|
||||
ins->dst = dst;
|
||||
src_param_init_ssa_float4(&srcs[0], coords);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsir_src_param_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1);
|
||||
srcs[0].reg.idx[0].offset = idx;
|
||||
srcs[0].reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
srcs[0].swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
}
|
||||
|
||||
vsir_src_param_init_resource(&srcs[1], idx, idx);
|
||||
vsir_src_param_init_sampler(&srcs[2], idx, idx);
|
||||
@@ -2082,6 +2140,7 @@ static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program,
|
||||
unsigned int idx = ins->dst[0].reg.idx[0].offset;
|
||||
uint32_t ssa_coords, ssa_luminance, ssa_sample;
|
||||
struct vkd3d_shader_src_param orig_coords;
|
||||
bool projected;
|
||||
|
||||
/* texbem t#, SRC
|
||||
* ->
|
||||
@@ -2097,6 +2156,11 @@ static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program,
|
||||
* mad srLUM.x, SRC.z, BUMP_LUMINANCE_SCALE#, BUMP_LUMINANCE_OFFSET#
|
||||
* mul t#, t#, srLUM.xxxx
|
||||
*
|
||||
* If projecting, we replace srCOORDS calculation with
|
||||
*
|
||||
* div srPROJ, t#, t#.w
|
||||
* bem srCOORDS.xy, srPROJ.xy, SRC
|
||||
*
|
||||
* Note that the t# destination will subsequently be turned into a temp. */
|
||||
|
||||
descriptor = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx);
|
||||
@@ -2115,7 +2179,8 @@ static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program,
|
||||
return VKD3D_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (!vsir_program_iterator_insert_after(it, is_texbeml ? 4 : 2))
|
||||
projected = is_texture_projected(program, message_context, idx);
|
||||
if (!vsir_program_iterator_insert_after(it, 2 + (is_texbeml ? 2 : 0) + (projected ? 1 : 0)))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
vsir_src_param_init(&orig_coords, VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1);
|
||||
@@ -2123,6 +2188,23 @@ static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program,
|
||||
orig_coords.reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
orig_coords.swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
|
||||
if (projected)
|
||||
{
|
||||
uint32_t ssa_proj = program->ssa_count++;
|
||||
|
||||
ins = vsir_program_iterator_current(it);
|
||||
if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DIV, 1, 2))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
dst_param_init_ssa_float4(&ins->dst[0], ssa_proj);
|
||||
ins->src[0] = orig_coords;
|
||||
ins->src[1] = ins->src[0];
|
||||
ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W);
|
||||
|
||||
src_param_init_ssa_float4(&orig_coords, ssa_proj);
|
||||
|
||||
vsir_program_iterator_next(it);
|
||||
}
|
||||
|
||||
if (!(ins = generate_bump_coords(program, it, idx, &orig_coords, &src[0], &location)))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
ssa_coords = ins->dst[0].reg.idx[0].offset;
|
||||
@@ -2290,7 +2372,7 @@ static enum vkd3d_result vsir_program_lower_d3dbc_instructions(struct vsir_progr
|
||||
break;
|
||||
|
||||
case VSIR_OP_TEX:
|
||||
ret = vsir_program_lower_tex(program, ins);
|
||||
ret = vsir_program_lower_tex(program, &it, message_context);
|
||||
break;
|
||||
|
||||
case VSIR_OP_TEXLD:
|
||||
|
||||
@@ -67,10 +67,15 @@ ffff0101 % ps_1_1
|
||||
|
||||
[test]
|
||||
bump 1 f32(0.1, 0.2, 0.3, 0.5) 2.0 0.3
|
||||
projected 1 disable
|
||||
draw quad
|
||||
% WARP transposes the matrix for TEXBEM/TEXBEML, but not for BEM.
|
||||
if(!warp) probe (250, 500) f32(0.58, 0.27, 0.73, 0.42) 32
|
||||
if(!warp) probe (750, 500) f32(0.47, 0.33, 0.67, 0.53) 16
|
||||
projected 1 enable
|
||||
draw quad
|
||||
if(!warp) probe (250, 500) f32(0.28, 0.47, 0.53, 0.72) 32
|
||||
if(!warp) probe (750, 500) f32(0.17, 0.53, 0.47, 0.83) 16
|
||||
|
||||
[pixel shader d3dbc-hex]
|
||||
% TODO: Convert to assembly.
|
||||
@@ -82,11 +87,16 @@ ffff0101 % ps_1_1
|
||||
|
||||
[test]
|
||||
bump 1 f32(0.1, 0.2, 0.3, 0.5) 2.0 0.3
|
||||
projected 1 disable
|
||||
draw quad
|
||||
% Besides transposing the matrix, WARP also uses the texcoord t1.z (0.4)
|
||||
% as a luminance factor, instead of the textured value t0.z (0.3 or 0.2).
|
||||
if(!warp) probe (250, 500) f32(0.522, 0.243, 0.657, 0.378) 32
|
||||
if(!warp) probe (750, 500) f32(0.329, 0.231, 0.469, 0.371) 16
|
||||
projected 1 enable
|
||||
draw quad
|
||||
if(!warp) probe (250, 500) f32(0.252, 0.423, 0.477, 0.648) 32
|
||||
if(!warp) probe (750, 500) f32(0.119, 0.371, 0.329, 0.581) 32
|
||||
|
||||
[pixel shader d3dbc-hex]
|
||||
% TODO: Convert to assembly.
|
||||
|
||||
62
tests/hlsl/ps1-projection.shader_test
Normal file
62
tests/hlsl/ps1-projection.shader_test
Normal file
@@ -0,0 +1,62 @@
|
||||
% Test for the D3DTTFF_* projected texture flags.
|
||||
|
||||
[require]
|
||||
shader model < 3.0
|
||||
|
||||
[sampler 0]
|
||||
filter point point point
|
||||
address clamp clamp clamp
|
||||
|
||||
[srv 0]
|
||||
size (2d, 5, 5)
|
||||
.0 .0 .0 .1 .1 .0 .0 .1 .2 .0 .0 .1 .3 .0 .0 .1 .4 .0 .0 .1
|
||||
.0 .1 .0 .1 .1 .1 .0 .1 .2 .1 .0 .1 .3 .1 .0 .1 .4 .1 .0 .1
|
||||
.0 .2 .0 .1 .1 .2 .0 .1 .2 .2 .0 .1 .3 .2 .0 .1 .4 .2 .0 .1
|
||||
.0 .3 .0 .1 .1 .3 .0 .1 .2 .3 .0 .1 .3 .3 .0 .1 .4 .3 .0 .1
|
||||
.0 .4 .0 .1 .1 .4 .0 .1 .2 .4 .0 .1 .3 .4 .0 .1 .4 .4 .0 .1
|
||||
|
||||
[vertex shader]
|
||||
void main(inout float4 pos : position, out float4 tex : texcoord)
|
||||
{
|
||||
tex = float4(1.2, 0.5, 4.0, 2.0);
|
||||
}
|
||||
|
||||
[pixel shader d3dbc-hex]
|
||||
% TODO: Convert to assembly or HLSL.
|
||||
ffff0101 % ps_1_1
|
||||
00000042 b00f0000 % tex t0
|
||||
00000001 800f0000 b0e40000 % mov r0, t0
|
||||
0000ffff % end
|
||||
|
||||
[test]
|
||||
projected 0 disable
|
||||
draw quad
|
||||
probe (0, 0) f32(0.4, 0.2, 0.0, 0.1)
|
||||
projected 0 enable
|
||||
draw quad
|
||||
probe (0, 0) f32(0.3, 0.1, 0.0, 0.1)
|
||||
|
||||
% Doesn't affect 1.4 or 2.0.
|
||||
[pixel shader d3dbc-hex]
|
||||
% TODO: Convert to assembly or HLSL.
|
||||
ffff0104 % ps_1_4
|
||||
00000042 800f0000 b0e40000 % texld r0, t0
|
||||
0000ffff % end
|
||||
|
||||
[test]
|
||||
projected 0 enable
|
||||
draw quad
|
||||
probe (0, 0) f32(0.4, 0.2, 0.0, 0.1)
|
||||
|
||||
[pixel shader]
|
||||
sampler sam;
|
||||
|
||||
float4 main(float2 tex : texcoord) : sv_target
|
||||
{
|
||||
return tex2D(sam, tex);
|
||||
}
|
||||
|
||||
[test]
|
||||
projected 0 enable
|
||||
draw quad
|
||||
probe (0, 0) f32(0.4, 0.2, 0.0, 0.1)
|
||||
@@ -765,8 +765,10 @@ static void parse_resource_directive(struct resource_params *resource, const cha
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (isspace(*line))
|
||||
++line;
|
||||
u.u = strtoul(line, &rest, 0);
|
||||
if (rest && *rest == '.')
|
||||
if (*line == '.' || (rest && *rest == '.'))
|
||||
u.f = strtof(line, &rest);
|
||||
|
||||
if (rest == line)
|
||||
@@ -1764,6 +1766,20 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
|
||||
else
|
||||
fatal_error("Invalid denorm mode '%s'.\n", line);
|
||||
}
|
||||
else if (match_string(line, "projected", &line))
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
index = strtoul(line, (char **)&rest, 10);
|
||||
if (rest == line || index >= 6)
|
||||
fatal_error("Malformed projection directive '%s'.\n", line);
|
||||
line = rest;
|
||||
|
||||
if (match_string(line, "enable", &line))
|
||||
runner->projected_texture_mask |= (1u << index);
|
||||
else
|
||||
runner->projected_texture_mask &= ~(1u << index);
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal_error("Unknown test directive '%s'.\n", line);
|
||||
|
||||
@@ -304,6 +304,7 @@ struct shader_runner
|
||||
float matrix[2][2];
|
||||
float luminance_scale, luminance_offset;
|
||||
} bump[8];
|
||||
uint8_t projected_texture_mask;
|
||||
|
||||
enum denorm_mode denorm_mode;
|
||||
|
||||
|
||||
@@ -651,6 +651,10 @@ static bool d3d9_runner_draw(struct shader_runner *r,
|
||||
hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVLOFFSET,
|
||||
float_to_int(runner->r.bump[i].luminance_offset));
|
||||
ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr);
|
||||
|
||||
hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_TEXTURETRANSFORMFLAGS,
|
||||
(runner->r.projected_texture_mask & (1u << i)) ? D3DTTFF_PROJECTED : 0);
|
||||
ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr);
|
||||
}
|
||||
|
||||
hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements, &vertex_declaration);
|
||||
|
||||
@@ -366,7 +366,7 @@ static bool compile_d3d_code(struct vulkan_shader_runner *runner,
|
||||
struct vkd3d_shader_varying_map varying_map[12];
|
||||
struct vkd3d_shader_resource_binding *binding;
|
||||
struct vkd3d_shader_compile_option options[2];
|
||||
struct vkd3d_shader_parameter1 parameters[40];
|
||||
struct vkd3d_shader_parameter1 parameters[41];
|
||||
unsigned int i;
|
||||
char *messages;
|
||||
int ret;
|
||||
@@ -609,6 +609,11 @@ static bool compile_d3d_code(struct vulkan_shader_runner *runner,
|
||||
parameters[34 + i].u.immediate_constant.u.f32 = runner->r.bump[i].luminance_offset;
|
||||
}
|
||||
|
||||
parameters[40].name = VKD3D_SHADER_PARAMETER_NAME_PROJECTED_TEXTURE_MASK;
|
||||
parameters[40].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[40].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32;
|
||||
parameters[40].u.immediate_constant.u.u32 = runner->r.projected_texture_mask;
|
||||
|
||||
parameter_info.parameter_count = ARRAY_SIZE(parameters);
|
||||
parameter_info.parameters = parameters;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user