st/nine: Reimplement nine_context_apply_stateblock

The new version uses nine_context functions instead of
applying the changes directly to nine_context.
This will enable it to work with CSMT.

v2: Fix nine_context_light_enable_stateblock
The memcpy arguments were wrong, and the state
wasn't set dirty.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
index 3cdab4b..4242301 100644
--- a/src/gallium/state_trackers/nine/nine_state.c
+++ b/src/gallium/state_trackers/nine/nine_state.c
@@ -1446,6 +1446,23 @@
     context->changed.group |= NINE_STATE_PS_CONST;
 }
 
+/* For stateblocks */
+static void
+nine_context_set_pixel_shader_constant_i_transformed(struct NineDevice9 *device,
+                                                     UINT StartRegister,
+                                                     const int *pConstantData,
+                                                     UINT Vector4iCount)
+{
+    struct nine_context *context = &device->context;
+
+    memcpy(&context->ps_const_i[StartRegister][0],
+           pConstantData,
+           Vector4iCount * sizeof(context->ps_const_i[0]));
+
+    context->changed.ps_const_i = TRUE;
+    context->changed.group |= NINE_STATE_PS_CONST;
+}
+
 void
 nine_context_set_pixel_shader_constant_i(struct NineDevice9 *device,
                                          UINT StartRegister,
@@ -1587,6 +1604,20 @@
     context->changed.group |= NINE_STATE_FF_LIGHTING;
 }
 
+
+/* For stateblocks */
+static void
+nine_context_light_enable_stateblock(struct NineDevice9 *device,
+                                     const uint16_t active_light[NINE_MAX_LIGHTS_ACTIVE], /* TODO: use pointer that convey size for csmt */
+                                     unsigned int num_lights_active)
+{
+    struct nine_context *context = &device->context;
+
+    memcpy(context->ff.active_light, active_light, NINE_MAX_LIGHTS_ACTIVE * sizeof(context->ff.active_light[0]));
+    context->ff.num_lights_active = num_lights_active;
+    context->changed.group |= NINE_STATE_FF_LIGHTING;
+}
+
 void
 nine_context_light_enable(struct NineDevice9 *device,
                           DWORD Index,
@@ -1653,6 +1684,8 @@
     context->changed.ucp = TRUE;
 }
 
+#if 0
+
 void
 nine_context_apply_stateblock(struct NineDevice9 *device,
                               const struct nine_state *src)
@@ -1878,6 +1911,179 @@
     }
 }
 
