From 02114ac21f08b7a8bb60ccc71282ecf76a707a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Thu, 13 Sep 2007 14:48:57 +0200 Subject: [PATCH] wined3d: The D3DSI_COISSUE flag changes the behavior of cnd. --- dlls/d3d9/tests/visual.c | 162 +++++++++++++++++++++++++++++- dlls/wined3d/arb_program_shader.c | 11 +- dlls/wined3d/baseshader.c | 4 + dlls/wined3d/glsl_shader.c | 10 +- 4 files changed, 181 insertions(+), 6 deletions(-) diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index d75ae62906d..af64fbee2b0 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -3231,6 +3231,7 @@ static void constant_clamp_ps_test(IDirect3DDevice9 *device) static void cnd_test(IDirect3DDevice9 *device) { IDirect3DPixelShader9 *shader_11, *shader_12, *shader_13, *shader_14; + IDirect3DPixelShader9 *shader_11_coissue, *shader_12_coissue, *shader_13_coissue, *shader_14_coissue; HRESULT hr; DWORD color; /* ps 1.x shaders are rather picky with writemasks and source swizzles. The dp3 is @@ -3247,7 +3248,6 @@ static void cnd_test(IDirect3DDevice9 *device) 0x00000050, 0x800f0000, 0x80ff0000, 0xa0e40001, 0xa0e40002, /* cnd r0, r0.a, c1, c2 */ 0x0000ffff /* end */ }; - DWORD shader_code_12[] = { 0xffff0102, /* ps_1_2 */ 0x00000051, 0xa00f0000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 1, 0, 0, 0 */ @@ -3258,7 +3258,6 @@ static void cnd_test(IDirect3DDevice9 *device) 0x00000050, 0x800f0000, 0x80ff0000, 0xa0e40001, 0xa0e40002, /* cnd r0, r0.a, c1, c2 */ 0x0000ffff /* end */ }; - DWORD shader_code_13[] = { 0xffff0103, /* ps_1_3 */ 0x00000051, 0xa00f0000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 1, 0, 0, 0 */ @@ -3277,6 +3276,72 @@ static void cnd_test(IDirect3DDevice9 *device) 0x00000050, 0x800f0000, 0x80e40000, 0xa0e40001, 0xa0e40002, /* cnd r0, r0, c1, c2 */ 0x0000ffff /* end */ }; + + /* Special fun: The coissue flag on cnd: Apparently cnd always selects the 2nd source, + * as if the src0 comparison against 0.5 always evaluates to true. The coissue flag isn't + * set by the compiler, it was added manually after compilation. It isn't always allowed, + * only if there's a mov r0.a, XXXX, and the cnd instruction writes to r0.xyz, otherwise + * native CreatePixelShader returns an error. + * + * The shader attempts to test the range [-1;1] against coissued cnd, which is a bit tricky. + * The input from t0 is [0;1]. 0.5 is substracted, then we have to multiply with 2. Since + * constants are clamped to [-1;1], a 2.0 is constructed by adding c0.r(=1.0) to c0.r into r1.r, + * then r1(2.0, 0.0, 0.0, 0.0) is passed to dp3(explained above). + */ + DWORD shader_code_11_coissue[] = { + 0xffff0101, /* ps_1_1 */ + 0x00000051, 0xa00f0000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 1, 0, 0, 0 */ + 0x00000051, 0xa00f0003, 0x3f000000, 0x3f000000, 0x3f000000, 0x00000000, /* def c3, 0.5, 0.5, 0.5, 0 */ + 0x00000040, 0xb00f0000, /* texcoord t0 */ + 0x00000001, 0x800f0000, 0xb0e40000, /* mov r0, t0 */ + 0x00000003, 0x800f0000, 0x80e40000, 0xa0e40003, /* sub r0, r0, c3 */ + 0x00000002, 0x800f0001, 0xa0e40000, 0xa0e40000, /* add r1, c0, c0 */ + 0x00000008, 0x800f0001, 0x80e40000, 0x80e40001, /* dp3, r1, r0, r1 */ + 0x00000001, 0x80080000, 0x80ff0001, /* mov r0.a, r1.a */ + /* 0x40000000 = D3DSI_COISSUE */ + 0x40000050, 0x80070000, 0x80ff0000, 0xa0e40001, 0xa0e40002, /* cnd r0.xyz, r0.a, c1, c2 */ + 0x0000ffff /* end */ + }; + DWORD shader_code_12_coissue[] = { + 0xffff0102, /* ps_1_2 */ + 0x00000051, 0xa00f0000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 1, 0, 0, 0 */ + 0x00000051, 0xa00f0003, 0x3f000000, 0x3f000000, 0x3f000000, 0x00000000, /* def c3, 0.5, 0.5, 0.5, 0 */ + 0x00000040, 0xb00f0000, /* texcoord t0 */ + 0x00000001, 0x800f0000, 0xb0e40000, /* mov r0, t0 */ + 0x00000003, 0x800f0000, 0x80e40000, 0xa0e40003, /* sub r0, r0, c3 */ + 0x00000002, 0x800f0001, 0xa0e40000, 0xa0e40000, /* add r1, c0, c0 */ + 0x00000008, 0x800f0001, 0x80e40000, 0x80e40001, /* dp3, r1, r0, r1 */ + 0x00000001, 0x80080000, 0x80ff0001, /* mov r0.a, r1.a */ + /* 0x40000000 = D3DSI_COISSUE */ + 0x40000050, 0x80070000, 0x80ff0000, 0xa0e40001, 0xa0e40002, /* cnd r0.xyz, r0.a, c1, c2 */ + 0x0000ffff /* end */ + }; + DWORD shader_code_13_coissue[] = { + 0xffff0103, /* ps_1_3 */ + 0x00000051, 0xa00f0000, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 1, 0, 0, 0 */ + 0x00000051, 0xa00f0003, 0x3f000000, 0x3f000000, 0x3f000000, 0x00000000, /* def c3, 0.5, 0.5, 0.5, 0 */ + 0x00000040, 0xb00f0000, /* texcoord t0 */ + 0x00000001, 0x800f0000, 0xb0e40000, /* mov r0, t0 */ + 0x00000003, 0x800f0000, 0x80e40000, 0xa0e40003, /* sub r0, r0, c3 */ + 0x00000002, 0x800f0001, 0xa0e40000, 0xa0e40000, /* add r1, c0, c0 */ + 0x00000008, 0x800f0001, 0x80e40000, 0x80e40001, /* dp3, r1, r0, r1 */ + 0x00000001, 0x80080000, 0x80ff0001, /* mov r0.a, r1.a */ + /* 0x40000000 = D3DSI_COISSUE */ + 0x40000050, 0x80070000, 0x80ff0000, 0xa0e40001, 0xa0e40002, /* cnd r0.xyz, r0.a, c1, c2 */ + 0x0000ffff /* end */ + }; + /* ps_1_4 does not have a different cnd behavior, just pass the [0;1] texcrd result to cnd, it will + * compare against 0.5 + */ + DWORD shader_code_14_coissue[] = { + 0xffff0104, /* ps_1_4 */ + 0x00000051, 0xa00f0000, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, /* def c0, 0, 0, 0, 1 */ + 0x00000040, 0x80070000, 0xb0e40000, /* texcrd r0, t0 */ + 0x00000001, 0x80080000, 0xa0ff0000, /* mov r0.a, c0.a */ + /* 0x40000000 = D3DSI_COISSUE */ + 0x40000050, 0x80070000, 0x80e40000, 0xa0e40001, 0xa0e40002, /* cnd r0.xyz, r0, c1, c2 */ + 0x0000ffff /* end */ + }; float quad1[] = { -1.0, -1.0, 0.1, 0.0, 0.0, 1.0, 0.0, -1.0, 0.1, 1.0, 0.0, 1.0, @@ -3303,6 +3368,8 @@ static void cnd_test(IDirect3DDevice9 *device) }; float test_data_c1[4] = { 0.0, 0.0, 0.0, 0.0}; float test_data_c2[4] = { 1.0, 1.0, 1.0, 1.0}; + float test_data_c1_coi[4] = { 0.0, 1.0, 0.0, 0.0}; + float test_data_c2_coi[4] = { 1.0, 0.0, 1.0, 1.0}; hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ffff, 0.0, 0); ok(hr == D3D_OK, "IDirect3DDevice9_Clear returned %s\n", DXGetErrorString9(hr)); @@ -3315,6 +3382,14 @@ static void cnd_test(IDirect3DDevice9 *device) ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); hr = IDirect3DDevice9_CreatePixelShader(device, shader_code_14, &shader_14); ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreatePixelShader(device, shader_code_11_coissue, &shader_11_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreatePixelShader(device, shader_code_12_coissue, &shader_12_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreatePixelShader(device, shader_code_13_coissue, &shader_13_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreatePixelShader(device, shader_code_14_coissue, &shader_14_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader returned %s\n", DXGetErrorString9(hr)); hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 1, test_data_c1, 1); ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); @@ -3396,6 +3471,89 @@ static void cnd_test(IDirect3DDevice9 *device) color = getPixelColor(device, 482, 122); ok(color == 0x00000000, "pixel 482, 122 has color %08x, expected 0x00000000\n", color); + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff00ffff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 1, test_data_c1_coi, 1); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShaderConstantF returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetPixelShaderConstantF(device, 2, test_data_c2_coi, 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_SetPixelShader(device, shader_11_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad1, 6 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_SetPixelShader(device, shader_12_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad2, 6 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_SetPixelShader(device, shader_13_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad3, 6 * sizeof(float)); + ok(hr == D3D_OK, "DrawPrimitiveUP failed (%08x)\n", hr); + + hr = IDirect3DDevice9_SetPixelShader(device, shader_14_coissue); + ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad4, 6 * 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)); + + /* This is the 1.4 test. The coissue doesn't change the behavior here, but keep in mind + * that we swapped the values in c1 and c2 to make the other tests return some color + */ + color = getPixelColor(device, 158, 118); + ok(color == 0x00ffffff, "pixel 158, 118 has color %08x, expected 0x00ffffff\n", color); + color = getPixelColor(device, 162, 118); + ok(color == 0x0000ffff, "pixel 162, 118 has color %08x, expected 0x0000ffff\n", color); + color = getPixelColor(device, 158, 122); + ok(color == 0x00ff00ff, "pixel 162, 122 has color %08x, expected 0x00ff00ff\n", color); + color = getPixelColor(device, 162, 122); + ok(color == 0x000000ff, "pixel 162, 122 has color %08x, expected 0x000000ff\n", color); + + /* 1.1 shader. coissue flag changed the semantic of cnd, c1 is always selected */ + color = getPixelColor(device, 158, 358); + ok(color == 0x0000ff00, "pixel 158, 358 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 162, 358); + ok(color == 0x0000ff00, "pixel 162, 358 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 158, 362); + ok(color == 0x0000ff00, "pixel 158, 362 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 162, 362); + ok(color == 0x0000ff00, "pixel 162, 362 has color %08x, expected 0x0000ff00\n", color); + + /* 1.2 shader */ + color = getPixelColor(device, 478, 358); + ok(color == 0x0000ff00, "pixel 478, 358 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 482, 358); + ok(color == 0x0000ff00, "pixel 482, 358 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 478, 362); + ok(color == 0x0000ff00, "pixel 478, 362 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 482, 362); + ok(color == 0x0000ff00, "pixel 482, 362 has color %08x, expected 0x0000ff00\n", color); + + /* 1.3 shader */ + color = getPixelColor(device, 478, 118); + ok(color == 0x0000ff00, "pixel 478, 118 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 482, 118); + ok(color == 0x0000ff00, "pixel 482, 118 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 478, 122); + ok(color == 0x0000ff00, "pixel 478, 122 has color %08x, expected 0x0000ff00\n", color); + color = getPixelColor(device, 482, 122); + ok(color == 0x0000ff00, "pixel 482, 122 has color %08x, expected 0x0000ff00\n", color); + + IDirect3DPixelShader9_Release(shader_14_coissue); + IDirect3DPixelShader9_Release(shader_13_coissue); + IDirect3DPixelShader9_Release(shader_12_coissue); + IDirect3DPixelShader9_Release(shader_11_coissue); IDirect3DPixelShader9_Release(shader_14); IDirect3DPixelShader9_Release(shader_13); IDirect3DPixelShader9_Release(shader_12); diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 7f89bf9bdda..7b851de41b4 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -572,6 +572,7 @@ void pshader_hw_bem(SHADER_OPCODE_ARG* arg) { void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; SHADER_BUFFER* buffer = arg->buffer; char dst_wmask[20]; char dst_name[50]; @@ -589,8 +590,14 @@ void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) { pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); - shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]); - shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]); + /* The coissue flag changes the semantic of the cnd instruction in <= 1.3 shaders */ + if (shader->baseShader.hex_version <= WINED3DPS_VERSION(1, 3) && + arg->opcode_token & WINED3DSI_COISSUE) { + shader_addline(buffer, "MOV %s, %s;\n", dst_name, src_name[1]); + } else { + shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]); + shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]); + } } void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) { diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 01ccbdc41d7..d04a2e667a8 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -949,6 +949,10 @@ void shader_trace_init( shader_dump_param(iface, *(pToken + 2), 0, 1); TRACE(") "); } + if (opcode_token & WINED3DSI_COISSUE) { + /* PixWin marks instructions with the coissue flag with a '+' */ + TRACE("+"); + } TRACE("%s", curOpcode->name); diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index f36884c8914..f1990195a54 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1303,8 +1303,14 @@ void shader_glsl_cnd(SHADER_OPCODE_ARG* arg) { shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); - shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", - src0_param.param_str, src1_param.param_str, src2_param.param_str); + + /* Fun: The D3DSI_COISSUE flag changes the semantic of the cnd instruction for < 1.4 shaders */ + if(arg->opcode_token & WINED3DSI_COISSUE) { + shader_addline(arg->buffer, "%s /* COISSUE! */);\n", src1_param.param_str); + } else { + shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); + } return; } /* Cycle through all source0 channels */