v3d: Add SSBO/atomic counters support.
[mesa.git] / src / gallium / drivers / softpipe / sp_state_shader.c
index da895270aa97b398b1ad248b455a9e71d0b8fa30..da4792757f1b6420819899c98c15fcfe853101bc 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.
@@ -38,7 +38,6 @@
 #include "draw/draw_vs.h"
 #include "draw/draw_gs.h"
 #include "tgsi/tgsi_dump.h"
-#include "tgsi/tgsi_exec.h"
 #include "tgsi/tgsi_scan.h"
 #include "tgsi/tgsi_parse.h"
 
@@ -52,26 +51,28 @@ create_fs_variant(struct softpipe_context *softpipe,
                   const struct sp_fragment_shader_variant_key *key)
 {
    struct sp_fragment_shader_variant *var;
-   struct pipe_shader_state *stipple_fs = NULL, *curfs = &fs->shader;
-   unsigned unit = 0;
-
-   if (key->polygon_stipple) {
-      /* get new shader that implements polygon stippling */
-      stipple_fs = util_pstipple_create_fragment_shader(&softpipe->pipe,
-                                                        curfs, &unit);
-      curfs = stipple_fs;
-   }
+   struct pipe_shader_state *curfs = &fs->shader;
 
    /* codegen, create variant object */
-   var = softpipe_create_fs_variant_sse(softpipe, curfs);
-   if (!var) {
-      var = softpipe_create_fs_variant_exec(softpipe, curfs);
-   }
+   var = softpipe_create_fs_variant_exec(softpipe);
 
    if (var) {
       var->key = *key;
-      var->tokens = tgsi_dup_tokens(curfs->tokens);
-      var->stipple_sampler_unit = unit;
+
+#if DO_PSTIPPLE_IN_HELPER_MODULE
+      if (key->polygon_stipple) {
+         /* get new shader that implements polygon stippling */
+         var->tokens = 
+            util_pstipple_create_fragment_shader(curfs->tokens,
+                                                 &var->stipple_sampler_unit, 0,
+                                                 TGSI_FILE_INPUT);
+      }
+      else
+#endif
+      {
+         var->tokens = tgsi_dup_tokens(curfs->tokens);
+         var->stipple_sampler_unit = 0;
+      }
 
       tgsi_scan_shader(var->tokens, &var->info);
 
@@ -92,11 +93,6 @@ create_fs_variant(struct softpipe_context *softpipe,
       fs->variants = var;
    }
 
-   if (stipple_fs) {
-      free((void *) stipple_fs->tokens);
-      free(stipple_fs);
-   }
-
    return var;
 }
 
@@ -137,7 +133,7 @@ softpipe_create_fs_state(struct pipe_context *pipe,
    state->draw_shader = draw_create_fragment_shader(softpipe->draw,
                                                     &state->shader);
    if (!state->draw_shader) {
-      FREE((void *) state->shader.tokens);
+      tgsi_free_tokens(state->shader.tokens);
       FREE(state);
       return NULL;
    }
@@ -159,8 +155,10 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
 
    softpipe->fs = fs;
 
-   if (fs == NULL)
-      softpipe->fs_variant = NULL;
+   /* This depends on the current fragment shader and must always be
+    * re-validated before use.
+    */
+   softpipe->fs_variant = NULL;
 
    if (state)
       draw_bind_fragment_shader(softpipe->draw,
@@ -181,13 +179,6 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
 
    assert(fs != softpipe->fs);
 
-   if (softpipe->fs_machine->Tokens == state->shader.tokens) {
-      /* unbind the shader from the tgsi executor if we're
-       * deleting it.
-       */
-      tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL);
-   }
-
    /* delete variants */
    for (var = state->variants; var; var = next_var) {
       next_var = var->next;
@@ -199,12 +190,13 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
       draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
 #endif
 
-      var->delete(var);
+      var->delete(var, softpipe->fs_machine);
    }
 
    draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
 
-   FREE((void *) state->shader.tokens);
+   tgsi_free_tokens(state->shader.tokens);
+   FREE(state);
 }
 
 
@@ -216,7 +208,7 @@ softpipe_create_vs_state(struct pipe_context *pipe,
    struct sp_vertex_shader *state;
 
    state = CALLOC_STRUCT(sp_vertex_shader);
-   if (state == NULL ) 
+   if (!state)
       goto fail;
 
    /* copy shader tokens, the ones passed in will go away.
@@ -235,7 +227,7 @@ softpipe_create_vs_state(struct pipe_context *pipe,
 
 fail:
    if (state) {
-      FREE( (void *)state->shader.tokens );
+      tgsi_free_tokens(state->shader.tokens);
       FREE( state->draw_data );
       FREE( state );
    }
@@ -265,7 +257,7 @@ softpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
    struct sp_vertex_shader *state = (struct sp_vertex_shader *) vs;
 
    draw_delete_vertex_shader(softpipe->draw, state->draw_data);
-   FREE( (void *)state->shader.tokens );
+   tgsi_free_tokens(state->shader.tokens);
    FREE( state );
 }
 
@@ -278,30 +270,34 @@ softpipe_create_gs_state(struct pipe_context *pipe,
    struct sp_geometry_shader *state;
 
    state = CALLOC_STRUCT(sp_geometry_shader);
-   if (state == NULL )
+   if (!state)
       goto fail;
 
-   /* debug */
-   if (softpipe->dump_gs)
-      tgsi_dump(templ->tokens, 0);
+   state->shader = *templ;
 
-   /* copy shader tokens, the ones passed in will go away.
-    */
-   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
-   if (state->shader.tokens == NULL)
-      goto fail;
+   if (templ->tokens) {
+      /* debug */
+      if (softpipe->dump_gs)
+         tgsi_dump(templ->tokens, 0);
 
-   state->draw_data = draw_create_geometry_shader(softpipe->draw, templ);
-   if (state->draw_data == NULL)
-      goto fail;
+      /* copy shader tokens, the ones passed in will go away.
+       */
+      state->shader.tokens = tgsi_dup_tokens(templ->tokens);
+      if (state->shader.tokens == NULL)
+         goto fail;
 
-   state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
+      state->draw_data = draw_create_geometry_shader(softpipe->draw, templ);
+      if (state->draw_data == NULL)
+         goto fail;
+
+      state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
+   }
 
    return state;
 
 fail:
    if (state) {
-      FREE( (void *)state->shader.tokens );
+      tgsi_free_tokens(state->shader.tokens);
       FREE( state->draw_data );
       FREE( state );
    }
@@ -333,21 +329,36 @@ softpipe_delete_gs_state(struct pipe_context *pipe, void *gs)
 
    draw_delete_geometry_shader(softpipe->draw,
                                (state) ? state->draw_data : 0);
+
+   tgsi_free_tokens(state->shader.tokens);
    FREE(state);
 }
 
 
 static void
 softpipe_set_constant_buffer(struct pipe_context *pipe,
-                             uint shader, uint index,
-                             struct pipe_resource *constants)
+                             enum pipe_shader_type shader, uint index,
+                             const struct pipe_constant_buffer *cb)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
-   unsigned size = constants ? constants->width0 : 0;
-   const void *data = constants ? softpipe_resource(constants)->data : NULL;
+   struct pipe_resource *constants = cb ? cb->buffer : NULL;
+   unsigned size;
+   const void *data;
 
    assert(shader < PIPE_SHADER_TYPES);
 
