Squashed commit of the following:
[mesa.git] / src / gallium / drivers / i965 / brw_pipe_shader.c
index fbb772d18c999f3fd75af33ff999fc57d6850b0f..d9bee96c11f73ad2ed099e87b300f5df2eac5bd4 100644 (file)
   * Authors:
   *   Keith Whitwell <keith@tungstengraphics.com>
   */
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
   
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_scan.h"
+
 #include "brw_context.h"
-#include "brw_util.h"
 #include "brw_wm.h"
 
-static void brwBindProgram( struct brw_context *brw,
-                           GLenum target, 
-                           struct gl_program *prog )
+
+/**
+ * Determine if the given shader uses complex features such as flow
+ * conditionals, loops, subroutines.
+ */
+static GLboolean has_flow_control(const struct tgsi_shader_info *info)
 {
-   struct brw_context *brw = brw_context(ctx);
-
-   switch (target) {
-   case GL_VERTEX_PROGRAM_ARB: 
-      brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
-      break;
-   case GL_FRAGMENT_PROGRAM_ARB:
-      brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
-      break;
-   }
+    return (info->opcode_count[TGSI_OPCODE_ARL] > 0 ||
+           info->opcode_count[TGSI_OPCODE_IF] > 0 ||
+           info->opcode_count[TGSI_OPCODE_ENDIF] > 0 || /* redundant - IF */
+           info->opcode_count[TGSI_OPCODE_CAL] > 0 ||
+           info->opcode_count[TGSI_OPCODE_BRK] > 0 ||   /* redundant - BGNLOOP */
+           info->opcode_count[TGSI_OPCODE_RET] > 0 ||   /* redundant - CAL */
+           info->opcode_count[TGSI_OPCODE_BGNLOOP] > 0);
 }
 
