st/nine: Implement fallback behaviour when rts and ds don't match
authorAxel Davy <axel.davy@ens.fr>
Sun, 18 Jan 2015 10:05:34 +0000 (11:05 +0100)
committerAxel Davy <axel.davy@ens.fr>
Thu, 5 Feb 2015 23:07:19 +0000 (00:07 +0100)
This seems to be the behaviour on Win. Previous behaviour led
to different issues depending on the driver.

Reviewed-by: Tiziano Bacocco <tizbac2@gmail.com>
Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/nine_state.c

index 1e533354d64b065ac7b0216575292803ca487861..02fef9a381da3c4146a6f225e93ac7d9d38a9310 100644 (file)
@@ -44,7 +44,10 @@ update_framebuffer(struct NineDevice9 *device)
     struct nine_state *state = &device->state;
     struct pipe_framebuffer_state *fb = &device->state.fb;
     unsigned i;
-    unsigned w = 0, h = 0; /* no surface can have width or height 0 */
+    struct NineSurface9 *rt0 = state->rt[0];
+    unsigned w = rt0->desc.Width;
+    unsigned h = rt0->desc.Height;
+    D3DMULTISAMPLE_TYPE nr_samples = rt0->desc.MultiSampleType;
 
     const int sRGB = state->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0;
 
@@ -53,19 +56,31 @@ update_framebuffer(struct NineDevice9 *device)
     state->rt_mask = 0x0;
     fb->nr_cbufs = 0;
 
+    /* all render targets must have the same size and the depth buffer must be
+     * bigger. Multisample has to match, according to spec. But some apps do
+     * things wrong there, and no error is returned. The behaviour they get
+     * apparently is that depth buffer is disabled if it doesn't match.
+     * Surely the same for render targets. */
+
+    /* Special case: D3DFMT_NULL is used to bound no real render target,
+     * but render to depth buffer. We have to not take into account the render
+     * target info. TODO: know what should happen when there are several render targers
+     * and the first one is D3DFMT_NULL */
+    if (rt0->desc.Format == D3DFMT_NULL && state->ds) {
+        w = state->ds->desc.Width;
+        h = state->ds->desc.Height;
+        nr_samples = state->ds->desc.MultiSampleType;
+    }
+
     for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) {
-        if (state->rt[i] && state->rt[i]->desc.Format != D3DFMT_NULL) {
-            struct NineSurface9 *rt = state->rt[i];
+        struct NineSurface9 *rt = state->rt[i];
+
+        if (rt && rt->desc.Format != D3DFMT_NULL && rt->desc.Width == w &&
+            rt->desc.Height == h && rt->desc.MultiSampleType == nr_samples) {
             fb->cbufs[i] = NineSurface9_GetSurface(rt, sRGB);
             state->rt_mask |= 1 << i;
             fb->nr_cbufs = i + 1;
-            if (w) {
-                w = MIN2(w, rt->desc.Width);
-                h = MIN2(h, rt->desc.Height);
-            } else {
-                w = rt->desc.Width;
-                h = rt->desc.Height;
-            }
+
             if (unlikely(rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)) {
                 assert(rt->texture == D3DRTYPE_TEXTURE ||
                        rt->texture == D3DRTYPE_CUBETEXTURE);
@@ -79,15 +94,10 @@ update_framebuffer(struct NineDevice9 *device)
         }
     }
 
-    if (state->ds) {
+    if (state->ds && state->ds->desc.Width >= w &&
+        state->ds->desc.Height >= h &&
+        state->ds->desc.MultiSampleType == nr_samples) {
         fb->zsbuf = NineSurface9_GetSurface(state->ds, 0);
-        if (w) {
-            w = MIN2(w, state->ds->desc.Width);
-            h = MIN2(h, state->ds->desc.Height);
-        } else {
-            w = state->ds->desc.Width;
-            h = state->ds->desc.Height;
-        }
     } else {
         fb->zsbuf = NULL;
     }