Commit 8a3ef776 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: gl_FragCoord isn't exact.

parent c00c89eb
......@@ -6907,7 +6907,16 @@ static void vpos_register_test(IDirect3DDevice9 *device)
0x02000001, 0x800f0800, 0x80e40002, /* mov oC0, r2 */
0x0000ffff /* end */
};
IDirect3DPixelShader9 *shader;
const DWORD shader_frac_code[] = {
0xffff0300, /* ps_3_0 */
0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.0, 0.0, 0.0, 0.0 */
0x0200001f, 0x80000000, 0x90031000, /* dcl vPos.xy */
0x02000001, 0x800f0000, 0xa0e40000, /* mov r0, c0 */
0x02000013, 0x80030000, 0x90541000, /* frc r0.xy, vPos.xy */
0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
0x0000ffff /* end */
};
IDirect3DPixelShader9 *shader, *shader_frac;
IDirect3DSurface9 *surface = NULL, *backbuffer;
const float quad[] = {
-1.0, -1.0, 0.1, 0.0, 0.0,
......@@ -6923,6 +6932,8 @@ static void vpos_register_test(IDirect3DDevice9 *device)
ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_CreatePixelShader(device, shader_code, &shader);
ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader failed hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_CreatePixelShader(device, shader_frac_code, &shader_frac);
ok(hr == D3D_OK, "IDirect3DDevice9_CreatePixelShader failed hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetPixelShader(device, shader);
ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader failed hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ);
......@@ -6967,8 +6978,6 @@ static void vpos_register_test(IDirect3DDevice9 *device)
ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitiveUP failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_EndScene(device);
ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetRenderTarget(device, 0, backbuffer);
ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderTarget failed, hr=%s\n", DXGetErrorString9(hr));
}
hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, D3DLOCK_READONLY);
ok(hr == D3D_OK, "IDirect3DSurface9_LockRect failed, hr=%s\n", DXGetErrorString9(hr));
......@@ -6989,7 +6998,38 @@ static void vpos_register_test(IDirect3DDevice9 *device)
hr = IDirect3DSurface9_UnlockRect(surface);
ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect failed, hr=%s\n", DXGetErrorString9(hr));
/* Test the fraction value of vPos. This is tested with the offscreen target and not the backbuffer to
* have full control over the multisampling setting inside this test
*/
hr = IDirect3DDevice9_SetPixelShader(device, shader_frac);
ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader failed hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_BeginScene(device);
ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene failed hr=%s\n", DXGetErrorString9(hr));
if(SUCCEEDED(hr)) {
hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0, 0);
ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float) * 5);
ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitiveUP failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_EndScene(device);
ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed hr=%s\n", DXGetErrorString9(hr));
}
hr = IDirect3DDevice9_SetRenderTarget(device, 0, backbuffer);
ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderTarget failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, D3DLOCK_READONLY);
ok(hr == D3D_OK, "IDirect3DSurface9_LockRect failed, hr=%s\n", DXGetErrorString9(hr));
pos = (DWORD *) (((BYTE *) lr.pBits) + 14 * lr.Pitch + 14 * sizeof(DWORD));
color = *pos & 0x00ffffff;
ok(color == 0x00000000, "vPos fraction test has color 0x%08x, expected 0x00000000\n", color);
hr = IDirect3DSurface9_UnlockRect(surface);
ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect failed, hr=%s\n", DXGetErrorString9(hr));
hr = IDirect3DDevice9_SetPixelShader(device, NULL);
ok(hr == D3D_OK, "IDirect3DDevice9_SetPixelShader failed hr=%s\n", DXGetErrorString9(hr));
IDirect3DPixelShader9_Release(shader);
IDirect3DPixelShader9_Release(shader_frac);
if(surface) IDirect3DSurface9_Release(surface);
IDirect3DSurface9_Release(backbuffer);
}
......
......@@ -706,7 +706,21 @@ void shader_generate_glsl_declarations(
/* Start the main program */
shader_addline(buffer, "void main() {\n");
if(pshader && reg_maps->vpos) {
shader_addline(buffer, "vpos = vec4(0, ycorrection[0], 0, 0) + gl_FragCoord * vec4(1, ycorrection[1], 1, 1) - 0.5;\n");
/* DirectX apps expect integer values, while OpenGL drivers add approximately 0.5. This causes
* off-by-one problems as spotted by the vPos d3d9 visual test. Unfortunately the ATI cards do
* not add exactly 0.5, but rather something like 0.49999999 or 0.50000001, which still causes
* precision troubles when we just substract 0.5.
*
* To deal with that just floor() the position. This will eliminate the fraction on all cards.
*
* TODO: Test how that behaves with multisampling once we can enable multisampling in winex11.
*
* An advantage of floor is that it works even if the driver doesn't add 1/2. It is somewhat
* questionable if 1.5, 2.5, ... are the proper values to return in gl_FragCoord, even though
* coordinates specify the pixel centers instead of the pixel corners. This code will behave
* correctly on drivers that returns integer values.
*/
shader_addline(buffer, "vpos = floor(vec4(0, ycorrection[0], 0, 0) + gl_FragCoord * vec4(1, ycorrection[1], 1, 1));\n");
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment