mesa: merge gallium-0.2 into gallium-master-merge
[mesa.git] / src / mesa / shader / arbprogparse.c
index 74004e9b137f8d9000aad5605e2d26958836d092..2e0fc3694a4f709377ff9968227553868d2553f3 100644 (file)
  * \author Karl Rasche
  */
 
+/**
+Notes on program parameters, etc.
+
+The instructions we emit will use six kinds of source registers:
+
+  PROGRAM_INPUT      - input registers
+  PROGRAM_TEMPORARY  - temp registers
+  PROGRAM_ADDRESS    - address/indirect register
+  PROGRAM_SAMPLER    - texture sampler
+  PROGRAM_CONSTANT   - indexes into program->Parameters, a known constant/literal
+  PROGRAM_STATE_VAR  - indexes into program->Parameters, and may actually be:
+                       + a state variable, like "state.fog.color", or
+                       + a pointer to a "program.local[k]" parameter, or
+                       + a pointer to a "program.env[k]" parameter
+
+Basically, all the program.local[] and program.env[] values will get mapped
+into the unified gl_program->Parameters array.  This solves the problem of
+having three separate program parameter arrays.
+*/
+
+
 #include "main/glheader.h"
 #include "main/imports.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
 #include "shader/grammar/grammar_mesa.h"
 #include "arbprogparse.h"
 #include "program.h"
+#include "programopt.h"
 #include "prog_parameter.h"
 #include "prog_statevars.h"
-#include "context.h"
-#include "macros.h"
-#include "mtypes.h"
 #include "prog_instruction.h"
 
-
-/* For ARB programs, use the NV instruction limits */
-#define MAX_INSTRUCTIONS MAX2(MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS, \
-                              MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
-
-
 /**
  * This is basically a union of the vertex_program and fragment_program
  * structs that we can use to parse the program into
@@ -963,6 +979,8 @@ parse_output_color_num (GLcontext * ctx, const GLubyte ** inst,
 
 
 /**
+ * Validate the index of a texture coordinate
+ *
  * \param coord The texture unit index
  * \return 0 on sucess, 1 on error
  */
