st/nine: Workaround barycentrics issue on some cards
authorAxel Davy <axel.davy@ens.fr>
Thu, 23 Apr 2015 19:46:09 +0000 (21:46 +0200)
committerAxel Davy <axel.davy@ens.fr>
Wed, 29 Apr 2015 06:28:10 +0000 (08:28 +0200)
Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/device9.c
src/gallium/state_trackers/nine/device9.h
src/gallium/state_trackers/nine/nine_state.c

index 43eb7e6397c2f70faab76249d1c46eaa3c0f3633..9ca1bb93597fc9f981623f2e6d138618566616df 100644 (file)
@@ -310,8 +310,10 @@ NineDevice9_ctor( struct NineDevice9 *This,
             return E_OUTOFMEMORY;
 
         if (strstr(pScreen->get_name(pScreen), "AMD") ||
-            strstr(pScreen->get_name(pScreen), "ATI"))
+            strstr(pScreen->get_name(pScreen), "ATI")) {
             This->prefer_user_constbuf = TRUE;
+            This->driver_bugs.buggy_barycentrics = TRUE;
+        }
 
         tmpl.target = PIPE_BUFFER;
         tmpl.format = PIPE_FORMAT_R8_UNORM;
index f412088ca08bfba642a4fff86ff563937df1457b..d662f839d88761e61e73bdc648ec5fb9a63e8519 100644 (file)
@@ -118,6 +118,10 @@ struct NineDevice9
         boolean ps_integer;
     } driver_caps;
 
+    struct {
+        boolean buggy_barycentrics;
+    } driver_bugs;
+
     struct u_upload_mgr *upload;
 
     struct nine_range_pool range_pool;
index 495cc862b2a8eae2c0b8e51d7eb68597d73c1c90..6c7eab3c25cad25bfbc28ab8fba5927cfaca2afd 100644 (file)
@@ -150,6 +150,30 @@ update_viewport(struct NineDevice9 *device)
     pvport.translate[1] = (float)vport->Height * 0.5f + (float)vport->Y;
     pvport.translate[2] = vport->MinZ;
 
+    /* We found R600 and SI cards have some imprecision
+     * on the barycentric coordinates used for interpolation.
+     * Some shaders rely on having something precise.
+     * We found that the proprietary driver has the imprecision issue,
+     * except when the render target width and height are powers of two.
+     * It is using some sort of workaround for these cases
+     * which covers likely all the cases the applications rely
+     * on something precise.
+     * We haven't found the workaround, but it seems like it's better
+     * for applications if the imprecision is biased towards infinity
+     * instead of -infinity (which is what measured). So shift slightly
+     * the viewport: not enough to change rasterization result (in particular
+     * for multisampling), but enough to make the imprecision biased
+     * towards infinity. We do this shift only if render target width and
+     * height are powers of two.
+     * Solves 'red shadows' bug on UE3 games.
+     */
+    if (device->driver_bugs.buggy_barycentrics &&
+        ((vport->Width & (vport->Width-1)) == 0) &&
+        ((vport->Height & (vport->Height-1)) == 0)) {
+        pvport.translate[0] -= 1.0f / 128.0f;
+        pvport.translate[1] -= 1.0f / 128.0f;
+    }
+
     pipe->set_viewport_states(pipe, 0, 1, &pvport);
 }