cso: only allow saving and restoring fragment sampler views
[mesa.git] / src / gallium / auxiliary / cso_cache / cso_context.c
index 60c9a9673d568d679f1f98f76fb43f83b5cf8219..1705175d66055e89405e151668eb57f5ae758238 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 VMware, Inc.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -31,8 +31,8 @@
   * Wrap the cso cache & hash mechanisms in a simplified
   * pipe-driver-specific interface.
   *
-  * @author Zack Rusin <zack@tungstengraphics.com>
-  * @author Keith Whitwell <keith@tungstengraphics.com>
+  * @author Zack Rusin <zackr@vmware.com>
+  * @author Keith Whitwell <keithw@vmware.com>
   */
 
 #include "pipe/p_state.h"
@@ -66,12 +66,6 @@ struct sampler_info
 
    void *samplers_saved[PIPE_MAX_SAMPLERS];
    unsigned nr_samplers_saved;
-
-   struct pipe_sampler_view *views[PIPE_MAX_SAMPLERS];
-   unsigned nr_views;
-
-   struct pipe_sampler_view *views_saved[PIPE_MAX_SAMPLERS];
-   unsigned nr_views_saved;
 };
 
 
@@ -82,8 +76,15 @@ struct cso_context {
    struct u_vbuf *vbuf;
 
    boolean has_geometry_shader;
+   boolean has_tessellation;
    boolean has_streamout;
 
+   struct pipe_sampler_view *fragment_views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+   unsigned nr_fragment_views;
+
+   struct pipe_sampler_view *fragment_views_saved[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+   unsigned nr_fragment_views_saved;
+
    struct sampler_info samplers[PIPE_SHADER_TYPES];
 
    struct pipe_vertex_buffer aux_vertex_buffer_current;
@@ -108,6 +109,8 @@ struct cso_context {
    void *fragment_shader, *fragment_shader_saved;
    void *vertex_shader, *vertex_shader_saved;
    void *geometry_shader, *geometry_shader_saved;
+   void *tessctrl_shader, *tessctrl_shader_saved;
+   void *tesseval_shader, *tesseval_shader_saved;
    void *velements, *velements_saved;
    struct pipe_query *render_condition, *render_condition_saved;
    uint render_condition_mode, render_condition_mode_saved;
@@ -120,6 +123,7 @@ struct cso_context {
    struct pipe_viewport_state vp, vp_saved;
    struct pipe_blend_color blend_color;
    unsigned sample_mask, sample_mask_saved;
+   unsigned min_samples, min_samples_saved;
    struct pipe_stencil_ref stencil_ref, stencil_ref_saved;
 };
 
@@ -188,7 +192,7 @@ static boolean delete_vertex_elements(struct cso_context *ctx,
 }
 
 
-static INLINE boolean delete_cso(struct cso_context *ctx,
+static inline boolean delete_cso(struct cso_context *ctx,
                                  void *state, enum cso_cache_type type)
 {
    switch (type) {
@@ -209,7 +213,7 @@ static INLINE boolean delete_cso(struct cso_context *ctx,
    return FALSE;
 }
 
-static INLINE void
+static inline void
 sanitize_hash(struct cso_hash *hash, enum cso_cache_type type,
               int max_size, void *user_data)
 {
@@ -238,18 +242,8 @@ static void cso_init_vbuf(struct cso_context *cso)
 {
    struct u_vbuf_caps caps;
 
-   u_vbuf_get_caps(cso->pipe->screen, &caps);
-
    /* Install u_vbuf if there is anything unsupported. */
-   if (!caps.buffer_offset_unaligned ||
-       !caps.buffer_stride_unaligned ||
-       !caps.velem_src_offset_unaligned ||
-       !caps.format_fixed32 ||
-       !caps.format_float16 ||
-       !caps.format_float64 ||
-       !caps.format_norm32 ||
-       !caps.format_scaled32 ||
-       !caps.user_vertex_buffers) {
+   if (u_vbuf_get_caps(cso->pipe->screen, &caps)) {
       cso->vbuf = u_vbuf_create(cso->pipe, &caps,
                                 cso->aux_vertex_buffer_index);
    }
@@ -269,7 +263,7 @@ struct cso_context *cso_create_context( struct pipe_context *pipe )
                                    ctx);
 
    ctx->pipe = pipe;
-   ctx->sample_mask_saved = ~0;
+   ctx->sample_mask = ~0;
 
    ctx->aux_vertex_buffer_index = 0; /* 0 for now */
 
@@ -282,6 +276,10 @@ struct cso_context *cso_create_context( struct pipe_context *pipe )
                                 PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) {
       ctx->has_geometry_shader = TRUE;
    }
+   if (pipe->screen->get_shader_param(pipe->screen, PIPE_SHADER_TESS_CTRL,
+                                PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) {
+      ctx->has_tessellation = TRUE;
+   }
    if (pipe->screen->get_param(pipe->screen,
                                PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0) {
       ctx->has_streamout = TRUE;
@@ -295,53 +293,63 @@ out:
 }
 
 /**
- * Prior to context destruction, this function unbinds all state objects.
+ * Free the CSO context.
  */
-void cso_release_all( struct cso_context *ctx )
+void cso_destroy_context( struct cso_context *ctx )
 {
-   unsigned i, shader;
+   unsigned i;
 
    if (ctx->pipe) {
+      ctx->pipe->set_index_buffer(ctx->pipe, NULL);
+
       ctx->pipe->bind_blend_state( ctx->pipe, NULL );
       ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL );
 
-      if (ctx->pipe->bind_sampler_states) {
+      {
+         static struct pipe_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS] = { NULL };
          static void *zeros[PIPE_MAX_SAMPLERS] = { NULL };
          struct pipe_screen *scr = ctx->pipe->screen;
          unsigned sh;
          for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) {
-            int max = scr->get_shader_param(scr, sh,
-                                      PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
-            assert(max <= PIPE_MAX_SAMPLERS);
-            if (max > 0) {
-               ctx->pipe->bind_sampler_states(ctx->pipe, sh, 0, max, zeros);
+            int maxsam = scr->get_shader_param(scr, sh,
+                                               PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
+            int maxview = scr->get_shader_param(scr, sh,
+                                                PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS);
+            assert(maxsam <= PIPE_MAX_SAMPLERS);
+            assert(maxview <= PIPE_MAX_SHADER_SAMPLER_VIEWS);
+            if (maxsam > 0) {
+               ctx->pipe->bind_sampler_states(ctx->pipe, sh, 0, maxsam, zeros);
+            }
+            if (maxview > 0) {
+               ctx->pipe->set_sampler_views(ctx->pipe, sh, 0, maxview, views);
             }
          }
       }
-      else {
-         ctx->pipe->bind_fragment_sampler_states( ctx->pipe, 0, NULL );
-         if (ctx->pipe->bind_vertex_sampler_states)
-            ctx->pipe->bind_vertex_sampler_states(ctx->pipe, 0, NULL);
-      }
 
       ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL );
       ctx->pipe->bind_fs_state( ctx->pipe, NULL );
+      ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, NULL);
       ctx->pipe->bind_vs_state( ctx->pipe, NULL );
-      ctx->pipe->bind_vertex_elements_state( ctx->pipe, NULL );
-      ctx->pipe->set_fragment_sampler_views(ctx->pipe, 0, NULL);
-      if (ctx->pipe->set_vertex_sampler_views)
-         ctx->pipe->set_vertex_sampler_views(ctx->pipe, 0, NULL);
-      if (ctx->pipe->set_stream_output_targets)
-         ctx->pipe->set_stream_output_targets(ctx->pipe, 0, NULL, 0);
-   }
-
-   /* free fragment samplers, views */
-   for (shader = 0; shader < Elements(ctx->samplers); shader++) {
-      struct sampler_info *info = &ctx->samplers[shader];
-      for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
-         pipe_sampler_view_reference(&info->views[i], NULL);
-         pipe_sampler_view_reference(&info->views_saved[i], NULL);
+      ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, NULL);
+      if (ctx->has_geometry_shader) {
+         ctx->pipe->bind_gs_state(ctx->pipe, NULL);
+         ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_GEOMETRY, 0, NULL);
+      }
+      if (ctx->has_tessellation) {
+         ctx->pipe->bind_tcs_state(ctx->pipe, NULL);
+         ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_TESS_CTRL, 0, NULL);
+         ctx->pipe->bind_tes_state(ctx->pipe, NULL);
+         ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_TESS_EVAL, 0, NULL);
       }
+      ctx->pipe->bind_vertex_elements_state( ctx->pipe, NULL );
+
+      if (ctx->has_streamout)
+         ctx->pipe->set_stream_output_targets(ctx->pipe, 0, NULL, NULL);
+   }
+
+   for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
+      pipe_sampler_view_reference(&ctx->fragment_views[i], NULL);
+      pipe_sampler_view_reference(&ctx->fragment_views_saved[i], NULL);
    }
 
    util_unreference_framebuffer_state(&ctx->fb);
@@ -364,20 +372,10 @@ void cso_release_all( struct cso_context *ctx )
       cso_cache_delete( ctx->cache );
       ctx->cache = NULL;
    }
-}
-
 
-/**
- * Free the CSO context.  NOTE: the state tracker should have previously called
- * cso_release_all().
- */
-void cso_destroy_context( struct cso_context *ctx )
-{
-   if (ctx) {
-      if (ctx->vbuf)
-         u_vbuf_destroy(ctx->vbuf);
-      FREE( ctx );
-   }
+   if (ctx->vbuf)
+      u_vbuf_destroy(ctx->vbuf);
+   FREE( ctx );
 }
 
 
@@ -716,6 +714,24 @@ void cso_restore_sample_mask(struct cso_context *ctx)
    cso_set_sample_mask(ctx, ctx->sample_mask_saved);
 }
 
+void cso_set_min_samples(struct cso_context *ctx, unsigned min_samples)
+{
+   if (ctx->min_samples != min_samples && ctx->pipe->set_min_samples) {
+      ctx->min_samples = min_samples;
+      ctx->pipe->set_min_samples(ctx->pipe, min_samples);
+   }
+}
+
+void cso_save_min_samples(struct cso_context *ctx)
+{
+   ctx->min_samples_saved = ctx->min_samples;
+}
+
+void cso_restore_min_samples(struct cso_context *ctx)
+{
+   cso_set_min_samples(ctx, ctx->min_samples_saved);
+}
+
 void cso_set_stencil_ref(struct cso_context *ctx,
                          const struct pipe_stencil_ref *sr)
 {
@@ -813,16 +829,102 @@ void cso_restore_geometry_shader(struct cso_context *ctx)
    ctx->geometry_shader_saved = NULL;
 }
 
+void cso_set_tessctrl_shader_handle(struct cso_context *ctx, void *handle)
+{
+   assert(ctx->has_tessellation || !handle);
+
+   if (ctx->has_tessellation && ctx->tessctrl_shader != handle) {
+      ctx->tessctrl_shader = handle;
+      ctx->pipe->bind_tcs_state(ctx->pipe, handle);
+   }
+}
+
+void cso_delete_tessctrl_shader(struct cso_context *ctx, void *handle)
+{
+    if (handle == ctx->tessctrl_shader) {
+      /* unbind before deleting */
+      ctx->pipe->bind_tcs_state(ctx->pipe, NULL);
+      ctx->tessctrl_shader = NULL;
+   }
+   ctx->pipe->delete_tcs_state(ctx->pipe, handle);
+}
+
+void cso_save_tessctrl_shader(struct cso_context *ctx)
+{
+   if (!ctx->has_tessellation) {
+      return;
+   }
+
+   assert(!ctx->tessctrl_shader_saved);
+   ctx->tessctrl_shader_saved = ctx->tessctrl_shader;
+}
+
+void cso_restore_tessctrl_shader(struct cso_context *ctx)
+{
+   if (!ctx->has_tessellation) {
+      return;
+   }
+
+   if (ctx->tessctrl_shader_saved != ctx->tessctrl_shader) {
+      ctx->pipe->bind_tcs_state(ctx->pipe, ctx->tessctrl_shader_saved);
+      ctx->tessctrl_shader = ctx->tessctrl_shader_saved;
+   }
+   ctx->tessctrl_shader_saved = NULL;
+}
+
+void cso_set_tesseval_shader_handle(struct cso_context *ctx, void *handle)
+{
+   assert(ctx->has_tessellation || !handle);
+
+   if (ctx->has_tessellation && ctx->tesseval_shader != handle) {
+      ctx->tesseval_shader = handle;
+      ctx->pipe->bind_tes_state(ctx->pipe, handle);
+   }
+}
+
+void cso_delete_tesseval_shader(struct cso_context *ctx, void *handle)
+{
+    if (handle == ctx->tesseval_shader) {
+      /* unbind before deleting */
+      ctx->pipe->bind_tes_state(ctx->pipe, NULL);
+      ctx->tesseval_shader = NULL;
+   }
+   ctx->pipe->delete_tes_state(ctx->pipe, handle);
+}
+
+void cso_save_tesseval_shader(struct cso_context *ctx)
+{
+   if (!ctx->has_tessellation) {
+      return;
+   }
+
+   assert(!ctx->tesseval_shader_saved);
+   ctx->tesseval_shader_saved = ctx->tesseval_shader;
+}
+
+void cso_restore_tesseval_shader(struct cso_context *ctx)
+{
+   if (!ctx->has_tessellation) {
+      return;
+   }
+
+   if (ctx->tesseval_shader_saved != ctx->tesseval_shader) {
+      ctx->pipe->bind_tes_state(ctx->pipe, ctx->tesseval_shader_saved);
+      ctx->tesseval_shader = ctx->tesseval_shader_saved;
+   }
+   ctx->tesseval_shader_saved = NULL;
+}
+
 /* clip state */
 
-static INLINE void
+static inline void
 clip_state_cpy(struct pipe_clip_state *dst,
                const struct pipe_clip_state *src)
 {
    memcpy(dst->ucp, src->ucp, sizeof(dst->ucp));
 }
 
-static INLINE int
+static inline int
 clip_state_cmp(const struct pipe_clip_state *a,
                const struct pipe_clip_state *b)
 {
@@ -1094,33 +1196,17 @@ single_sampler_done(struct cso_context *ctx, unsigned shader_stage)
       memcpy(info->hw.samplers,
              info->samplers,
              info->nr_samplers * sizeof(void *));
-      info->hw.nr_samplers = info->nr_samplers;
 
-      if (ctx->pipe->bind_sampler_states) {
-         ctx->pipe->bind_sampler_states(ctx->pipe, shader_stage, 0,
-                                        info->nr_samplers, info->samplers);
-      }
-      else {
-         switch (shader_stage) {
-         case PIPE_SHADER_FRAGMENT:
-            ctx->pipe->bind_fragment_sampler_states(ctx->pipe,
-                                                    info->nr_samplers,
-                                                    info->samplers);
-            break;
-         case PIPE_SHADER_VERTEX:
-            ctx->pipe->bind_vertex_sampler_states(ctx->pipe,
-                                                  info->nr_samplers,
-                                                  info->samplers);
-            break;
-         case PIPE_SHADER_GEOMETRY:
-            ctx->pipe->bind_geometry_sampler_states(ctx->pipe,
-                                                  info->nr_samplers,
-                                                  info->samplers);
-            break;
-         default:
-            assert(!"bad shader type in single_sampler_done()");
-         }
-      }
+      /* set remaining slots/pointers to null */
+      for (i = info->nr_samplers; i < info->hw.nr_samplers; i++)
+         info->samplers[i] = NULL;
+
+      ctx->pipe->bind_sampler_states(ctx->pipe, shader_stage, 0,
+                                     MAX2(info->nr_samplers,
+                                          info->hw.nr_samplers),
+                                     info->samplers);
+
+      info->hw.nr_samplers = info->nr_samplers;
    }
 }
 
