i915g: Check for geometry shader earlier in i915_set_constant_buffer.
[mesa.git] / src / gallium / drivers / i915 / i915_state.c
index e54997736f977ad8131b1cf22fb9d18a6efe6ed8..1ff53884ada3bdb1eaf6dc0b2e44d405cc5a5762 100644 (file)
 #include "util/u_inlines.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
+#include "util/u_transfer.h"
 #include "tgsi/tgsi_parse.h"
 
 #include "i915_context.h"
 #include "i915_reg.h"
 #include "i915_state_inlines.h"
 #include "i915_fpc.h"
+#include "i915_resource.h"
 
 /* The i915 (and related graphics cores) do not support GL_CLAMP.  The
  * Intel drivers for "other operating systems" implement GL_CLAMP as
@@ -56,10 +58,8 @@ translate_wrap_mode(unsigned wrap)
       return TEXCOORDMODE_CLAMP_EDGE;
    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
       return TEXCOORDMODE_CLAMP_BORDER;
-   /*         
-   case PIPE_TEX_WRAP_MIRRORED_REPEAT:
+   case PIPE_TEX_WRAP_MIRROR_REPEAT:
       return TEXCOORDMODE_MIRROR;
-    */
    default:
       return TEXCOORDMODE_WRAP;
    }
@@ -146,6 +146,7 @@ i915_create_blend_state(struct pipe_context *pipe,
    if (blend->dither)
       cso_data->LIS5 |= S5_COLOR_DITHER_ENABLE;
 
+   /* XXX here take the target fixup into account */
    if ((blend->rt[0].colormask & PIPE_MASK_R) == 0)
       cso_data->LIS5 |= S5_WRITEDISABLE_RED;
 
@@ -176,7 +177,9 @@ static void i915_bind_blend_state(struct pipe_context *pipe,
                                   void *blend)
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
+
+   if (i915->blend == blend)
+      return;
 
    i915->blend = (struct i915_blend_state*)blend;
 
@@ -193,7 +196,9 @@ static void i915_set_blend_color( struct pipe_context *pipe,
                                   const struct pipe_blend_color *blend_color )
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
+
+   if (!blend_color)
+      return;
 
    i915->blend_color = *blend_color;
 
@@ -204,7 +209,6 @@ static void i915_set_stencil_ref( struct pipe_context *pipe,
                                   const struct pipe_stencil_ref *stencil_ref )
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
 
    i915->stencil_ref = *stencil_ref;
 
@@ -222,12 +226,12 @@ i915_create_sampler_state(struct pipe_context *pipe,
    unsigned minFilt, magFilt;
    unsigned mipFilt;
 
-   cso->templ = sampler;
+   cso->templ = *sampler;
 
    mipFilt = translate_mip_filter(sampler->min_mip_filter);
    minFilt = translate_img_filter( sampler->min_img_filter );
    magFilt = translate_img_filter( sampler->mag_img_filter );
-   
+
    if (sampler->max_anisotropy > 1)
       minFilt = magFilt = FILTER_ANISOTROPIC;
 
@@ -243,10 +247,10 @@ i915_create_sampler_state(struct pipe_context *pipe,
 
    /* Shadow:
     */
-   if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) 
+   if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE)
    {
       cso->state[0] |= (SS2_SHADOW_ENABLE |
-                        i915_translate_compare_func(sampler->compare_func));
+                        i915_translate_shadow_compare_func(sampler->compare_func));
 
       minFilt = FILTER_4X4_FLAT;
       magFilt = FILTER_4X4_FLAT;
@@ -278,30 +282,66 @@ i915_create_sampler_state(struct pipe_context *pipe,
    }
 
    {
-      ubyte r = float_to_ubyte(sampler->border_color[0]);
-      ubyte g = float_to_ubyte(sampler->border_color[1]);
-      ubyte b = float_to_ubyte(sampler->border_color[2]);
-      ubyte a = float_to_ubyte(sampler->border_color[3]);
+      ubyte r = float_to_ubyte(sampler->border_color.f[0]);
+      ubyte g = float_to_ubyte(sampler->border_color.f[1]);
+      ubyte b = float_to_ubyte(sampler->border_color.f[2]);
+      ubyte a = float_to_ubyte(sampler->border_color.f[3]);
       cso->state[2] = I915PACKCOLOR8888(r, g, b, a);
    }
    return cso;
 }
 
