Stefan Dösinger : wined3d: gl_FragCoord isn't exact.
Alexandre Julliard
julliard at winehq.org
Fri Mar 7 05:30:12 CST 2008
Module: wine
Branch: master
Commit: 8a3ef776f4f411172c5bfcc634f358dbedbc7479
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8a3ef776f4f411172c5bfcc634f358dbedbc7479
Author: Stefan Dösinger <stefan at codeweavers.com>
Date: Fri Mar 7 03:13:07 2008 +0100
wined3d: gl_FragCoord isn't exact.
---
dlls/d3d9/tests/visual.c | 46 +++++++++++++++++++++++++++++++++++++++++--
dlls/wined3d/glsl_shader.c | 16 ++++++++++++++-
2 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 6b70a02..280e92d 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -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);
}
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 61b21fa..5a0b7c5 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -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");
}
}
More information about the wine-cvs
mailing list