-static struct gl_program *brwNewProgram( structg brw_context *brw,
-                                     GLenum target, 
-                                     GLuint id )
+
+static void scan_immediates(const struct tgsi_token *tokens,
+                            const struct tgsi_shader_info *info,
+                            struct brw_immediate_data *imm)
 {
-   struct brw_context *brw = brw_context(ctx);
+   struct tgsi_parse_context parse;
+   boolean done = FALSE;
+
+   imm->nr = 0;
+   imm->data = MALLOC(info->immediate_count * 4 * sizeof(float));
+
+   tgsi_parse_init( &parse, tokens );
+   while (!tgsi_parse_end_of_tokens( &parse ) && !done) {
+      tgsi_parse_token( &parse );
 
-   switch (target) {
-   case GL_VERTEX_PROGRAM_ARB: {
-      struct brw_vertex_program *prog = CALLOC_STRUCT(brw_vertex_program);
-      if (prog) {
-        prog->id = brw->program_id++;
+      switch (parse.FullToken.Token.Type) {
+      case TGSI_TOKEN_TYPE_DECLARATION:
+         break;
 
-        return _mesa_init_vertex_program( ctx, &prog->program,
-                                            target, id );
+      case TGSI_TOKEN_TYPE_IMMEDIATE: {
+        static const float id[4] = {0,0,0,1};
+        const float *value = &parse.FullToken.FullImmediate.u[0].Float;
+        unsigned size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
+         unsigned i;
+
+        for (i = 0; i < size; i++)
+           imm->data[imm->nr][i] = value[i];
+
+        for (; i < 4; i++)
+           imm->data[imm->nr][i] = id[i];
+         
+         imm->nr++;
+        break;
+      }
+
+      case TGSI_TOKEN_TYPE_INSTRUCTION:
+        done = 1;
+        break;
       }
-      else
-        return NULL;
    }
+}
 
-   case GL_FRAGMENT_PROGRAM_ARB: {
-      struct brw_fragment_program *prog = CALLOC_STRUCT(brw_fragment_program);
-      if (prog) {
-        prog->id = brw->program_id++;
 
-        return _mesa_init_fragment_program( ctx, &prog->program,
-                                            target, id );
-      }
-      else
-        return NULL;
+static void brw_bind_fs_state( struct pipe_context *pipe, void *prog )
+{
+   struct brw_fragment_shader *fs = (struct brw_fragment_shader *)prog;
+   struct brw_context *brw = brw_context(pipe);
+   
+   if (brw->curr.fragment_shader == fs)
+      return;
+
+   if (brw->curr.fragment_shader == NULL ||
+       fs == NULL ||
+       memcmp(&brw->curr.fragment_shader->signature, &fs->signature,
+              brw_fs_signature_size(&fs->signature)) != 0) {
+      brw->state.dirty.mesa |= PIPE_NEW_FRAGMENT_SIGNATURE;
    }
 
-   default:
-      return _mesa_new_program(ctx, target, id);
+   brw->curr.fragment_shader = fs;
+   brw->state.dirty.mesa |= PIPE_NEW_FRAGMENT_SHADER;
+}
+
+static void brw_bind_vs_state( struct pipe_context *pipe, void *prog )
+{
+   struct brw_context *brw = brw_context(pipe);
+
+   brw->curr.vertex_shader = (struct brw_vertex_shader *)prog;
+   brw->state.dirty.mesa |= PIPE_NEW_VERTEX_SHADER;
+}
+
+
+
+static void *brw_create_fs_state( struct pipe_context *pipe,
+                                 const struct pipe_shader_state *shader )
+{
+   struct brw_context *brw = brw_context(pipe);
+   struct brw_fragment_shader *fs;
+   int i;
+
+   fs = CALLOC_STRUCT(brw_fragment_shader);
+   if (fs == NULL)
+      return NULL;
+
+   /* Duplicate tokens, scan shader
+    */
+   fs->id = brw->program_id++;
+   fs->has_flow_control = has_flow_control(&fs->info);
+
+   fs->tokens = tgsi_dup_tokens(shader->tokens);
+   if (fs->tokens == NULL)
+      goto fail;
+
+   tgsi_scan_shader(fs->tokens, &fs->info);
+   scan_immediates(fs->tokens, &fs->info, &fs->immediates);
+
+   fs->signature.nr_inputs = fs->info.num_inputs;
+   for (i = 0; i < fs->info.num_inputs; i++) {
+      fs->signature.input[i].interp = fs->info.input_interpolate[i];
+      fs->signature.input[i].semantic = fs->info.input_semantic_name[i];
+      fs->signature.input[i].semantic_index = fs->info.input_semantic_index[i];
    }
+
+   for (i = 0; i < fs->info.num_inputs; i++)
+      if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_POSITION)
+        fs->uses_depth = 1;
+
+   if (fs->info.uses_kill)
+      fs->iz_lookup |= IZ_PS_KILL_ALPHATEST_BIT;
+
+   if (fs->info.writes_z)
+      fs->iz_lookup |= IZ_PS_COMPUTES_DEPTH_BIT;
+
+   return (void *)fs;
+
+fail:
+   FREE(fs);
+   return NULL;
 }
 
-static void brwDeleteProgram( struct brw_context *brw,
-                             struct gl_program *prog )
+
+static void *brw_create_vs_state( struct pipe_context *pipe,
+                                 const struct pipe_shader_state *shader )
 {
-   if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
-      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
-      struct brw_fragment_program *brw_fprog = brw_fragment_program(fprog);
-      brw->sws->bo_unreference(brw_fprog->const_buffer);
+   struct brw_context *brw = brw_context(pipe);
+   struct brw_vertex_shader *vs;
+   unsigned i;
+
+   vs = CALLOC_STRUCT(brw_vertex_shader);
+   if (vs == NULL)
+      return NULL;
+
+   /* Duplicate tokens, scan shader
+    */
+   vs->tokens = tgsi_dup_tokens(shader->tokens);
+   if (vs->tokens == NULL)
+      goto fail;
+
+   tgsi_scan_shader(vs->tokens, &vs->info);
+   scan_immediates(vs->tokens, &vs->info, &vs->immediates);
+
+   vs->id = brw->program_id++;
+   vs->has_flow_control = has_flow_control(&vs->info);
+
+   vs->output_hpos = BRW_OUTPUT_NOT_PRESENT;
+   vs->output_color0 = BRW_OUTPUT_NOT_PRESENT;
+   vs->output_color1 = BRW_OUTPUT_NOT_PRESENT;
+   vs->output_bfc0 = BRW_OUTPUT_NOT_PRESENT;
+   vs->output_bfc1 = BRW_OUTPUT_NOT_PRESENT;
+   vs->output_edgeflag = BRW_OUTPUT_NOT_PRESENT;
+
+   for (i = 0; i < vs->info.num_outputs; i++) {
+      int index = vs->info.output_semantic_index[i];
+      switch (vs->info.output_semantic_name[i]) {
+      case TGSI_SEMANTIC_POSITION:
+         vs->output_hpos = i;
+         break;
+      case TGSI_SEMANTIC_COLOR:
+         if (index == 0)
+            vs->output_color0 = i;
+         else
+            vs->output_color1 = i;
+         break;
+      case TGSI_SEMANTIC_BCOLOR:
+         if (index == 0)
+            vs->output_bfc0 = i;
+         else
+            vs->output_bfc1 = i;
+         break;
+      case TGSI_SEMANTIC_EDGEFLAG:
+         vs->output_edgeflag = i;
+         break;
+      }
    }
 
-   _mesa_delete_program( ctx, prog );
+   
+   /* Done:
+    */
+   return (void *)vs;
+
+fail:
+   FREE(vs);
+   return NULL;
 }
 
 
-static GLboolean brwIsProgramNative( struct brw_context *brw,
-                                    GLenum target, 
-                                    struct gl_program *prog )
+static void brw_delete_fs_state( struct pipe_context *pipe, void *prog )
 {
-   return GL_TRUE;
+   struct brw_fragment_shader *fs = (struct brw_fragment_shader *)prog;
+
+   bo_reference(&fs->const_buffer, NULL);
+   FREE( (void *)fs->tokens );
+   FREE( fs );
 }
 
-static void brwProgramStringNotify( struct brw_context *brw,
-                                   GLenum target,
-                                   struct gl_program *prog )
+
+static void brw_delete_vs_state( struct pipe_context *pipe, void *prog )
 {
-   struct brw_context *brw = brw_context(ctx);
+   struct brw_fragment_shader *vs = (struct brw_fragment_shader *)prog;
 
-   if (target == GL_FRAGMENT_PROGRAM_ARB) {
-      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
-      struct brw_fragment_program *newFP = brw_fragment_program(fprog);
-      const struct brw_fragment_program *curFP =
-         brw_fragment_program_const(brw->fragment_program);
+   /* Delete draw shader
+    */
+   FREE( (void *)vs->tokens );
+   FREE( vs );
+}
 
-      if (fprog->FogOption) {
-         _mesa_append_fog_code(ctx, fprog);
-         fprog->FogOption = GL_NONE;
-      }
 
-      if (newFP == curFP)
-        brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
-      newFP->id = brw->program_id++;      
-      newFP->isGLSL = brw_wm_is_glsl(fprog);
+static void brw_set_constant_buffer(struct pipe_context *pipe,
+                                     uint shader, uint index,
+                                     struct pipe_resource *buf)
+{
+   struct brw_context *brw = brw_context(pipe);
+
+   assert(index == 0);
+
+   if (shader == PIPE_SHADER_FRAGMENT) {
+      pipe_resource_reference( &brw->curr.fragment_constants,
+                             buf );
+
+      brw->state.dirty.mesa |= PIPE_NEW_FRAGMENT_CONSTANTS;
    }
-   else if (target == GL_VERTEX_PROGRAM_ARB) {
-      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
-      struct brw_vertex_program *newVP = brw_vertex_program(vprog);
-      const struct brw_vertex_program *curVP =
-         brw_vertex_program_const(brw->vertex_program);
-
-      if (newVP == curVP)
-        brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
-      if (newVP->program.IsPositionInvariant) {
-        _mesa_insert_mvp_code(ctx, &newVP->program);
-      }
-      newVP->id = brw->program_id++;      
+   else {
+      pipe_resource_reference( &brw->curr.vertex_constants,
+                             buf );
 
-      /* Also tell tnl about it:
-       */
-      _tnl_program_string(ctx, target, prog);
+      brw->state.dirty.mesa |= PIPE_NEW_VERTEX_CONSTANTS;
    }
 }
 
-void brwInitFragProgFuncs( struct dd_function_table *functions )
+
+void brw_pipe_shader_init( struct brw_context *brw )
 {
-   assert(functions->ProgramStringNotify == _tnl_program_string); 
+   brw->base.set_constant_buffer = brw_set_constant_buffer;
 
-   functions->BindProgram = brwBindProgram;
-   functions->NewProgram = brwNewProgram;
-   functions->DeleteProgram = brwDeleteProgram;
-   functions->IsProgramNative = brwIsProgramNative;
-   functions->ProgramStringNotify = brwProgramStringNotify;
+   brw->base.create_vs_state = brw_create_vs_state;
+   brw->base.bind_vs_state = brw_bind_vs_state;
+   brw->base.delete_vs_state = brw_delete_vs_state;
+
+   brw->base.create_fs_state = brw_create_fs_state;
+   brw->base.bind_fs_state = brw_bind_fs_state;
+   brw->base.delete_fs_state = brw_delete_fs_state;
 }
 
+void brw_pipe_shader_cleanup( struct brw_context *brw )
+{
+   pipe_resource_reference( &brw->curr.fragment_constants, NULL );
+   pipe_resource_reference( &brw->curr.vertex_constants, NULL );
+}