-static void i915_bind_sampler_states(struct pipe_context *pipe,
-                                     unsigned num, void **sampler)
+static void i915_fixup_bind_sampler_states(struct pipe_context *pipe,
+                                           unsigned num, void **sampler)
+{
+   struct i915_context *i915 = i915_context(pipe);
+
+   i915->saved_nr_samplers = num;
+   memcpy(&i915->saved_samplers, sampler, sizeof(void *) * num);
+
+   i915->saved_bind_sampler_states(pipe, num, sampler);
+}
+
+static void
+i915_bind_vertex_sampler_states(struct pipe_context *pipe,
+                                unsigned num_samplers,
+                                void **samplers)
 {
    struct i915_context *i915 = i915_context(pipe);
    unsigned i;
 
-   assert(num <= PIPE_MAX_SAMPLERS);
+   assert(num_samplers <= PIPE_MAX_VERTEX_SAMPLERS);
+
+   /* Check for no-op */
+   if (num_samplers == i915->num_vertex_samplers &&
+       !memcmp(i915->vertex_samplers, samplers, num_samplers * sizeof(void *)))
+      return;
+
+   for (i = 0; i < num_samplers; ++i)
+      i915->vertex_samplers[i] = samplers[i];
+   for (i = num_samplers; i < PIPE_MAX_VERTEX_SAMPLERS; ++i)
+      i915->vertex_samplers[i] = NULL;
+
+   i915->num_vertex_samplers = num_samplers;
+
+   draw_set_samplers(i915->draw,
+                     i915->vertex_samplers,
+                     i915->num_vertex_samplers);
+}
+
+
+
+static void i915_bind_fragment_sampler_states(struct pipe_context *pipe,
+                                     unsigned num, void **sampler)
+{
+   struct i915_context *i915 = i915_context(pipe);
+   unsigned i;
 
    /* Check for no-op */
    if (num == i915->num_samplers &&
        !memcmp(i915->sampler, sampler, num * sizeof(void *)))
       return;
 
-   draw_flush(i915->draw);
-
    for (i = 0; i < num; ++i)
       i915->sampler[i] = sampler[i];
    for (i = num; i < PIPE_MAX_SAMPLERS; ++i)
@@ -319,6 +359,76 @@ static void i915_delete_sampler_state(struct pipe_context *pipe,
 }
 
 
+/**
+ * Called before drawing VBO to map vertex samplers and hand them to draw
+ */
+void
+i915_prepare_vertex_sampling(struct i915_context *i915)
+{
+   struct i915_winsys *iws = i915->iws;
+   unsigned i,j;
+   uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
+   uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
+   const void* data[PIPE_MAX_TEXTURE_LEVELS];
+   unsigned num = i915->num_vertex_sampler_views;
+   struct pipe_sampler_view **views = i915->vertex_sampler_views;
+
+   assert(num <= PIPE_MAX_VERTEX_SAMPLERS);
+   if (!num)
+      return;
+
+   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
+      struct pipe_sampler_view *view = i < num ? views[i] : NULL;
+
+      if (view) {
+         struct pipe_resource *tex = view->texture;
+         struct i915_texture *i915_tex = i915_texture(tex);
+         ubyte *addr;
+
+         /* We're referencing the texture's internal data, so save a
+          * reference to it.
+          */
+         pipe_resource_reference(&i915->mapped_vs_tex[i], tex);
+
+        i915->mapped_vs_tex_buffer[i] = i915_tex->buffer;
+         addr = iws->buffer_map(iws,
+                                i915_tex->buffer,
+                                FALSE /* read only */);
+
+         /* Setup array of mipmap level pointers */
+        /* FIXME: handle 3D textures? */
+         for (j = view->u.tex.first_level; j <= tex->last_level; j++) {
+            unsigned offset = i915_texture_offset(i915_tex, j , 0 /* FIXME depth */);
+            data[j] = addr + offset;
+            row_stride[j] = i915_tex->stride;
+            img_stride[j] = 0; /* FIXME */;
+         }
+
+         draw_set_mapped_texture(i915->draw,
+                                 i,
+                                 tex->width0, tex->height0, tex->depth0,
+                                 view->u.tex.first_level, tex->last_level,
+                                 row_stride, img_stride, data);
+      } else
+         i915->mapped_vs_tex[i] = NULL;
+   }
+}
+
+void
+i915_cleanup_vertex_sampling(struct i915_context *i915)
+{
+   struct i915_winsys *iws = i915->iws;
+   unsigned i;
+   for (i = 0; i < Elements(i915->mapped_vs_tex); i++) {
+      if (i915->mapped_vs_tex_buffer[i]) { 
+         iws->buffer_unmap(iws, i915->mapped_vs_tex_buffer[i]);
+         pipe_resource_reference(&i915->mapped_vs_tex[i], NULL);
+      }
+   }
+}
+
+
+
 /** XXX move someday?  Or consolidate all these simple state setters
  * into one file.
  */
