nvc0: kill assert in ppp code
[mesa.git] / src / gallium / drivers / softpipe / sp_state_shader.c
index 50bc2eea5ffc0a2f930fe76e14d0f8fabbd9615e..79bd597ebcb89dffee8d5da64e2172833959cda1 100644 (file)
 #include "pipe/p_defines.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
+#include "util/u_pstipple.h"
 #include "draw/draw_context.h"
 #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"
 
 
-void *
+/**
+ * Create a new fragment shader variant.
+ */
+static struct sp_fragment_shader_variant *
+create_fs_variant(struct softpipe_context *softpipe,
+                  struct sp_fragment_shader *fs,
+                  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 DO_PSTIPPLE_IN_HELPER_MODULE
+   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;
+   }
+#endif
+
+   /* codegen, create variant object */
+   var = softpipe_create_fs_variant_exec(softpipe, curfs);
+
+   if (var) {
+      var->key = *key;
+      var->tokens = tgsi_dup_tokens(curfs->tokens);
+      var->stipple_sampler_unit = unit;
+
+      tgsi_scan_shader(var->tokens, &var->info);
+
+      /* See comments elsewhere about draw fragment shaders */
+#if 0
+      /* draw's fs state */
+      var->draw_shader = draw_create_fragment_shader(softpipe->draw,
+                                                     &fs->shader);
+      if (!var->draw_shader) {
+         var->delete(var);
+         FREE((void *) var->tokens);
+         return NULL;
+      }
+#endif
+
+      /* insert variant into linked list */
+      var->next = fs->variants;
+      fs->variants = var;
+   }
+
+   if (stipple_fs) {
+      FREE((void *) stipple_fs->tokens);
+      FREE(stipple_fs);
+   }
+
+   return var;
+}
+
+
+struct sp_fragment_shader_variant *
+softpipe_find_fs_variant(struct softpipe_context *sp,
+                         struct sp_fragment_shader *fs,
+                         const struct sp_fragment_shader_variant_key *key)
+{
+   struct sp_fragment_shader_variant *var;
+
+   for (var = fs->variants; var; var = var->next) {
+      if (memcmp(&var->key, key, sizeof(*key)) == 0) {
+         /* found it */
+         return var;
+      }
+   }
+
+   return create_fs_variant(sp, fs, key);
+}
+
+
+static void *
 softpipe_create_fs_state(struct pipe_context *pipe,
                          const struct pipe_shader_state *templ)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
-   struct sp_fragment_shader *state;
-   unsigned i;
+   struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader);
 
    /* debug */
    if (softpipe->dump_fs) 
       tgsi_dump(templ->tokens, 0);
 
-   /* codegen */
-   state = softpipe_create_fs_sse( softpipe, templ );
-   if (!state) {
-      state = softpipe_create_fs_exec( softpipe, templ );
-   }
-
-   if (!state)
-      return NULL;
+   /* we need to keep a local copy of the tokens */
+   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
 
    /* draw's fs state */
-   state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ);
+   state->draw_shader = draw_create_fragment_shader(softpipe->draw,
+                                                    &state->shader);
    if (!state->draw_shader) {
-      state->delete( state );
+      FREE((void *) state->shader.tokens);
+      FREE(state);
       return NULL;
    }
 
-   /* get/save the summary info for this shader */
-   tgsi_scan_shader(templ->tokens, &state->info);
-
-   for (i = 0; i < state->info.num_properties; ++i) {
-      if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN)
-         state->origin_lower_left = state->info.properties[i].data[0];
-      else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_PIXEL_CENTER)
-        state->pixel_center_integer = state->info.properties[i].data[0];
-   }
-
    return state;
 }
 
 
-void
+static void
 softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
-
-   draw_flush(softpipe->draw);
+   struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs;
 
    if (softpipe->fs == fs)
       return;
@@ -98,35 +157,52 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
 
    softpipe->fs = fs;
 
-   draw_bind_fragment_shader(softpipe->draw,
-                             (softpipe->fs ? softpipe->fs->draw_shader : 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,
+                                state->draw_shader);
+   else
+      draw_bind_fragment_shader(softpipe->draw, NULL);
 
    softpipe->dirty |= SP_NEW_FS;
 }
 
 
-void
+static void
 softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
    struct sp_fragment_shader *state = fs;
+   struct sp_fragment_shader_variant *var, *next_var;
 
-   assert(fs != softpipe_context(pipe)->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;
+
+      assert(var != softpipe->fs_variant);
+
+      /* See comments elsewhere about draw fragment shaders */
+#if 0
+      draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
+#endif
+
+      var->delete(var, softpipe->fs_machine);
    }
 
    draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
 
