summaryrefslogtreecommitdiffstats
path: root/src/gallium/state_trackers
diff options
context:
space:
mode:
authorAxel Davy <[email protected]>2015-04-23 21:46:09 +0200
committerAxel Davy <[email protected]>2015-04-29 08:28:10 +0200
commit6e825b69bd4fb163cba0a565616ed966fb1a8929 (patch)
tree53a71d1e26160551677e044ca9202368873f5e63 /src/gallium/state_trackers
parentf3fd06e94d29172a5de68594d3a6433f91a41362 (diff)
st/nine: Workaround barycentrics issue on some cards
Signed-off-by: Axel Davy <[email protected]>
Diffstat (limited to 'src/gallium/state_trackers')
-rw-r--r--src/gallium/state_trackers/nine/device9.c4
-rw-r--r--src/gallium/state_trackers/nine/device9.h4
-rw-r--r--src/gallium/state_trackers/nine/nine_state.c24
3 files changed, 31 insertions, 1 deletions
diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
index 43eb7e6397c..9ca1bb93597 100644
--- a/src/gallium/state_trackers/nine/device9.c
+++ b/src/gallium/state_trackers/nine/device9.c
@@ -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;
diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h
index f412088ca08..d662f839d88 100644
--- a/src/gallium/state_trackers/nine/device9.h
+++ b/src/gallium/state_trackers/nine/device9.h
@@ -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;
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
index 495cc862b2a..6c7eab3c25c 100644
--- a/src/gallium/state_trackers/nine/nine_state.c
+++ b/src/gallium/state_trackers/nine/nine_state.c
@@ -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);
}