@@ -416,7 +526,9 @@ static void i915_bind_depth_stencil_state(struct pipe_context *pipe,
                                           void *depth_stencil)
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
+
+   if (i915->depth_stencil == depth_stencil)
+      return;
 
    i915->depth_stencil = (const struct i915_depth_stencil_state *)depth_stencil;
 
@@ -434,7 +546,6 @@ static void i915_set_scissor_state( struct pipe_context *pipe,
                                  const struct pipe_scissor_state *scissor )
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
 
    memcpy( &i915->scissor, scissor, sizeof(*scissor) );
    i915->dirty |= I915_NEW_SCISSOR;
@@ -457,6 +568,7 @@ i915_create_fs_state(struct pipe_context *pipe,
    if (!ifs)
       return NULL;
 
+   ifs->draw_data = draw_create_fragment_shader(i915->draw, templ);
    ifs->state.tokens = tgsi_dup_tokens(templ->tokens);
 
    tgsi_scan_shader(templ->tokens, &ifs->info);
@@ -467,14 +579,31 @@ i915_create_fs_state(struct pipe_context *pipe,
    return ifs;
 }
 
+static void
+i915_fixup_bind_fs_state(struct pipe_context *pipe, void *shader)
+{
+   struct i915_context *i915 = i915_context(pipe);
+
+   if (i915->saved_fs == shader)
+      return;
+
+   i915->saved_fs = shader;
+
+   i915->saved_bind_fs_state(pipe, shader);
+}
+
 static void
 i915_bind_fs_state(struct pipe_context *pipe, void *shader)
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
+
+   if (i915->fs == shader)
+      return;
 
    i915->fs = (struct i915_fragment_shader*) shader;
 
+   draw_bind_fragment_shader(i915->draw,  (i915->fs ? i915->fs->draw_data : NULL));
+
    i915->dirty |= I915_NEW_FS;
 }
 
@@ -483,11 +612,19 @@ void i915_delete_fs_state(struct pipe_context *pipe, void *shader)
 {
    struct i915_fragment_shader *ifs = (struct i915_fragment_shader *) shader;
 
-   if (ifs->program)
+   if (ifs->decl) {
+      FREE(ifs->decl);
+      ifs->decl = NULL;
+   }
+
+   if (ifs->program) {
       FREE(ifs->program);
+      ifs->program = NULL;
+      FREE((struct tgsi_token *)ifs->state.tokens);
+      ifs->state.tokens = NULL;
+   }
    ifs->program_len = 0;
-
-   FREE((struct tgsi_token *)ifs->state.tokens);
+   ifs->decl_len = 0;
 
    FREE(ifs);
 }
