st/nine: Fix stateblocks crashes with lights
authorAxel Davy <axel.davy@ens.fr>
Sat, 6 Feb 2016 18:29:10 +0000 (19:29 +0100)
committerAxel Davy <axel.davy@ens.fr>
Fri, 12 Feb 2016 22:26:36 +0000 (23:26 +0100)
We had several issues of crashes with it.
This should fix it.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
src/gallium/state_trackers/nine/stateblock9.c

index 0d1a04b657a48ea5702c18b82f8fa4eea09ad721..47893465f0816fe773045ec3aec7a7a0f1a16f0b 100644 (file)
@@ -86,7 +86,7 @@ NineStateBlock9_dtor( struct NineStateBlock9 *This )
  */
 static void
 nine_state_copy_common(struct nine_state *dst,
-                       const struct nine_state *src,
+                       struct nine_state *src,
                        struct nine_state *mask, /* aliases either src or dst */
                        const boolean apply,
                        struct nine_range_pool *pool)
@@ -267,17 +267,41 @@ nine_state_copy_common(struct nine_state *dst,
         }
     }
     if (mask->changed.group & NINE_STATE_FF_LIGHTING) {
-        if (dst->ff.num_lights < mask->ff.num_lights) {
+        unsigned num_lights = MAX2(dst->ff.num_lights, src->ff.num_lights);
+        /* Can happen in Capture() if device state has created new lights after
+         * the stateblock was created.
+         * Can happen in Apply() if the stateblock had recorded the creation of
+         * new lights. */
+        if (dst->ff.num_lights < num_lights) {
             dst->ff.light = REALLOC(dst->ff.light,
                                     dst->ff.num_lights * sizeof(D3DLIGHT9),
-                                    mask->ff.num_lights * sizeof(D3DLIGHT9));
-            for (i = dst->ff.num_lights; i < mask->ff.num_lights; ++i) {
-                memset(&dst->ff.light[i], 0, sizeof(D3DLIGHT9));
-                dst->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
+                                    num_lights * sizeof(D3DLIGHT9));
+            memset(&dst->ff.light[dst->ff.num_lights], 0, (num_lights - dst->ff.num_lights) * sizeof(D3DLIGHT9));
+            /* if mask == dst, a Type of 0 will trigger
+             * "dst->ff.light[i] = src->ff.light[i];" later,
+             * which is what we want in that case. */
+            if (mask != dst) {
+                for (i = src->ff.num_lights; i < num_lights; ++i)
+                    src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
             }
-            dst->ff.num_lights = mask->ff.num_lights;
+            dst->ff.num_lights = num_lights;
         }
-        for (i = 0; i < mask->ff.num_lights; ++i)
+        /* Can happen in Capture() if the stateblock had recorded the creation of
+         * new lights.
+         * Can happen in Apply() if device state has created new lights after
+         * the stateblock was created. */
+        if (src->ff.num_lights < num_lights) {
+            src->ff.light = REALLOC(src->ff.light,
+                                    src->ff.num_lights * sizeof(D3DLIGHT9),
+                                    num_lights * sizeof(D3DLIGHT9));
+            memset(&src->ff.light[src->ff.num_lights], 0, (num_lights - src->ff.num_lights) * sizeof(D3DLIGHT9));
+            for (i = src->ff.num_lights; i < num_lights; ++i)
+                src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
+            src->ff.num_lights = num_lights;
+        }
+        /* Note: mask is either src or dst, so at this point src, dst and mask
+         * have num_lights lights. */
+        for (i = 0; i < num_lights; ++i)
             if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID)
                 dst->ff.light[i] = src->ff.light[i];