mesa: glsl: grab latest fixes from gallium-0.1 branch
authorBrian Paul <brian.paul@tungstengraphics.com>
Mon, 25 Aug 2008 15:20:00 +0000 (09:20 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Mon, 25 Aug 2008 15:20:00 +0000 (09:20 -0600)
Includes:
1. Fixes failed asserting about bad swizzles in src reg emit.
2. Tracks uniform var usage.
3. Emit exp() in terms of EXP2 instruction.

src/mesa/shader/prog_parameter.c
src/mesa/shader/prog_parameter.h
src/mesa/shader/slang/library/slang_common_builtin.gc
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_link.c

index d87e8f6..2dfd923 100644 (file)
@@ -29,9 +29,9 @@
  */
 
 
-#include "glheader.h"
-#include "imports.h"
-#include "macros.h"
+#include "main/glheader.h"
+#include "main/imports.h"
+#include "main/macros.h"
 #include "prog_instruction.h"
 #include "prog_parameter.h"
 #include "prog_statevars.h"
@@ -278,6 +278,26 @@ _mesa_add_uniform(struct gl_program_parameter_list *paramList,
 
 
 /**
+ * Mark the named uniform as 'used'.
+ */
+void
+_mesa_use_uniform(struct gl_program_parameter_list *paramList,
+                  const char *name)
+{
+   GLuint i;
+   for (i = 0; i < paramList->NumParameters; i++) {
+      struct gl_program_parameter *p = paramList->Parameters + i;
+      if (p->Type == PROGRAM_UNIFORM && _mesa_strcmp(p->Name, name) == 0) {
+         p->Used = GL_TRUE;
+         /* Note that large uniforms may occupy several slots so we're
+          * not done searching yet.
+          */
+      }
+   }
+}
+
+
+/**
  * Add a sampler to the parameter list.
  * \param name  uniform's name
  * \param datatype  GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc.
@@ -591,21 +611,24 @@ _mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
    /** Not too efficient, but correct */
    for (i = 0; i < list->NumParameters; i++) {
       struct gl_program_parameter *p = list->Parameters + i;
+      struct gl_program_parameter *pCopy;
       GLuint size = MIN2(p->Size, 4);
       GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
                                     list->ParameterValues[i], NULL);
       ASSERT(j >= 0);
+      pCopy = clone->Parameters + j;
+      pCopy->Used = p->Used;
       /* copy state indexes */
       if (p->Type == PROGRAM_STATE_VAR) {
          GLint k;
-         struct gl_program_parameter *q = clone->Parameters + j;
          for (k = 0; k < STATE_LENGTH; k++) {
-            q->StateIndexes[k] = p->StateIndexes[k];
+            pCopy->StateIndexes[k] = p->StateIndexes[k];
          }
       }
       else {
          clone->Parameters[j].Size = p->Size;
       }
+      
    }
 
    clone->StateFlags = list->StateFlags;
index dfb8c39..e8d3e9e 100644 (file)
@@ -31,7 +31,7 @@
 #ifndef PROG_PARAMETER_H
 #define PROG_PARAMETER_H
 
-#include "mtypes.h"
+#include "main/mtypes.h"
 #include "prog_statevars.h"
 
 
@@ -48,6 +48,7 @@ struct gl_program_parameter
    enum register_file Type; /**< PROGRAM_NAMED_PARAM, CONSTANT or STATE_VAR */
    GLenum DataType;         /**< GL_FLOAT, GL_FLOAT_VEC2, etc */
    GLuint Size;             /**< Number of components (1..4) */
+   GLboolean Used;          /**< Helper flag for GLSL uniform tracking */
    /**
     * A sequence of STATE_* tokens and integers to identify GL state.
     */
@@ -112,6 +113,10 @@ extern GLint
 _mesa_add_uniform(struct gl_program_parameter_list *paramList,
                   const char *name, GLuint size, GLenum datatype);
 
+extern void
+_mesa_use_uniform(struct gl_program_parameter_list *paramList,
+                  const char *name);
+
 extern GLint
 _mesa_add_sampler(struct gl_program_parameter_list *paramList,
                   const char *name, GLenum datatype);
index e908e6c..561e94f 100644 (file)
@@ -473,32 +473,33 @@ vec4 pow(const vec4 a, const vec4 b)
 
 float exp(const float a)
 {
-   const float e = 2.71828;
-   __asm float_power __retVal, e, a;
+   // NOTE: log2(e) = 1.44269502
+   float t = a * 1.44269502;
+   __asm float_exp2 __retVal, t;
 }
 
 vec2 exp(const vec2 a)
 {
-   const float e = 2.71828;
-   __asm float_power __retVal.x, e, a.x;
-   __asm float_power __retVal.y, e, a.y;
+   vec2 t = a * 1.44269502;
+   __asm float_exp2 __retVal.x, t.x;
+   __asm float_exp2 __retVal.y, t.y;
 }
 
 vec3 exp(const vec3 a)
 {
-   const float e = 2.71828;
-   __asm float_power __retVal.x, e, a.x;
-   __asm float_power __retVal.y, e, a.y;
-   __asm float_power __retVal.z, e, a.z;
+   vec3 t = a * 1.44269502;
+   __asm float_exp2 __retVal.x, t.x;
+   __asm float_exp2 __retVal.y, t.y;
+   __asm float_exp2 __retVal.z, t.z;
 }
 
 vec4 exp(const vec4 a)
 {
-   const float e = 2.71828;
-   __asm float_power __retVal.x, e, a.x;
-   __asm float_power __retVal.y, e, a.y;
-   __asm float_power __retVal.z, e, a.z;
-   __asm float_power __retVal.w, e, a.w;
+   vec4 t = a * 1.44269502;
+   __asm float_exp2 __retVal.x, t.x;
+   __asm float_exp2 __retVal.y, t.y;
+   __asm float_exp2 __retVal.z, t.z;
+   __asm float_exp2 __retVal.w, t.w;
 }
 
 
index f96c655..7006e86 100644 (file)
@@ -1481,7 +1481,7 @@ _slang_simple_writemask(GLuint writemask, GLuint swizzle)
  * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple
  */
 static GLboolean
-swizzle_to_writemask(GLuint swizzle,
+swizzle_to_writemask(slang_assemble_ctx *A, GLuint swizzle,
                      GLuint *writemaskOut, GLuint *swizzleOut)
 {
    GLuint mask = 0x0, newSwizzle[4];
@@ -1495,6 +1495,18 @@ swizzle_to_writemask(GLuint swizzle,
          break;
       }
       assert(swz >= 0 && swz <= 3);
+
+      if (swizzle != SWIZZLE_XXXX &&
+          swizzle != SWIZZLE_YYYY &&
+          swizzle != SWIZZLE_ZZZZ &&
+          swizzle != SWIZZLE_WWWW &&
+          (mask & (1 << swz))) {
+         /* a channel can't be specified twice (ex: ".xyyz") */
+         slang_info_log_error(A->log, "Invalid writemask '%s'",
+                              _mesa_swizzle_string(swizzle, 0, 0));
+         return GL_FALSE;
+      }
+
       mask |= (1 << swz);
    }
    assert(mask <= 0xf);
@@ -1590,11 +1602,11 @@ resolve_swizzle(const slang_operation *oper)
  * As above, but produce a writemask.
  */
 static GLuint
-resolve_writemask(const slang_operation *oper)
+resolve_writemask(slang_assemble_ctx *A, const slang_operation *oper)
 {
    GLuint swizzle = resolve_swizzle(oper);
    GLuint writemask, swizzleOut;
-   swizzle_to_writemask(swizzle, &writemask, &swizzleOut);
+   swizzle_to_writemask(A, swizzle, &writemask, &swizzleOut);
    return writemask;
 }
 
@@ -1668,7 +1680,7 @@ _slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper,
 
       dest_oper = &oper->children[0];
 
-      writemask = resolve_writemask(dest_oper);
+      writemask = resolve_writemask(A, dest_oper);
 
       n0 = _slang_gen_operation(A, dest_oper);
       if (!n0)
@@ -1980,6 +1992,12 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
       fun = _slang_locate_struct_constructor(A, name);
    }
 
+   /*
+    * At this point, some heuristics are used to try to find a function
+    * that matches the calling signature by means of casting or "unrolling"
+    * of constructors.
+    */
+
    if (!fun && _slang_is_vec_mat_type(name)) {
       /* Next, if this call looks like a vec() or mat() constructor call,
        * try "unwinding" the args to satisfy a constructor.
@@ -1995,7 +2013,7 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
       }
    }
 
-   if (!fun) {
+   if (!fun && _slang_is_vec_mat_type(name)) {
       /* Next, try casting args to the types of the formal parameters */
       int numArgs = oper->num_children;
       fun = _slang_find_function_by_argc(A->space.funcs, name, numArgs);
@@ -2008,6 +2026,13 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
       assert(fun);
    }
 
+   if (!fun) {
+      slang_info_log_error(A->log,
+                           "Function '%s' not found (check argument types)",
+                           name);
+      return NULL;
+   }
+
    n = _slang_gen_function_call(A, fun, oper, dest);
 
    if (n && !n->Store && !dest
@@ -2716,7 +2741,11 @@ _slang_assignment_compatible(slang_assemble_ctx *A,
    slang_typeinfo t0, t1;
    GLuint sz0, sz1;
 
-   
+   if (op0->type == SLANG_OPER_POSTINCREMENT ||
+       op0->type == SLANG_OPER_POSTDECREMENT) {
+      return GL_FALSE;
+   }
+
    slang_typeinfo_construct(&t0);
    _slang_typeof_operation(A, op0, &t0);
 
@@ -3020,7 +3049,7 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
       if (lhs && rhs) {
          /* convert lhs swizzle into writemask */
          GLuint writemask, newSwizzle;
-         if (!swizzle_to_writemask(lhs->Store->Swizzle,
+         if (!swizzle_to_writemask(A, lhs->Store->Swizzle,
                                    &writemask, &newSwizzle)) {
             /* Non-simple writemask, need to swizzle right hand side in
              * order to put components into the right place.
index f0c3791..9e8daa1 100644 (file)
@@ -108,7 +108,9 @@ writemask_to_swizzle(GLuint writemask)
 
 
 /**
- * Swizzle a swizzle.  That is, return swz2(swz1)
+ * Swizzle a swizzle (function composition).
+ * That is, return swz2(swz1), or said another way: swz1.szw2
+ * Example: swizzle_swizzle(".zwxx", ".xxyw") yields ".zzwx"
  */
 GLuint
 _slang_swizzle_swizzle(GLuint swz1, GLuint swz2)
@@ -279,7 +281,7 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
    while (st->Parent) {
       st = st->Parent;
       index += st->Index;
-      swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle);
+      swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle);
    }
 
    assert(st->File >= 0);
@@ -1636,6 +1638,88 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
 }
 
 
+/**
+ * Emit code for a variable declaration.
+ * This usually doesn't result in any code generation, but just
+ * memory allocation.
+ */
+static struct prog_instruction *
+emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n)
+{
+   struct prog_instruction *inst;
+
+   assert(n->Store);
+   assert(n->Store->File != PROGRAM_UNDEFINED);
+   assert(n->Store->Size > 0);
+   /*assert(n->Store->Index < 0);*/
+
+   if (!n->Var || n->Var->isTemp) {
+      /* a nameless/temporary variable, will be freed after first use */
+      /*NEW*/
+      if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) {
+         slang_info_log_error(emitInfo->log,
+                              "Ran out of registers, too many temporaries");
+         return NULL;
+      }
+   }
+   else {
+      /* a regular variable */
+      _slang_add_variable(emitInfo->vt, n->Var);
+      if (!_slang_alloc_var(emitInfo->vt, n->Store)) {
+         slang_info_log_error(emitInfo->log,
+                              "Ran out of registers, too many variables");
+         return NULL;
+      }
+      /*
+        printf("IR_VAR_DECL %s %d store %p\n",
+        (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
+      */
+      assert(n->Var->aux == n->Store);
+   }
+   if (emitInfo->EmitComments) {
+      /* emit NOP with comment describing the variable's storage location */
+      char s[1000];
+      sprintf(s, "TEMP[%d]%s = variable %s (size %d)",
+              n->Store->Index,
+              _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), 
+              (n->Var ? (char *) n->Var->a_name : "anonymous"),
+              n->Store->Size);
+      inst = emit_comment(emitInfo, s);
+      return inst;
+   }
+   return NULL;
+}
+
+
+/**
+ * Emit code for a reference to a variable.
+ * Actually, no code is generated but we may do some memory alloation.
+ * In particular, state vars (uniforms) are allocated on an as-needed basis.
+ */
+static struct prog_instruction *
+emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n)
+{
+   assert(n->Store);
+   assert(n->Store->File != PROGRAM_UNDEFINED);
+
+   if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) {
+      n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
+   }
+   else if (n->Store->File == PROGRAM_UNIFORM) {
+      /* mark var as used */
+      _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name);
+   }
+
+   if (n->Store->Index < 0) {
+      /* probably ran out of registers */
+      return NULL;
+   }
+   assert(n->Store->Size > 0);
+
+   return NULL;
+}
+
+
 static struct prog_instruction *
 emit(slang_emit_info *emitInfo, slang_ir_node *n)
 {
@@ -1671,64 +1755,14 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
 
    case IR_VAR_DECL:
       /* Variable declaration - allocate a register for it */
-      assert(n->Store);
-      assert(n->Store->File != PROGRAM_UNDEFINED);
-      assert(n->Store->Size > 0);
-      /*assert(n->Store->Index < 0);*/
-      if (!n->Var || n->Var->isTemp) {
-         /* a nameless/temporary variable, will be freed after first use */
-         /*NEW*/
-         if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) {
-            slang_info_log_error(emitInfo->log,
-                                 "Ran out of registers, too many temporaries");
-            return NULL;
-         }
-      }
-      else {
-         /* a regular variable */
-         _slang_add_variable(emitInfo->vt, n->Var);
-         if (!_slang_alloc_var(emitInfo->vt, n->Store)) {
-            slang_info_log_error(emitInfo->log,
-                                 "Ran out of registers, too many variables");
-            return NULL;
-         }
-         /*
-         printf("IR_VAR_DECL %s %d store %p\n",
-                (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
-         */
-         assert(n->Var->aux == n->Store);
-      }
-      if (emitInfo->EmitComments) {
-         /* emit NOP with comment describing the variable's storage location */
-         char s[1000];
-         sprintf(s, "TEMP[%d]%s = variable %s (size %d)",
-                 n->Store->Index,
-                 _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), 
-                 (n->Var ? (char *) n->Var->a_name : "anonymous"),
-                 n->Store->Size);
-         inst = emit_comment(emitInfo, s);
-         return inst;
-      }
-      return NULL;
+      inst = emit_var_decl(emitInfo, n);
+      return inst;
 
    case IR_VAR:
       /* Reference to a variable
        * Storage should have already been resolved/allocated.
        */