@@ -507,6 +644,11 @@ static void i915_bind_vs_state(struct pipe_context *pipe, void *shader)
 {
    struct i915_context *i915 = i915_context(pipe);
 
+   if (i915->saved_vs == shader)
+      return;
+
+   i915->saved_vs = shader;
+
    /* just pass-through to draw module */
    draw_bind_vertex_shader(i915->draw, (struct draw_vertex_shader *) shader);
 
@@ -523,43 +665,81 @@ static void i915_delete_vs_state(struct pipe_context *pipe, void *shader)
 
 static void i915_set_constant_buffer(struct pipe_context *pipe,
                                      uint shader, uint index,
-                                     struct pipe_buffer *buf)
+                                     struct pipe_constant_buffer *cb)
 {
    struct i915_context *i915 = i915_context(pipe);
-   struct pipe_screen *screen = pipe->screen;
-   draw_flush(i915->draw);
-
-   assert(shader < PIPE_SHADER_TYPES);
-   assert(index == 0);
-
-   /* Make a copy of shader constants.
-    * During fragment program translation we may add additional
-    * constants to the array.
-    *
-    * We want to consider the situation where some user constants
-    * (ex: a material color) may change frequently but the shader program
-    * stays the same.  In that case we should only be updating the first
-    * N constants, leaving any extras from shader translation alone.
-    */
+   struct pipe_resource *buf = cb ? cb->buffer : NULL;
+   unsigned new_num = 0;
+   boolean diff = TRUE;
+
+   /* XXX don't support geom shaders now */
+   if (shader == PIPE_SHADER_GEOMETRY)
+      return;
+
+   if (cb && cb->user_buffer) {
+      buf = i915_user_buffer_create(pipe->screen, cb->user_buffer,
+                                    cb->buffer_size,
+                                    PIPE_BIND_CONSTANT_BUFFER);
+   }
+
+   /* if we have a new buffer compare it with the old one */
    if (buf) {
-      void *mapped;
-      if (buf->size &&
-          (mapped = pipe_buffer_map(screen, buf,
-                                    PIPE_BUFFER_USAGE_CPU_READ))) {
-         memcpy(i915->current.constants[shader], mapped, buf->size);
-         pipe_buffer_unmap(screen, buf);
-         i915->current.num_user_constants[shader]
-            = buf->size / (4 * sizeof(float));
-      }
-      else {
-         i915->current.num_user_constants[shader] = 0;
+      struct i915_buffer *ibuf = i915_buffer(buf);
+      struct pipe_resource *old_buf = i915->constants[shader];
+      struct i915_buffer *old = old_buf ? i915_buffer(old_buf) : NULL;
+      unsigned old_num = i915->current.num_user_constants[shader];
+
+      new_num = ibuf->b.b.width0 / 4 * sizeof(float);
+
+      if (old_num == new_num) {
+         if (old_num == 0)
+            diff = FALSE;
+#if 0
+         /* XXX no point in running this code since st/mesa only uses user buffers */
+         /* Can't compare the buffer data since they are userbuffers */
+         else if (old && old->free_on_destroy)
+            diff = memcmp(old->data, ibuf->data, ibuf->b.b.width0);
+#else
+         (void)old;
+#endif
       }
+   } else {
+      diff = i915->current.num_user_constants[shader] != 0;
    }
 
-   i915->dirty |= I915_NEW_CONSTANTS;
+   pipe_resource_reference(&i915->constants[shader], buf);
+   i915->current.num_user_constants[shader] = new_num;
+
+   if (diff)
+      i915->dirty |= shader == PIPE_SHADER_VERTEX ? I915_NEW_VS_CONSTANTS : I915_NEW_FS_CONSTANTS;
+
+   if (cb && cb->user_buffer) {
+      pipe_resource_reference(&buf, NULL);
+   }
 }
 
 
+static void
+i915_fixup_set_fragment_sampler_views(struct pipe_context *pipe,
+                                      unsigned num,
+                                      struct pipe_sampler_view **views)
+{
+   struct i915_context *i915 = i915_context(pipe);
+   int i;
+
+   for (i = 0; i < num; i++)
+      pipe_sampler_view_reference(&i915->saved_sampler_views[i],
+                                  views[i]);
+
+   for (i = num; i < i915->saved_nr_sampler_views; i++)
+      pipe_sampler_view_reference(&i915->saved_sampler_views[i],
+                                  NULL);
+
+   i915->saved_nr_sampler_views = num;
+
+   i915->saved_set_sampler_views(pipe, num, views);
+}
+
 static void i915_set_fragment_sampler_views(struct pipe_context *pipe,
                                             unsigned num,
                                             struct pipe_sampler_view **views)
@@ -574,9 +754,6 @@ static void i915_set_fragment_sampler_views(struct pipe_context *pipe,
        !memcmp(i915->fragment_sampler_views, views, num * sizeof(struct pipe_sampler_view *)))
       return;
 
-   /* Fixes wrong texture in texobj with VBUF */
-   draw_flush(i915->draw);
-
    for (i = 0; i < num; i++)
       pipe_sampler_view_reference(&i915->fragment_sampler_views[i],
                                   views[i]);
@@ -590,10 +767,39 @@ static void i915_set_fragment_sampler_views(struct pipe_context *pipe,
    i915->dirty |= I915_NEW_SAMPLER_VIEW;
 }
 
+static void
+i915_set_vertex_sampler_views(struct pipe_context *pipe,
+                              unsigned num,
+                              struct pipe_sampler_view **views)
+{
+   struct i915_context *i915 = i915_context(pipe);
+   uint i;
+
+   assert(num <= PIPE_MAX_VERTEX_SAMPLERS);
+
+   /* Check for no-op */
+   if (num == i915->num_vertex_sampler_views &&
+       !memcmp(i915->vertex_sampler_views, views, num * sizeof(struct pipe_sampler_view *))) {
+      return;
+   }
+
+   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
+      struct pipe_sampler_view *view = i < num ? views[i] : NULL;
+
+      pipe_sampler_view_reference(&i915->vertex_sampler_views[i], view);
+   }
+
+   i915->num_vertex_sampler_views = num;
+
+   draw_set_sampler_views(i915->draw,
+                          i915->vertex_sampler_views,
+                          i915->num_vertex_sampler_views);
+}
+
 
 static struct pipe_sampler_view *
 i915_create_sampler_view(struct pipe_context *pipe,
-                         struct pipe_texture *texture,
+                         struct pipe_resource *texture,
                          const struct pipe_sampler_view *templ)
 {
    struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view);