+   if (cb && cb->user_buffer) {
+      constants = softpipe_user_buffer_create(pipe->screen,
+                                              (void *) cb->user_buffer,
+                                              cb->buffer_size,
+                                              PIPE_BIND_CONSTANT_BUFFER);
+   }
+
+   size = cb ? cb->buffer_size : 0;
+   data = constants ? softpipe_resource_data(constants) : NULL;
+   if (data)
+      data = (const char *) data + cb->buffer_offset;
+
    draw_flush(softpipe->draw);
 
    /* note: reference counting */
@@ -361,8 +372,61 @@ softpipe_set_constant_buffer(struct pipe_context *pipe,
    softpipe->const_buffer_size[shader][index] = size;
 
    softpipe->dirty |= SP_NEW_CONSTANTS;
+
+   if (cb && cb->user_buffer) {
+      pipe_resource_reference(&constants, NULL);
+   }
+}
+
+static void *
+softpipe_create_compute_state(struct pipe_context *pipe,
+                              const struct pipe_compute_state *templ)
+{
+   struct softpipe_context *softpipe = softpipe_context(pipe);
+   const struct tgsi_token *tokens;
+   struct sp_compute_shader *state;
+   if (templ->ir_type != PIPE_SHADER_IR_TGSI)
+      return NULL;
+
+   tokens = templ->prog;
+   /* debug */
+   if (softpipe->dump_cs)
+      tgsi_dump(tokens, 0);
+
+   state = CALLOC_STRUCT(sp_compute_shader);
+
+   state->shader = *templ;
+   state->tokens = tgsi_dup_tokens(tokens);
+   tgsi_scan_shader(state->tokens, &state->info);
+
+   state->max_sampler = state->info.file_max[TGSI_FILE_SAMPLER];
+
+   return state;
+}
+
+static void
+softpipe_bind_compute_state(struct pipe_context *pipe,
+                            void *cs)
+{
+   struct softpipe_context *softpipe = softpipe_context(pipe);
+   struct sp_compute_shader *state = (struct sp_compute_shader *)cs;
+   if (softpipe->cs == state)
+      return;
+
+   softpipe->cs = state;
 }
 
+static void
+softpipe_delete_compute_state(struct pipe_context *pipe,
+                              void *cs)
+{
+   MAYBE_UNUSED struct softpipe_context *softpipe = softpipe_context(pipe);
+   struct sp_compute_shader *state = (struct sp_compute_shader *)cs;
+
+   assert(softpipe->cs != state);
+   tgsi_free_tokens(state->tokens);
+   FREE(state);
+}
 
 void
 softpipe_init_shader_funcs(struct pipe_context *pipe)
@@ -380,4 +444,8 @@ softpipe_init_shader_funcs(struct pipe_context *pipe)
    pipe->delete_gs_state = softpipe_delete_gs_state;
 
    pipe->set_constant_buffer = softpipe_set_constant_buffer;
+
+   pipe->create_compute_state = softpipe_create_compute_state;
+   pipe->bind_compute_state = softpipe_bind_compute_state;
+   pipe->delete_compute_state = softpipe_delete_compute_state;
 }