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