-   state->delete( state );
+   FREE((void *) state->shader.tokens);
+   FREE(state);
 }
 
 
-void *
+static void *
 softpipe_create_vs_state(struct pipe_context *pipe,
                          const struct pipe_shader_state *templ)
 {
@@ -161,7 +237,7 @@ fail:
 }
 
 
-void
+static void
 softpipe_bind_vs_state(struct pipe_context *pipe, void *vs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
@@ -175,7 +251,7 @@ softpipe_bind_vs_state(struct pipe_context *pipe, void *vs)
 }
 
 
-void
+static void
 softpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
@@ -187,34 +263,8 @@ softpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
    FREE( state );
 }
 
-void
-softpipe_set_constant_buffer(struct pipe_context *pipe,
-                             uint shader, uint index,
-                             struct pipe_resource *constants)
-{
-   struct softpipe_context *softpipe = softpipe_context(pipe);
-   unsigned size = constants ? constants->width0 : 0;
-   const void *data = constants ? softpipe_resource(constants)->data : NULL;
-
-   assert(shader < PIPE_SHADER_TYPES);
-
-   draw_flush(softpipe->draw);
-
-   /* note: reference counting */
-   pipe_resource_reference(&softpipe->constants[shader][index], constants);
-
-   if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
-      draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size);
-   }
-
-   softpipe->mapped_constants[shader][index] = data;
-   softpipe->const_buffer_size[shader][index] = size;
 
-   softpipe->dirty |= SP_NEW_CONSTANTS;
-}
-
-
-void *
+static void *
 softpipe_create_gs_state(struct pipe_context *pipe,
                          const struct pipe_shader_state *templ)
 {
@@ -225,21 +275,25 @@ softpipe_create_gs_state(struct pipe_context *pipe,
    if (state == NULL )
       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;
 
@@ -253,7 +307,7 @@ fail:
 }
 
 
-void
+static void
 softpipe_bind_gs_state(struct pipe_context *pipe, void *gs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
@@ -267,7 +321,7 @@ softpipe_bind_gs_state(struct pipe_context *pipe, void *gs)
 }
 
 
-void
+static void
 softpipe_delete_gs_state(struct pipe_context *pipe, void *gs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
@@ -277,5 +331,68 @@ softpipe_delete_gs_state(struct pipe_context *pipe, void *gs)
 
    draw_delete_geometry_shader(softpipe->draw,
                                (state) ? state->draw_data : 0);
+
+   FREE((void *) state->shader.tokens);
    FREE(state);
 }
+
+
+static void
+softpipe_set_constant_buffer(struct pipe_context *pipe,
+                             uint shader, uint index,
+                             struct pipe_constant_buffer *cb)
+{
+   struct softpipe_context *softpipe = softpipe_context(pipe);
+   struct pipe_resource *constants = cb ? cb->buffer : NULL;
+   unsigned size;
+   const void *data;
+
+   if (cb && cb->user_buffer) {
+      constants = softpipe_user_buffer_create(pipe->screen,
+                                              (void *) cb->user_buffer,
+                                              cb->buffer_size,
+                                              PIPE_BIND_CONSTANT_BUFFER);
+   }
+
+   size = constants ? constants->width0 : 0;
+   data = constants ? softpipe_resource(constants)->data : NULL;
+
+   assert(shader < PIPE_SHADER_TYPES);
+
+   draw_flush(softpipe->draw);
+
+   /* note: reference counting */
+   pipe_resource_reference(&softpipe->constants[shader][index], constants);
+
+   if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
+      draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size);
+   }
+
+   softpipe->mapped_constants[shader][index] = data;
+   softpipe->const_buffer_size[shader][index] = size;
+
+   softpipe->dirty |= SP_NEW_CONSTANTS;
+
+   if (cb && cb->user_buffer) {
+      pipe_resource_reference(&constants, NULL);
+   }
+}
+
+
+void
+softpipe_init_shader_funcs(struct pipe_context *pipe)
+{
+   pipe->create_fs_state = softpipe_create_fs_state;
+   pipe->bind_fs_state   = softpipe_bind_fs_state;
+   pipe->delete_fs_state = softpipe_delete_fs_state;
+
+   pipe->create_vs_state = softpipe_create_vs_state;
+   pipe->bind_vs_state   = softpipe_bind_vs_state;
+   pipe->delete_vs_state = softpipe_delete_vs_state;
+
+   pipe->create_gs_state = softpipe_create_gs_state;
+   pipe->bind_gs_state   = softpipe_bind_gs_state;
+   pipe->delete_gs_state = softpipe_delete_gs_state;
+
+   pipe->set_constant_buffer = softpipe_set_constant_buffer;
+}