@@ -602,7 +808,7 @@ i915_create_sampler_view(struct pipe_context *pipe,
       *view = *templ;
       view->reference.count = 1;
       view->texture = NULL;
-      pipe_texture_reference(&view->texture, texture);
+      pipe_resource_reference(&view->texture, texture);
       view->context = pipe;
    }
 
@@ -614,7 +820,7 @@ static void
 i915_sampler_view_destroy(struct pipe_context *pipe,
                           struct pipe_sampler_view *view)
 {
-   pipe_texture_reference(&view->texture, NULL);
+   pipe_resource_reference(&view->texture, NULL);
    FREE(view);
 }
 
@@ -625,13 +831,12 @@ static void i915_set_framebuffer_state(struct pipe_context *pipe,
    struct i915_context *i915 = i915_context(pipe);
    int i;
 
-   draw_flush(i915->draw);
-
    i915->framebuffer.width = fb->width;
    i915->framebuffer.height = fb->height;
    i915->framebuffer.nr_cbufs = fb->nr_cbufs;
    for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
-      pipe_surface_reference(&i915->framebuffer.cbufs[i], fb->cbufs[i]);
+      pipe_surface_reference(&i915->framebuffer.cbufs[i],
+                             i < fb->nr_cbufs ? fb->cbufs[i] : NULL);
    }
    pipe_surface_reference(&i915->framebuffer.zsbuf, fb->zsbuf);
 
