From a006d2568b7f8efb772736c7541fe6338446866b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20D=C3=B6singer?= Date: Fri, 31 Aug 2007 17:00:16 +0200 Subject: [PATCH] wined3d: Fix texdepth instruction. --- dlls/d3d9/tests/visual.c | 212 ++++++++++++++++++++++++++++++++++++++ dlls/wined3d/arb_program_shader.c | 26 +++++ dlls/wined3d/glsl_shader.c | 8 +- dlls/wined3d/pixelshader.c | 2 +- dlls/wined3d/wined3d_private.h | 1 + 5 files changed, 247 insertions(+), 2 deletions(-) diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index 16bb3d2c4b9..21f380963a9 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -2360,6 +2360,217 @@ static void texture_transform_flags_test(IDirect3DDevice9 *device) IDirect3DVertexDeclaration9_Release(decl2); } +static void texdepth_test(IDirect3DDevice9 *device) +{ + IDirect3DPixelShader9 *shader; + HRESULT hr; + const float texdepth_test_data1[] = { 0.25, 2.0, 0.0, 0.0}; + const float texdepth_test_data2[] = { 0.25, 0.5, 0.0, 0.0}; + const float texdepth_test_data3[] = {-1.00, 0.1, 0.0, 0.0}; + const float texdepth_test_data4[] = {-0.25, -0.5, 0.0, 0.0}; + const float texdepth_test_data5[] = { 1.00, -0.1, 0.0, 0.0}; + const float texdepth_test_data6[] = { 1.00, 0.5, 0.0, 0.0}; + const float texdepth_test_data7[] = { 0.50, 0.0, 0.0, 0.0}; + DWORD shader_code[] = { + 0xffff0104, /* ps_1_4 */ + 0x00000051, 0xa00f0001, 0x00000000, 0x00000000, 0x3f800000, 0x3f800000, /* def c1, 0, 0, 1, 1 */ + 0x00000001, 0x800f0005, 0xa0e40000, /* mov r5, c0 */ + 0x0000fffd, /* phase */ + 0x00000057, 0x800f0005, /* texdepth r5 */ + 0x00000001, 0x800f0000, 0xa0e40001, /* mov r0, c1 */ + 0x0000ffff /* end */ + }; + DWORD color; + float vertex[] = { + -1.0, -1.0, 0.0, + 1.0, -1.0, 1.0, + -1.0, 1.0, 0.0, + 1.0, 1.0, 1.0 + }; + + hr = IDirect3DDevice9_CreatePixelShader(device, shader_code, &shader); + ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffff00, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_TRUE); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, TRUE); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZFUNC, D3DCMP_ALWAYS); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ); + + /* Fill the depth buffer with a gradient */ + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + + /* Now perform the actual tests. Same geometry, but with the shader */ + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZFUNC, D3DCMP_GREATER); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, FALSE); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetPixelShader(device, shader); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader failed (%08x)\n", hr); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data1, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + color = getPixelColor(device, 158, 240); + ok(color == 0x000000ff, "Pixel 158(25%% - 2 pixel) has color %08x, expected 0x000000ff\n", color); + color = getPixelColor(device, 162, 240); + ok(color == 0x00ffffff, "Pixel 158(25%% + 2 pixel) has color %08x, expected 0x00ffffff\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffff00, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data2, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + color = getPixelColor(device, 318, 240); + ok(color == 0x000000ff, "Pixel 318(50%% - 2 pixel) has color %08x, expected 0x000000ff\n", color); + color = getPixelColor(device, 322, 240); + ok(color == 0x00ffff00, "Pixel 322(50%% + 2 pixel) has color %08x, expected 0x00ffff00\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data3, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + + color = getPixelColor(device, 1, 240); + ok(color == 0x00ff0000, "Pixel 1(0%% + 2 pixel) has color %08x, expected 0x00ff0000\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data4, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + color = getPixelColor(device, 318, 240); + ok(color == 0x000000ff, "Pixel 318(50%% - 2 pixel) has color %08x, expected 0x000000ff\n", color); + color = getPixelColor(device, 322, 240); + ok(color == 0x0000ff00, "Pixel 322(50%% + 2 pixel) has color %08x, expected 0x0000ff00\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffff00, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data5, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + + color = getPixelColor(device, 1, 240); + ok(color == 0x00ffff00, "Pixel 1(0%% + 2 pixel) has color %08x, expected 0x00ffff00\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data6, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + + color = getPixelColor(device, 638, 240); + ok(color == 0x000000ff, "Pixel 638(100%% + 2 pixel) has color %08x, expected 0x000000ff\n", color); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0); + + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 0, texdepth_test_data7, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, vertex, 3 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_EndScene(device); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + } + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_Present failed with %s\n", DXGetErrorString9(hr)); + + color = getPixelColor(device, 638, 240); + ok(color == 0x000000ff, "Pixel 638(100%% + 2 pixel) has color %08x, expected 0x000000ff\n", color); + + hr = IDirect3DDevice9_SetPixelShader(device, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader failed (%08x)\n", hr); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, TRUE); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); +} + START_TEST(visual) { IDirect3DDevice9 *device_ptr; @@ -2454,6 +2665,7 @@ START_TEST(visual) if (caps.PixelShaderVersion >= D3DPS_VERSION(1, 1)) { texbem_test(device_ptr); + texdepth_test(device_ptr); } else skip("No ps_1_1 support\n"); diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 5cbadc2a528..873d0e5b1a0 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -884,6 +884,32 @@ void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) { current_state->current_row = 0; } +void pshader_hw_texdepth(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + char dst_name[50]; + + /* texdepth has an implicit destination, the fragment depth value. It's only parameter, + * which is essentially an input, is the destiantion register because it is the first + * param. According to the msdn, this must be register r5, but let's keep it more flexible + * here + */ + pshader_get_register_name(arg->dst, dst_name); + + /* According to the msdn, the source register(must be r5) is unusable after + * the texdepth instruction, so we're free to modify it + */ + shader_addline(buffer, "MIN %s.g, %s.g, one.g;\n", dst_name, dst_name); + + /* How to deal with the special case dst_name.g == 0? if r != 0, then + * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct + * result. But if r = 0.0, then 0 * inf = 0, which is incorrect. + */ + shader_addline(buffer, "RCP %s.g, %s.g;\n", dst_name, dst_name); + shader_addline(buffer, "MUL TMP.x, %s.r, %s.g;\n", dst_name, dst_name); + shader_addline(buffer, "MIN TMP.x, TMP.x, one.r;\n", dst_name, dst_name); + shader_addline(buffer, "MAX result.depth, TMP.x, 0.0;\n", dst_name, dst_name); +} + /** Handles transforming all WINED3DSIO_M?x? opcodes for Vertex shaders to ARB_vertex_program codes */ void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) { diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 305ab2701fd..6dfa706fb67 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1733,7 +1733,13 @@ void pshader_glsl_texdepth(SHADER_OPCODE_ARG* arg) { shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); - shader_addline(arg->buffer, "gl_FragDepth = %s.x / %s.y;\n", dst_param.reg_name, dst_param.reg_name); + /* Tests show that texdepth never returns anything below 0.0, and that r5.y is clamped to 1.0. + * Negative input is accepted, -0.25 / -0.5 returns 0.5. GL should clamp gl_FragDepth to [0;1], but + * this doesn't always work, so clamp the results manually. Wether or not the x value is clamped at 1 + * too is irrelevant, since if x = 0, any y value < 1.0(and > 1.0 is not allowed) results in a result + * >= 1.0 or < 0.0 + */ + shader_addline(arg->buffer, "gl_FragDepth = (%s.y == 0.0) ? 1.0 : clamp((%s.x / min(%s.y, 1.0)), 0.0, 1.0);\n", dst_param.reg_name, dst_param.reg_name, dst_param.reg_name); } /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in GLSL: diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 55e9bf95cc1..140a7123225 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -238,7 +238,7 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { {WINED3DSIO_TEXM3x2DEPTH, "texm3x2depth", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x2depth, WINED3DPS_VERSION(1,3), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXDP3, "texdp3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texdp3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x3, "texm3x3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXDEPTH, "texdepth", GLNAME_REQUIRE_GLSL, 1, 1, NULL, pshader_glsl_texdepth, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_TEXDEPTH, "texdepth", NULL, 1, 1, pshader_hw_texdepth, pshader_glsl_texdepth, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_BEM, "bem", "undefined", 1, 3, pshader_hw_bem, pshader_glsl_bem, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_DSX, "dsx", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, {WINED3DSIO_DSY, "dsy", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e02aabb9f5d..a3969ad270c 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1785,6 +1785,7 @@ extern void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texdepth(SHADER_OPCODE_ARG* arg); /* ARB vertex shader prototypes */ extern void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg); -- 2.11.4.GIT