-      assert(n->Store);
-      assert(n->Store->File != PROGRAM_UNDEFINED);
-
-      if (n->Store->File == PROGRAM_STATE_VAR &&
-          n->Store->Index < 0) {
-         n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
-      }
-
-      if (n->Store->Index < 0) {
-         /* probably ran out of registers */
-         return NULL;
-      }
-      assert(n->Store->Size > 0);
-      break;
+      return emit_var_ref(emitInfo, n);
 
    case IR_ELEMENT:
       return emit_array_element(emitInfo, n);
@@ -1939,6 +1973,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
    GET_CURRENT_CONTEXT(ctx);
    GLboolean success;
    slang_emit_info emitInfo;
+   GLuint maxUniforms;
 
    emitInfo.log = log;
    emitInfo.vt = vt;
@@ -1955,6 +1990,19 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
       emitInfo.EmitHighLevelInstructions = GL_TRUE;
    }      
 
+   /* Check uniform/constant limits */
+   if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
+      maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4;
+   }
+   else {
+      assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+      maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4;
+   }
+   if (prog->Parameters->NumParameters > maxUniforms) {
+      slang_info_log_error(log, "Constant/uniform register limit exceeded");
+      return GL_FALSE;
+   }
+
    (void) emit(&emitInfo, n);
 
    /* finish up by adding the END opcode to program */
index e33272e..57dbfc2 100644 (file)
@@ -173,7 +173,7 @@ link_uniform_vars(struct gl_shader_program *shProg,
        * Furthermore, we'll need to fix the state-var's size/datatype info.
        */
 
-      if (p->Type == PROGRAM_UNIFORM ||
+      if ((p->Type == PROGRAM_UNIFORM && p->Used) ||
           p->Type == PROGRAM_SAMPLER) {
          _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
       }