@@ -644,7 +849,8 @@ static void i915_set_clip_state( struct pipe_context *pipe,
                             const struct pipe_clip_state *clip )
 {
    struct i915_context *i915 = i915_context(pipe);
-   draw_flush(i915->draw);
+
+   i915->saved_clip = *clip;
 
    draw_set_clip_state(i915->draw, clip);
 
@@ -676,7 +882,7 @@ i915_create_rasterizer_state(struct pipe_context *pipe,
 {
    struct i915_rasterizer_state *cso = CALLOC_STRUCT( i915_rasterizer_state );
 
-   cso->templ = rasterizer;
+   cso->templ = *rasterizer;
    cso->color_interp = rasterizer->flatshade ? INTERP_CONSTANT : INTERP_LINEAR;
    cso->light_twoside = rasterizer->light_twoside;
    cso->ds[0].u = _3DSTATE_DEPTH_OFFSET_SCALE;
@@ -690,17 +896,23 @@ i915_create_rasterizer_state(struct pipe_context *pipe,
    else
       cso->sc[0] = _3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT;
 
-   switch (rasterizer->cull_mode) {
-   case PIPE_WINDING_NONE:
+   switch (rasterizer->cull_face) {
+   case PIPE_FACE_NONE:
       cso->LIS4 |= S4_CULLMODE_NONE;
       break;
-   case PIPE_WINDING_CW:
-      cso->LIS4 |= S4_CULLMODE_CW;
+   case PIPE_FACE_FRONT:
+      if (rasterizer->front_ccw)
+         cso->LIS4 |= S4_CULLMODE_CCW;
+      else 
+         cso->LIS4 |= S4_CULLMODE_CW;
       break;
-   case PIPE_WINDING_CCW:
-      cso->LIS4 |= S4_CULLMODE_CCW;
+   case PIPE_FACE_BACK:
+      if (rasterizer->front_ccw)
+         cso->LIS4 |= S4_CULLMODE_CW;
+      else 
+         cso->LIS4 |= S4_CULLMODE_CCW;
       break;
-   case PIPE_WINDING_BOTH:
+   case PIPE_FACE_FRONT_AND_BACK:
       cso->LIS4 |= S4_CULLMODE_BOTH;
       break;
    }
@@ -737,11 +949,15 @@ static void i915_bind_rasterizer_state( struct pipe_context *pipe,
 {
    struct i915_context *i915 = i915_context(pipe);
 
+   if (i915->rasterizer == raster)
+      return;
+
    i915->rasterizer = (struct i915_rasterizer_state *)raster;
 
    /* pass-through to draw module */
    draw_set_rasterizer_state(i915->draw,
-                          (i915->rasterizer ? i915->rasterizer->templ : NULL));
+                           (i915->rasterizer ? &(i915->rasterizer->templ) : NULL),
+                           raster);
 
    i915->dirty |= I915_NEW_RASTERIZER;
 }
@@ -757,16 +973,30 @@ static void i915_set_vertex_buffers(struct pipe_context *pipe,
                                     const struct pipe_vertex_buffer *buffers)
 {
    struct i915_context *i915 = i915_context(pipe);
-   /* Because we change state before the draw_set_vertex_buffers call
-    * we need a flush here, just to be sure.
-    */
-   draw_flush(i915->draw);
+   struct draw_context *draw = i915->draw;
+   int i;
 
-   memcpy(i915->vertex_buffer, buffers, count * sizeof(buffers[0]));
-   i915->num_vertex_buffers = count;
+   util_copy_vertex_buffers(i915->saved_vertex_buffers,
+                            &i915->saved_nr_vertex_buffers,
+                            buffers, count);
+#if 0
+   /* XXX doesn't look like this is needed */
+   /* unmap old */
+   for (i = 0; i < i915->num_vertex_buffers; i++) {
+      draw_set_mapped_vertex_buffer(draw, i, NULL);
+   }
+#endif
 
    /* pass-through to draw module */
-   draw_set_vertex_buffers(i915->draw, count, buffers);
+   draw_set_vertex_buffers(draw, count, buffers);
+
+   /* map new */
+   for (i = 0; i < count; i++) {
+      const void *buf = buffers[i].user_buffer;
+      if (!buf)
+            buf = i915_buffer(buffers[i].buffer)->data;
+      draw_set_mapped_vertex_buffer(draw, i, buf);
+   }
 }
 
 static void *
@@ -791,13 +1021,16 @@ i915_bind_vertex_elements_state(struct pipe_context *pipe,
    struct i915_context *i915 = i915_context(pipe);
    struct i915_velems_state *i915_velems = (struct i915_velems_state *) velems;
 
-   /* Because we change state before the draw_set_vertex_buffers call
-    * we need a flush here, just to be sure.
-    */
-   draw_flush(i915->draw);
+   if (i915->saved_velems == velems)
+      return;
+
+   i915->saved_velems = velems;
 
    /* pass-through to draw module */
-   draw_set_vertex_elements(i915->draw, i915_velems->count, i915_velems->velem);
+   if (i915_velems) {
+      draw_set_vertex_elements(i915->draw,
+            i915_velems->count, i915_velems->velem);
+   }
 }
 
 static void
@@ -806,6 +1039,26 @@ i915_delete_vertex_elements_state(struct pipe_context *pipe, void *velems)
    FREE( velems );
 }
 
+static void i915_set_index_buffer(struct pipe_context *pipe,
+                                  const struct pipe_index_buffer *ib)
+{
+   struct i915_context *i915 = i915_context(pipe);
+
+   if (ib)
+      memcpy(&i915->index_buffer, ib, sizeof(i915->index_buffer));
+   else
+      memset(&i915->index_buffer, 0, sizeof(i915->index_buffer));
+
+   /* pass-through to draw module */
+   draw_set_index_buffer(i915->draw, ib);
+}
+
+static void
+i915_set_sample_mask(struct pipe_context *pipe,
+                     unsigned sample_mask)
+{
+}
+
 void
 i915_init_state_functions( struct i915_context *i915 )
 {
@@ -814,7 +1067,8 @@ i915_init_state_functions( struct i915_context *i915 )
    i915->base.delete_blend_state = i915_delete_blend_state;
 
    i915->base.create_sampler_state = i915_create_sampler_state;
-   i915->base.bind_fragment_sampler_states = i915_bind_sampler_states;
+   i915->base.bind_fragment_sampler_states = i915_bind_fragment_sampler_states;
+   i915->base.bind_vertex_sampler_states = i915_bind_vertex_sampler_states;
    i915->base.delete_sampler_state = i915_delete_sampler_state;
 
    i915->base.create_depth_stencil_alpha_state = i915_create_depth_stencil_state;
@@ -837,14 +1091,28 @@ i915_init_state_functions( struct i915_context *i915 )
    i915->base.set_blend_color = i915_set_blend_color;
    i915->base.set_stencil_ref = i915_set_stencil_ref;
    i915->base.set_clip_state = i915_set_clip_state;
+   i915->base.set_sample_mask = i915_set_sample_mask;
    i915->base.set_constant_buffer = i915_set_constant_buffer;
    i915->base.set_framebuffer_state = i915_set_framebuffer_state;
 
    i915->base.set_polygon_stipple = i915_set_polygon_stipple;
    i915->base.set_scissor_state = i915_set_scissor_state;
    i915->base.set_fragment_sampler_views = i915_set_fragment_sampler_views;
+   i915->base.set_vertex_sampler_views = i915_set_vertex_sampler_views;
    i915->base.create_sampler_view = i915_create_sampler_view;
    i915->base.sampler_view_destroy = i915_sampler_view_destroy;
    i915->base.set_viewport_state = i915_set_viewport_state;
    i915->base.set_vertex_buffers = i915_set_vertex_buffers;
+   i915->base.set_index_buffer = i915_set_index_buffer;
+}
+
+void
+i915_init_fixup_state_functions( struct i915_context *i915 )
+{
+   i915->saved_bind_fs_state = i915->base.bind_fs_state;
+   i915->base.bind_fs_state = i915_fixup_bind_fs_state;
+   i915->saved_bind_sampler_states = i915->base.bind_fragment_sampler_states;
+   i915->base.bind_fragment_sampler_states = i915_fixup_bind_sampler_states;
+   i915->saved_set_sampler_views = i915->base.set_fragment_sampler_views;
+   i915->base.set_fragment_sampler_views = i915_fixup_set_fragment_sampler_views;
 }