+#endif
+
+/* Do not write to nine_context directly. Slower,
+ * but works with csmt. TODO: write a special csmt version that
+ * would record the list of commands as much as possible,
+ * and use the version above else.
+ */
+void
+nine_context_apply_stateblock(struct NineDevice9 *device,
+                              const struct nine_state *src)
+{
+    int i;
+
+    /* No need to apply src->changed.group, since all calls do
+    * set context->changed.group */
+
+    for (i = 0; i < ARRAY_SIZE(src->changed.rs); ++i) {
+        uint32_t m = src->changed.rs[i];
+        while (m) {
+            const int r = ffs(m) - 1;
+            m &= ~(1 << r);
+            nine_context_set_render_state(device, i * 32 + r, src->rs_advertised[i * 32 + r]);
+        }
+    }
+
+    /* Textures */
+    if (src->changed.texture) {
+        uint32_t m = src->changed.texture;
+        unsigned s;
+
+        for (s = 0; m; ++s, m >>= 1) {
+            struct NineBaseTexture9 *tex = src->texture[s];
+            if (!(m & 1))
+                continue;
+            nine_context_set_texture(device, s, tex);
+        }
+    }
+
+    /* Sampler state */
+    if (src->changed.group & NINE_STATE_SAMPLER) {
+        unsigned s;
+
+        for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
+            uint32_t m = src->changed.sampler[s];
+            while (m) {
+                const int i = ffs(m) - 1;
+                m &= ~(1 << i);
+                nine_context_set_sampler_state(device, s, i, src->samp_advertised[s][i]);
+            }
+        }
+    }
+
+    /* Vertex buffers */
+    if (src->changed.vtxbuf | src->changed.stream_freq) {
+        uint32_t m = src->changed.vtxbuf | src->changed.stream_freq;
+        for (i = 0; m; ++i, m >>= 1) {
+            if (src->changed.vtxbuf & (1 << i))
+                nine_context_set_stream_source(device, i, src->stream[i], src->vtxbuf[i].buffer_offset, src->vtxbuf[i].stride);
+            if (src->changed.stream_freq & (1 << i))
+                nine_context_set_stream_source_freq(device, i, src->stream_freq[i]);
+        }
+    }
+
+    /* Index buffer */
+    if (src->changed.group & NINE_STATE_IDXBUF)
+        nine_context_set_indices(device, src->idxbuf);
+
+    /* Vertex declaration */
+    if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
+        nine_context_set_vertex_declaration(device, src->vdecl);
+
+    /* Vertex shader */
+    if (src->changed.group & NINE_STATE_VS)
+        nine_context_set_vertex_shader(device, src->vs);
+
+    /* Pixel shader */
+    if (src->changed.group & NINE_STATE_PS)
+        nine_context_set_pixel_shader(device, src->ps);
+
+    /* Vertex constants */
+    if (src->changed.group & NINE_STATE_VS_CONST) {
+        struct nine_range *r;
+        for (r = src->changed.vs_const_f; r; r = r->next)
+            nine_context_set_vertex_shader_constant_f(device, r->bgn,
+                                                      &src->vs_const_f[r->bgn * 4],
+                                                      r->end - r->bgn);
+        for (r = src->changed.vs_const_i; r; r = r->next)
+            nine_context_set_vertex_shader_constant_i(device, r->bgn,
+                                                      &src->vs_const_i[r->bgn * 4],
+                                                      r->end - r->bgn);
+        for (r = src->changed.vs_const_b; r; r = r->next)
+            nine_context_set_vertex_shader_constant_b(device, r->bgn,
+                                                      &src->vs_const_b[r->bgn * 4],
+                                                      r->end - r->bgn);
+    }
+
+    /* Pixel constants */
+    if (src->changed.group & NINE_STATE_PS_CONST) {
+        struct nine_range *r;
+        for (r = src->changed.ps_const_f; r; r = r->next)
+            nine_context_set_pixel_shader_constant_f(device, r->bgn,
+                                                     &src->ps_const_f[r->bgn * 4],
+                                                     r->end - r->bgn);
+        if (src->changed.ps_const_i) {
+            uint16_t m = src->changed.ps_const_i;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    nine_context_set_pixel_shader_constant_i_transformed(device, i,
+                                                                         src->ps_const_i[i], 1);
+        }
+        if (src->changed.ps_const_b) {
+            uint16_t m = src->changed.ps_const_b;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    nine_context_set_pixel_shader_constant_b(device, i,
+                                                             &src->ps_const_b[i], 1);
+        }
+    }
+
+    /* Viewport */
+    if (src->changed.group & NINE_STATE_VIEWPORT)
+        nine_context_set_viewport(device, &src->viewport);
+
+    /* Scissor */
+    if (src->changed.group & NINE_STATE_SCISSOR)
+        nine_context_set_scissor(device, &src->scissor);
+
+    /* User Clip Planes */
+    if (src->changed.ucp)
+        for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
+            if (src->changed.ucp & (1 << i))
+                nine_context_set_clip_plane(device, i, &src->clip.ucp[i][0]);
+
+    if (!(src->changed.group & NINE_STATE_FF))
+        return;
+
+    /* Fixed function state. */
+
+    if (src->changed.group & NINE_STATE_FF_MATERIAL)
+        nine_context_set_material(device, &src->ff.material);
+
+    if (src->changed.group & NINE_STATE_FF_PSSTAGES) {
+        unsigned s;
+        for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
+            for (i = 0; i < NINED3DTSS_COUNT; ++i)
+                if (src->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
+                   nine_context_set_texture_stage_state(device, s, i, src->ff.tex_stage[s][i]);
+        }
+    }
+    if (src->changed.group & NINE_STATE_FF_LIGHTING) {
+        for (i = 0; i < src->ff.num_lights; ++i)
+            if (src->ff.light[i].Type != NINED3DLIGHT_INVALID)
+                nine_context_set_light(device, i, &src->ff.light[i]);
+
+        nine_context_light_enable_stateblock(device, src->ff.active_light, src->ff.num_lights_active);
+    }
+    if (src->changed.group & NINE_STATE_FF_VSTRANSF) {
+        for (i = 0; i < ARRAY_SIZE(src->ff.changed.transform); ++i) {
+            unsigned s;
+            if (!src->ff.changed.transform[i])
+                continue;
+            for (s = i * 32; s < (i * 32 + 32); ++s) {
+                if (!(src->ff.changed.transform[i] & (1 << (s % 32))))
+                    continue;
+                nine_context_set_transform(device, s,
+                                           nine_state_access_transform(
+                                               (struct nine_ff_state *)&src->ff,
+                                                                       s, FALSE));
+            }
+        }
+    }
+}
+
 static void
 nine_update_state_framebuffer_clear(struct NineDevice9 *device)
 {