From 6633c220b7f610b4264f78dad30297d1d98cbc4d Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Sat, 9 Aug 2025 13:09:17 -0500 Subject: [PATCH] tests: Add bump mapping tests. --- Makefile.am | 1 + tests/hlsl/bump.shader_test | 106 +++++++++++++++++++++++++++++++++++ tests/shader_runner.c | 34 +++++++++++ tests/shader_runner.h | 5 ++ tests/shader_runner_d3d9.c | 22 ++++++++ tests/shader_runner_vulkan.c | 20 ++++++- 6 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tests/hlsl/bump.shader_test diff --git a/Makefile.am b/Makefile.am index 3136915fb..6ddb828d8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -74,6 +74,7 @@ vkd3d_shader_tests = \ tests/hlsl/bitwise.shader_test \ tests/hlsl/bool-cast.shader_test \ tests/hlsl/bool-semantics.shader_test \ + tests/hlsl/bump.shader_test \ tests/hlsl/calculate-lod.shader_test \ tests/hlsl/cast-64-bit.shader_test \ tests/hlsl/cast-broadcast.shader_test \ diff --git a/tests/hlsl/bump.shader_test b/tests/hlsl/bump.shader_test new file mode 100644 index 000000000..dc4891476 --- /dev/null +++ b/tests/hlsl/bump.shader_test @@ -0,0 +1,106 @@ +% Tests for 1.x bump environment mapping instructions. + +% The main function of texbem/texbeml is to slightly perturb the texture +% coordinates. We could in theory test the perturbed texture coordinates simply +% by setting up a linear filter between two pixels and testing what value is +% returned, but unfortunately linear filtering doesn't actually have arbitrary +% precision between two given pixels, and in practice the precision can be low. +% Instead we'll need to use a large source texture. Since we can't feasibly +% specify that much data by hand, we set up an initial rendering pass to fill +% the source texture with the right values. + +[require] +shader model < 3.0 + +[rtv 0] +format r32g32b32a32-float +size (2d, 1000, 1000) + +[sampler 0] +filter point point point +address clamp clamp clamp + +[sampler 1] +filter linear linear linear +address clamp clamp clamp + +[srv 0] +size (2d, 2, 1) +0.1 0.2 0.3 0.4 0.4 0.3 0.2 0.1 + +[srv 1] +size (2d, 1000, 1000) + +[vertex shader] +void main(inout float4 pos : position, out float4 tex : texcoord) +{ + tex = (pos + 1) / 2; +} + +[pixel shader] +float4 main(float4 tex : texcoord) : color +{ + /* Compensate for the pixel center. */ + tex.x += (0.5 / 1000.0); + tex.y -= (0.5 / 1000.0); + return float4(tex.yx, 1.0 - tex.xy); +} + +[test] +draw quad +copy rtv 0 srv 1 + +[vertex shader] +void main(inout float4 pos : position, out float4 tex0 : texcoord, out float4 tex1 : texcoord1) +{ + tex0 = (pos + 1) / 2; + tex1 = float4(0.2, 0.3, 0.4, 0.5); +} + +[pixel shader d3dbc-hex] +% TODO: Convert to assembly. +ffff0101 % ps_1_1 +00000042 b00f0000 % tex t0 +00000043 b00f0001 b0e40000 % texbem t1, t0 +00000001 800f0000 b0e40001 % mov r0, t1 +0000ffff % end + +[test] +bump 1 f32(0.1, 0.2, 0.3, 0.5) 2.0 0.3 +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 + +[pixel shader d3dbc-hex] +% TODO: Convert to assembly. +ffff0101 % ps_1_1 +00000042 b00f0000 % tex t0 +00000044 b00f0001 b0e40000 % texbeml t1, t0 +00000001 800f0000 b0e40001 % mov r0, t1 +0000ffff % end + +[test] +bump 1 f32(0.1, 0.2, 0.3, 0.5) 2.0 0.3 +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 + +[pixel shader d3dbc-hex] +% TODO: Convert to assembly. +ffff0104 % ps_1_4 +00000051 a00f0000 3dcccccd 3e4ccccd 3e99999a 3ecccccd % def c0, 0.1, 0.2, 0.3, 0.4 +00000051 a00f0001 3e99999a 3ecccccd 3f000000 3f19999a % def c1, 0.3, 0.4, 0.5, 0.6 +00000001 800f0000 a0e40000 % mov r0, c0 +00000001 800f0001 a0e40001 % mov r1, c1 +% Note that NVidia will crash if we use c0/c1 directly here. +00000059 80030002 80e40001 80e40000 % bem r2.xy, r1, r0 +00000001 80030000 80e40002 % mov r0.xy, r2 +0000ffff % end + +[test] +bump 2 f32(0.2, 0.3, 0.5, 0.6) 2.0 0.3 +draw quad +probe (320, 240) f32(0.42, 0.55, 0.3, 0.4) 1 diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 57beb75e4..ce6844fd2 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1715,6 +1715,40 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) runner->viewport_count = max(runner->viewport_count, i + 1); } + else if (match_string(line, "bump", &line)) + { + struct bump_constants *c; + unsigned int index; + + index = strtoul(line, (char **)&rest, 10); + if (rest == line || index >= 6) + fatal_error("Malformed bump directive '%s'.\n", line); + line = rest; + + c = &runner->bump[index]; + + if (!match_string(line, "f32", &line)) + fatal_error("Malformed bump directive '%s'.\n", line); + if (*line != '(') + fatal_error("Malformed bump directive '%s'.\n", line); + ++line; + read_f32(&line, &c->matrix[0][0]); + if (!match_string(line, ",", &line)) + fatal_error("Malformed bump directive '%s'.\n", line); + read_f32(&line, &c->matrix[0][1]); + if (!match_string(line, ",", &line)) + fatal_error("Malformed bump directive '%s'.\n", line); + read_f32(&line, &c->matrix[1][0]); + if (!match_string(line, ",", &line)) + fatal_error("Malformed bump directive '%s'.\n", line); + read_f32(&line, &c->matrix[1][1]); + if (*line != ')') + fatal_error("Malformed bump directive '%s'.\n", line); + ++line; + + read_f32(&line, &c->luminance_scale); + read_f32(&line, &c->luminance_offset); + } else { fatal_error("Unknown test directive '%s'.\n", line); diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 03bf99b57..1c1d1730b 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -286,6 +286,11 @@ struct shader_runner enum fog_mode fog_mode; float fog_start, fog_end, fog_density; bool ortho_fog; + struct bump_constants + { + float matrix[2][2]; + float luminance_scale, luminance_offset; + } bump[8]; struct viewport viewports[4]; unsigned int viewport_count; diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index 15983ce00..90c322a6d 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -631,6 +631,28 @@ static bool d3d9_runner_draw(struct shader_runner *r, hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGDENSITY, float_to_int(runner->r.fog_density)); ok(hr == D3D_OK, "Failed to set render state, hr %#lx.\n", hr); + for (unsigned int i = 0; i < 8; ++i) + { + hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVMAT00, + float_to_int(runner->r.bump[i].matrix[0][0])); + ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVMAT01, + float_to_int(runner->r.bump[i].matrix[0][1])); + ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVMAT10, + float_to_int(runner->r.bump[i].matrix[1][0])); + ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVMAT11, + float_to_int(runner->r.bump[i].matrix[1][1])); + ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, i, D3DTSS_BUMPENVLSCALE, + float_to_int(runner->r.bump[i].luminance_scale)); + ok(hr == D3D_OK, "Failed to set texture state, hr %#lx.\n", hr); + 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_CreateVertexDeclaration(device, decl_elements, &vertex_declaration); ok(hr == D3D_OK, "Failed to create vertex declaration, hr %#lx.\n", hr); hr = IDirect3DDevice9_CreateVertexShader(device, ID3D10Blob_GetBufferPointer(vs_code), &vs); diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 01d277814..f4b2ddf46 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -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[22]; + struct vkd3d_shader_parameter1 parameters[40]; unsigned int i; char *messages; int ret; @@ -591,6 +591,24 @@ static bool compile_d3d_code(struct vulkan_shader_runner *runner, parameters[21].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32; parameters[21].u.immediate_constant.u.u32 = get_fog_source(&runner->r); + for (i = 0; i < 6; ++i) + { + parameters[22 + i].name = VKD3D_SHADER_PARAMETER_NAME_BUMP_MATRIX_0 + i; + parameters[22 + i].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT; + parameters[22 + i].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4; + memcpy(parameters[22 + i].u.immediate_constant.u.f32_vec4, runner->r.bump[i].matrix, sizeof(struct vec4)); + + parameters[28 + i].name = VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_SCALE_0 + i; + parameters[28 + i].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT; + parameters[28 + i].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32; + parameters[28 + i].u.immediate_constant.u.f32 = runner->r.bump[i].luminance_scale; + + parameters[34 + i].name = VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_0 + i; + parameters[34 + i].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT; + parameters[34 + i].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32; + parameters[34 + i].u.immediate_constant.u.f32 = runner->r.bump[i].luminance_offset; + } + parameter_info.parameter_count = ARRAY_SIZE(parameters); parameter_info.parameters = parameters;