@@ -972,8 +990,30 @@ parse_texcoord_num (GLcontext * ctx, const GLubyte ** inst,
 {
    GLint i = parse_integer (inst, Program);
 
-   if ((i < 0) || (i >= (int)ctx->Const.MaxTextureUnits)) {
-      program_error(ctx, Program->Position, "Invalid texture unit index");
+   if ((i < 0) || (i >= (int)ctx->Const.MaxTextureCoordUnits)) {
+      program_error(ctx, Program->Position, "Invalid texture coordinate index");
+      return 1;
+   }
+
+   *coord = (GLuint) i;
+   return 0;
+}
+
+
+/**
+ * Validate the index of a texture image unit
+ *
+ * \param coord The texture unit index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_teximage_num (GLcontext * ctx, const GLubyte ** inst,
+                    struct arb_program *Program, GLuint * coord)
+{
+   GLint i = parse_integer (inst, Program);
+
+   if ((i < 0) || (i >= (int)ctx->Const.MaxTextureImageUnits)) {
+      program_error(ctx, Program->Position, "Invalid texture image index");
       return 1;
    }
 
@@ -981,6 +1021,7 @@ parse_texcoord_num (GLcontext * ctx, const GLubyte ** inst,
    return 0;
 }
 
+
 /**
  * \param coord The weight index
  * \return 0 on sucess, 1 on error
@@ -1132,7 +1173,9 @@ parse_state_single_item (GLcontext * ctx, const GLubyte ** inst,
                          struct arb_program *Program,
                          gl_state_index state_tokens[STATE_LENGTH])
 {
-   switch (*(*inst)++) {
+   GLubyte token = *(*inst)++;
+
+   switch (token) {
       case STATE_MATERIAL_PARSER:
          state_tokens[0] = STATE_MATERIAL;
          state_tokens[1] = parse_face_type (inst);
@@ -1317,7 +1360,6 @@ parse_state_single_item (GLcontext * ctx, const GLubyte ** inst,
 
       case STATE_CLIP_PLANE:
          state_tokens[0] = STATE_CLIPPLANE;
-         state_tokens[1] = parse_integer (inst, Program);
          if (parse_clipplane_num (ctx, inst, Program,
                                   (GLint *) &state_tokens[1]))
             return 1;
@@ -1769,7 +1811,9 @@ parse_param_elements (GLcontext * ctx, const GLubyte ** inst,
    gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0};
    GLfloat const_values[4];
 
-   switch (*(*inst)++) {
+   GLubyte token = *(*inst)++;
+
+   switch (token) {
       case PARAM_STATE_ELEMENT:
          if (parse_state_single_item (ctx, inst, Program, state_tokens))
             return 1;
@@ -1867,7 +1911,11 @@ parse_param_elements (GLcontext * ctx, const GLubyte ** inst,
                                         const_values, 4);
          if (param_var->param_binding_begin == ~0U)
             param_var->param_binding_begin = idx;
-         param_var->param_binding_type = PROGRAM_CONSTANT;
+         param_var->param_binding_type = PROGRAM_STATE_VAR;
+         /* Note: when we reference this parameter in an instruction later,
+          * we'll check if it's really a constant/immediate and set the
+          * instruction register type appropriately.
+          */
          param_var->param_binding_length++;
          Program->Base.NumParameters++;
          break;
@@ -2574,6 +2622,18 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst,
          return 1;
    }
 
+   if (*File == PROGRAM_STATE_VAR) {
+      enum register_file file;
+
+      /* If we're referencing the Program->Parameters[] array, check if the
+       * parameter is really a constant/literal.  If so, set File to CONSTANT.
+       */
+      assert(*Index < (GLint) Program->Base.Parameters->NumParameters);
+      file = Program->Base.Parameters->Parameters[*Index].Type;
+      if (file == PROGRAM_CONSTANT)
+         *File = PROGRAM_CONSTANT;
+   }
+
    /* Add attributes to InputsRead only if they are used the program.
     * This avoids the handling of unused ATTRIB declarations in the drivers. */
    if (*File == PROGRAM_INPUT)
@@ -3000,7 +3060,7 @@ parse_fp_instruction (GLcontext * ctx, const GLubyte ** inst,
             return 1;
 
          /* texImageUnit */
-         if (parse_texcoord_num (ctx, inst, Program, &texcoord))
+         if (parse_teximage_num (ctx, inst, Program, &texcoord))
             return 1;
          fp->TexSrcUnit = texcoord;
 
@@ -3350,11 +3410,11 @@ debug_variables (GLcontext * ctx, struct var_cache *vc_head,
                fprintf (stderr, "%s\n",
                         Program->Base.Parameters->Parameters[a + b].Name);
                if (Program->Base.Parameters->Parameters[a + b].Type == PROGRAM_STATE_VAR) {
-                  const char *s;
+                  char *s;
                   s = _mesa_program_state_string(Program->Base.Parameters->Parameters
                                                  [a + b].StateIndexes);
                   fprintf(stderr, "%s\n", s);
-                  _mesa_free((char *) s);
+                  _mesa_free(s);
                }
                else
                   fprintf (stderr, "%f %f %f %f\n",
@@ -3402,7 +3462,7 @@ parse_instructions(GLcontext * ctx, const GLubyte * inst,
       : ctx->Const.VertexProgram.MaxInstructions;
    GLint err = 0;
 
-   ASSERT(MAX_INSTRUCTIONS >= maxInst);
+   ASSERT(MAX_PROGRAM_INSTRUCTIONS >= maxInst);
 
    Program->MajorVersion = (GLuint) * inst++;
    Program->MinorVersion = (GLuint) * inst++;
@@ -3588,8 +3648,7 @@ enable_parser_extensions(GLcontext *ctx, grammar id)
    if (ctx->Extensions.NV_texture_rectangle
        && !enable_ext(ctx, id, "texture_rectangle"))
       return GL_FALSE;
-   if (ctx->Extensions.ARB_draw_buffers
-       && !enable_ext(ctx, id, "draw_buffers"))
+   if (!enable_ext(ctx, id, "draw_buffers"))
       return GL_FALSE;
    if (ctx->Extensions.MESA_texture_array
        && !enable_ext(ctx, id, "texture_array"))
@@ -3757,7 +3816,7 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target,
 
    /* Initialize the arb_program struct */
    program->Base.String = strz;
-   program->Base.Instructions = _mesa_alloc_instructions(MAX_INSTRUCTIONS);
+   program->Base.Instructions = _mesa_alloc_instructions(MAX_PROGRAM_INSTRUCTIONS);
    program->Base.NumInstructions =
    program->Base.NumTemporaries =
    program->Base.NumParameters =
@@ -3802,12 +3861,12 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target,
 
    _mesa_free (parsed);
 
-   /* Reallocate the instruction array from size [MAX_INSTRUCTIONS]
+   /* Reallocate the instruction array from size [MAX_PROGRAM_INSTRUCTIONS]
     * to size [ap.Base.NumInstructions].
     */
    program->Base.Instructions
       = _mesa_realloc_instructions(program->Base.Instructions,
-                                   MAX_INSTRUCTIONS,
+                                   MAX_PROGRAM_INSTRUCTIONS,
                                    program->Base.NumInstructions);
 
    return !err;
@@ -3851,12 +3910,18 @@ _mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target,
    program->Base.NumNativeTexIndirections = ap.Base.NumTexIndirections;
    program->Base.InputsRead      = ap.Base.InputsRead;
    program->Base.OutputsWritten  = ap.Base.OutputsWritten;
-   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) {
       program->Base.TexturesUsed[i] = ap.TexturesUsed[i];
+      if (ap.TexturesUsed[i])
+         program->Base.SamplersUsed |= (1 << i);
+   }
    program->Base.ShadowSamplers = ap.ShadowSamplers;
    program->FogOption          = ap.FogOption;
    program->UsesKill          = ap.UsesKill;
 
+   if (program->FogOption)
+      program->Base.InputsRead |= FRAG_BIT_FOGC;
+      
    if (program->Base.Instructions)
       _mesa_free(program->Base.Instructions);
    program->Base.Instructions = ap.Base.Instructions;
@@ -3865,8 +3930,18 @@ _mesa_parse_arb_fragment_program(GLcontext* ctx, GLenum target,
       _mesa_free_parameter_list(program->Base.Parameters);
    program->Base.Parameters    = ap.Base.Parameters;
 
+   /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
+    * or similar.  We used to leave this up to drivers, but it appears
+    * there's no hardware that wants to do fog in a discrete stage separate
+    * from the fragment shader.
+    */
+   if (program->FogOption != GL_NONE) {
+      _mesa_append_fog_code(ctx, program);
+      program->FogOption = GL_NONE;
+   }
+
 #if DEBUG_FP
-   _mesa_printf("____________Fragment program %u ________\n", program->Base.ID);
+   _mesa_printf("____________Fragment program %u ________\n", program->Base.Id);
    _mesa_print_program(&program->Base);
 #endif
 }