@@ -1191,85 +1277,74 @@ cso_set_sampler_views(struct cso_context *ctx,
                       unsigned count,
                       struct pipe_sampler_view **views)
 {
-   struct sampler_info *info = &ctx->samplers[shader_stage];
-   unsigned i;
+   if (shader_stage == PIPE_SHADER_FRAGMENT) {
+      unsigned i;
+      boolean any_change = FALSE;
 
-   /* reference new views */
-   for (i = 0; i < count; i++) {
-      pipe_sampler_view_reference(&info->views[i], views[i]);
-   }
-   /* unref extra old views, if any */
-   for (; i < info->nr_views; i++) {
-      pipe_sampler_view_reference(&info->views[i], NULL);
-   }
+      /* reference new views */
+      for (i = 0; i < count; i++) {
+         any_change |= ctx->fragment_views[i] != views[i];
+         pipe_sampler_view_reference(&ctx->fragment_views[i], views[i]);
+      }
+      /* unref extra old views, if any */
+      for (; i < ctx->nr_fragment_views; i++) {
+         any_change |= ctx->fragment_views[i] != NULL;
+         pipe_sampler_view_reference(&ctx->fragment_views[i], NULL);
+      }
 
-   info->nr_views = count;
+      /* bind the new sampler views */
+      if (any_change) {
+         ctx->pipe->set_sampler_views(ctx->pipe, shader_stage, 0,
+                                      MAX2(ctx->nr_fragment_views, count),
+                                      ctx->fragment_views);
+      }
 
-   /* bind the new sampler views */
-   switch (shader_stage) {
-   case PIPE_SHADER_FRAGMENT:
-      ctx->pipe->set_fragment_sampler_views(ctx->pipe, count, info->views);
-      break;
-   case PIPE_SHADER_VERTEX:
-      ctx->pipe->set_vertex_sampler_views(ctx->pipe, count, info->views);
-      break;
-   case PIPE_SHADER_GEOMETRY:
-      ctx->pipe->set_geometry_sampler_views(ctx->pipe, count, info->views);
-      break;
-   default:
-      assert(!"bad shader type in cso_set_sampler_views()");
+      ctx->nr_fragment_views = count;
    }
+   else
+      ctx->pipe->set_sampler_views(ctx->pipe, shader_stage, 0, count, views);
 }
 
 
 void
-cso_save_sampler_views(struct cso_context *ctx, unsigned shader_stage)
+cso_save_fragment_sampler_views(struct cso_context *ctx)
 {
-   struct sampler_info *info = &ctx->samplers[shader_stage];
    unsigned i;
 
-   info->nr_views_saved = info->nr_views;
+   ctx->nr_fragment_views_saved = ctx->nr_fragment_views;
 
-   for (i = 0; i < info->nr_views; i++) {
-      assert(!info->views_saved[i]);
-      pipe_sampler_view_reference(&info->views_saved[i], info->views[i]);
+   for (i = 0; i < ctx->nr_fragment_views; i++) {
+      assert(!ctx->fragment_views_saved[i]);
+      pipe_sampler_view_reference(&ctx->fragment_views_saved[i],
+                                  ctx->fragment_views[i]);
    }
 }
 
 
 void
-cso_restore_sampler_views(struct cso_context *ctx, unsigned shader_stage)
+cso_restore_fragment_sampler_views(struct cso_context *ctx)
 {
-   struct sampler_info *info = &ctx->samplers[shader_stage];
-   unsigned i, nr_saved = info->nr_views_saved;
+   unsigned i, nr_saved = ctx->nr_fragment_views_saved;
+   unsigned num;
 
    for (i = 0; i < nr_saved; i++) {
-      pipe_sampler_view_reference(&info->views[i], NULL);
+      pipe_sampler_view_reference(&ctx->fragment_views[i], NULL);
       /* move the reference from one pointer to another */
-      info->views[i] = info->views_saved[i];
-      info->views_saved[i] = NULL;
+      ctx->fragment_views[i] = ctx->fragment_views_saved[i];
+      ctx->fragment_views_saved[i] = NULL;
    }
-   for (; i < info->nr_views; i++) {
-      pipe_sampler_view_reference(&info->views[i], NULL);
+   for (; i < ctx->nr_fragment_views; i++) {
+      pipe_sampler_view_reference(&ctx->fragment_views[i], NULL);
    }
 
+   num = MAX2(ctx->nr_fragment_views, nr_saved);
+
    /* bind the old/saved sampler views */
-   switch (shader_stage) {
-   case PIPE_SHADER_FRAGMENT:
-      ctx->pipe->set_fragment_sampler_views(ctx->pipe, nr_saved, info->views);
-      break;
-   case PIPE_SHADER_VERTEX:
-      ctx->pipe->set_vertex_sampler_views(ctx->pipe, nr_saved, info->views);
-      break;
-   case PIPE_SHADER_GEOMETRY:
-      ctx->pipe->set_geometry_sampler_views(ctx->pipe, nr_saved, info->views);
-      break;
-   default:
-      assert(!"bad shader type in cso_restore_sampler_views()");
-   }
+   ctx->pipe->set_sampler_views(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, num,
+                                ctx->fragment_views);
 
-   info->nr_views = nr_saved;
-   info->nr_views_saved = 0;
+   ctx->nr_fragment_views = nr_saved;
+   ctx->nr_fragment_views_saved = 0;
 }
 
 
@@ -1277,7 +1352,7 @@ void
 cso_set_stream_outputs(struct cso_context *ctx,
                        unsigned num_targets,
                        struct pipe_stream_output_target **targets,
-                       unsigned append_bitmask)
+                       const unsigned *offsets)
 {
    struct pipe_context *pipe = ctx->pipe;
    uint i;
@@ -1302,7 +1377,7 @@ cso_set_stream_outputs(struct cso_context *ctx,
    }
 
    pipe->set_stream_output_targets(pipe, num_targets, targets,
-                                   append_bitmask);
+                                   offsets);
    ctx->nr_so_targets = num_targets;
 }
 
@@ -1328,6 +1403,7 @@ cso_restore_stream_outputs(struct cso_context *ctx)
 {
    struct pipe_context *pipe = ctx->pipe;
    uint i;
+   unsigned offset[PIPE_MAX_SO_BUFFERS];
 
    if (!ctx->has_streamout) {
       return;
@@ -1338,19 +1414,21 @@ cso_restore_stream_outputs(struct cso_context *ctx)
       return;
    }
 
+   assert(ctx->nr_so_targets_saved <= PIPE_MAX_SO_BUFFERS);
    for (i = 0; i < ctx->nr_so_targets_saved; i++) {
       pipe_so_target_reference(&ctx->so_targets[i], NULL);
       /* move the reference from one pointer to another */
       ctx->so_targets[i] = ctx->so_targets_saved[i];
       ctx->so_targets_saved[i] = NULL;
+      /* -1 means append */
+      offset[i] = (unsigned)-1;
    }
    for (; i < ctx->nr_so_targets; i++) {
       pipe_so_target_reference(&ctx->so_targets[i], NULL);
    }
 
-   /* ~0 means append */
    pipe->set_stream_output_targets(pipe, ctx->nr_so_targets_saved,
-                                   ctx->so_targets, ~0);
+                                   ctx->so_targets, offset);
 
    ctx->nr_so_targets = ctx->nr_so_targets_saved;
    ctx->nr_so_targets_saved = 0;
@@ -1452,3 +1530,23 @@ cso_draw_arrays(struct cso_context *cso, uint mode, uint start, uint count)
 
    cso_draw_vbo(cso, &info);
 }
+
+void
+cso_draw_arrays_instanced(struct cso_context *cso, uint mode,
+                          uint start, uint count,
+                          uint start_instance, uint instance_count)
+{
+   struct pipe_draw_info info;
+
+   util_draw_init_info(&info);
+
+   info.mode = mode;
+   info.start = start;
+   info.count = count;
+   info.min_index = start;
+   info.max_index = start + count - 1;
+   info.start_instance = start_instance;
+   info.instance_count = instance_count;
+
+   cso_draw_vbo(cso, &info);
+}