glsl: regenerated file
[mesa.git] / src / mesa / shader / slang / slang_emit.c
index 1e9b4c125451e26b56a9853f98a40919c993a30b..3af301eacdf1e448aa8e3eb78d78de0c941b1161 100644 (file)
@@ -62,6 +62,8 @@ typedef struct
 
    GLuint MaxInstructions;  /**< size of prog->Instructions[] buffer */
 
+   GLboolean UnresolvedFunctions;
+
    /* code-gen options */
    GLboolean EmitHighLevelInstructions;
    GLboolean EmitCondCodes;
@@ -164,7 +166,7 @@ _slang_var_swizzle(GLint size, GLint comp)
 {
    switch (size) {
    case 1:
-      return MAKE_SWIZZLE4(comp, comp, comp, comp);
+      return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL);
    case 2:
       return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL);
    case 3:
@@ -310,24 +312,22 @@ storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st)
       dst->WriteMask = swizzle_to_writemask(swizzle);
    }
    else {
-      GLuint writemask;
       switch (size) {
       case 1:
-         writemask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0);
+         dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0);
          break;
       case 2:
-         writemask = WRITEMASK_XY;
+         dst->WriteMask = WRITEMASK_XY;
          break;
       case 3:
-         writemask = WRITEMASK_XYZ;
+         dst->WriteMask = WRITEMASK_XYZ;
          break;
       case 4:
-         writemask = WRITEMASK_XYZW;
+         dst->WriteMask = WRITEMASK_XYZW;
          break;
       default:
          ; /* error would have been caught above */
       }
-      dst->WriteMask = writemask;
    }
 
    dst->RelAddr = relAddr;
@@ -448,12 +448,12 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)
 
 static struct prog_instruction *
 emit_arl_load(slang_emit_info *emitInfo,
-              enum register_file file, GLint index, GLuint swizzle)
+              gl_register_file file, GLint index, GLuint swizzle)
 {
    struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL);
    inst->SrcReg[0].File = file;
    inst->SrcReg[0].Index = index;
-   inst->SrcReg[0].Swizzle = swizzle;
+   inst->SrcReg[0].Swizzle = fix_swizzle(swizzle);
    inst->DstReg.File = PROGRAM_ADDRESS;
    inst->DstReg.Index = 0;
    inst->DstReg.WriteMask = WRITEMASK_X;
@@ -719,6 +719,9 @@ instruction_annotation(gl_inst_opcode opcode, char *dstAnnot,
    case OPCODE_MUL:
       operator = "*";
       break;
+   case OPCODE_DP2:
+      operator = "DP2";
+      break;
    case OPCODE_DP3:
       operator = "DP3";
       break;
@@ -871,7 +874,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
    emit(emitInfo, n->Children[1]);
 
    if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) {
+      /* XXX this error should have been caught in slang_codegen.c */
       slang_info_log_error(emitInfo->log, "invalid operands to == or !=");
+      n->Store = NULL;
       return NULL;
    }
 
@@ -901,6 +906,7 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
       slang_ir_storage tempStore;
 
       if (!alloc_local_temp(emitInfo, &tempStore, 4)) {
+         n->Store = NULL;
          return NULL;
          /* out of temps */
       }
@@ -915,7 +921,7 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
       }
       else {
          assert(size == 2);
-         dotOp = OPCODE_DP3;
+         dotOp = OPCODE_DP3; /* XXX use OPCODE_DP2 eventually */
          swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y);
       }
 
@@ -1129,7 +1135,7 @@ emit_negation(slang_emit_info *emitInfo, slang_ir_node *n)
                            n->Children[0]->Store,
                            NULL,
                            NULL);
-   inst->SrcReg[0].NegateBase = NEGATE_XYZW;
+   inst->SrcReg[0].Negate = NEGATE_XYZW;
    return inst;
 }
 
@@ -1258,16 +1264,47 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    struct prog_instruction *inst;
    gl_inst_opcode opcode;
+   GLboolean shadow = GL_FALSE;
 
-   if (n->Opcode == IR_TEX) {
+   switch (n->Opcode) {
+   case IR_TEX:
       opcode = OPCODE_TEX;
-   }
-   else if (n->Opcode == IR_TEXB) {
+      break;
+   case IR_TEX_SH:
+      opcode = OPCODE_TEX;
+      shadow = GL_TRUE;
+      break;
+   case IR_TEXB:
       opcode = OPCODE_TXB;
-   }
-   else {
-      assert(n->Opcode == IR_TEXP);
+      break;
+   case IR_TEXB_SH:
+      opcode = OPCODE_TXB;
+      shadow = GL_TRUE;
+      break;
+   case IR_TEXP:
+      opcode = OPCODE_TXP;
+      break;
+   case IR_TEXP_SH:
       opcode = OPCODE_TXP;
+      shadow = GL_TRUE;
+      break;
+   default:
+      _mesa_problem(NULL, "Bad IR TEX code");
+      return NULL;
+   }
+
+   if (n->Children[0]->Opcode == IR_ELEMENT) {
+      /* array is the sampler (a uniform which'll indicate the texture unit) */
+      assert(n->Children[0]->Children[0]->Store);
+      assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER);
+
+      emit(emitInfo, n->Children[0]);
+
+      n->Children[0]->Var = n->Children[0]->Children[0]->Var;
+   } else {
+      /* this is the sampler (a uniform which'll indicate the texture unit) */
+      assert(n->Children[0]->Store);
+      assert(n->Children[0]->Store->File == PROGRAM_SAMPLER);
    }
 
    /* emit code for the texcoord operand */
@@ -1285,16 +1322,16 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
                            NULL,
                            NULL);
 
-   /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
-   assert(n->Children[0]->Store);
-   /* Store->Index is the sampler index */
+   inst->TexShadow = shadow;
+
+   /* Store->Index is the uniform/sampler index */
    assert(n->Children[0]->Store->Index >= 0);
-   /* Store->Size is the texture target */
-   assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
-   assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
+   inst->TexSrcUnit = n->Children[0]->Store->Index;
+   inst->TexSrcTarget = n->Children[0]->Store->TexTarget;
 
-   inst->TexSrcTarget = n->Children[0]->Store->Size;
-   inst->TexSrcUnit = n->Children[0]->Store->Index; /* i.e. uniform's index */
+   /* mark the sampler as being used */
+   _mesa_use_uniform(emitInfo->prog->Parameters,
+                     (char *) n->Children[0]->Var->a_name);
 
    return inst;
 }
@@ -1322,7 +1359,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
    inst = emit(emitInfo, n->Children[1]);
 
    if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) {
-      if (!emitInfo->log->text) {
+      if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) {
+         /* XXX this error should have been caught in slang_codegen.c */
          slang_info_log_error(emitInfo->log, "invalid assignment");
       }
       return NULL;
@@ -1336,14 +1374,16 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
 
    if (n->Store->File == PROGRAM_SAMPLER) {
       /* no code generated for sampler assignments,
-       * just copy the sampler index at compile time.
+       * just copy the sampler index/target at compile time.
        */
       n->Store->Index = n->Children[1]->Store->Index;
+      n->Store->TexTarget = n->Children[1]->Store->TexTarget;
       return NULL;
    }
 
 #if PEEPHOLE_OPTIMIZATIONS
    if (inst &&
+       (n->Children[1]->Opcode != IR_SWIZZLE) &&
        _slang_is_temp(emitInfo->vt, n->Children[1]->Store) &&
        (inst->DstReg.File == n->Children[1]->Store->File) &&
        (inst->DstReg.Index == n->Children[1]->Store->Index) &&
@@ -1360,13 +1400,9 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
        * becomes:
        *   MUL a, x, y;
        */
-      if (n->Children[1]->Opcode != IR_SWIZZLE)
-         _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
-      *n->Children[1]->Store = *n->Children[0]->Store;
 
       /* fixup the previous instruction (which stored the RHS result) */
       assert(n->Children[0]->Store->Index >= 0);
-
       storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store);
       return inst;
    }
@@ -1799,6 +1835,25 @@ emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
 }
 
 
+/**
+ * Return the size of a swizzle mask given that some swizzle components
+ * may be NIL/undefined.  For example:
+ *  swizzle_size(".zzxx") = 4
+ *  swizzle_size(".xy??") = 2
+ *  swizzle_size(".w???") = 1
+ */
+static GLuint
+swizzle_size(GLuint swizzle)
+{
+   GLuint i;
+   for (i = 0; i < 4; i++) {
+      if (GET_SWZ(swizzle, i) == SWIZZLE_NIL)
+         return i;
+   }
+   return 4;
+}
+
+
 static struct prog_instruction *
 emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 {
@@ -1806,14 +1861,25 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 
    inst = emit(emitInfo, n->Children[0]);
 
-#if 0
-   assert(n->Store->Parent);
-   /* Apply this node's swizzle to parent's storage */
-   GLuint swizzle = n->Store->Swizzle;
-   _slang_copy_ir_storage(n->Store, n->Store->Parent);
-   n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+   if (!n->Store->Parent) {
+      /* this covers a case such as "(b ? p : q).x" */
+      n->Store->Parent = n->Children[0]->Store;
+      assert(n->Store->Parent);
+   }
+
+   {
+      const GLuint swizzle = n->Store->Swizzle;
+      /* new storage is parent storage with updated Swizzle + Size fields */
+      _slang_copy_ir_storage(n->Store, n->Store->Parent);
+      /* Apply this node's swizzle to parent's storage */
+      n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+      /* Update size */
+      n->Store->Size = swizzle_size(n->Store->Swizzle);
+   }
+
    assert(!n->Store->Parent);
-#endif
+   assert(n->Store->Index >= 0);
+
    return inst;
 }
 
@@ -1999,9 +2065,7 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
    _slang_copy_ir_storage(n->Store, n->Children[0]->Store);
 
    n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4;
-   /* XXX test this:
-   n->Store->Index += fieldOffset / 4;
-   */
+   n->Store->Size = fieldSize;
 
    switch (fieldSize) {
    case 1:
@@ -2095,18 +2159,24 @@ emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n)
       if (index < 0) {
          /* error */
          char s[100];
-         snprintf(s, sizeof(s), "Undefined variable '%s'",
-                  (char *) n->Var->a_name);
+         /* XXX isn't this really an out of memory/resources error? */
+         _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'",
+                        (char *) n->Var->a_name);
          slang_info_log_error(emitInfo->log, s);
          return NULL;
       }
 
       n->Store->Index = index;
    }
-   else if (n->Store->File == PROGRAM_UNIFORM) {
+   else if (n->Store->File == PROGRAM_UNIFORM ||
+            n->Store->File == PROGRAM_SAMPLER) {
       /* mark var as used */
       _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name);
    }
+   else if (n->Store->File == PROGRAM_INPUT) {
+      assert(n->Store->Index >= 0);
+      emitInfo->prog->InputsRead |= (1 << n->Store->Index);
+   }
 
    if (n->Store->Index < 0) {
       /* probably ran out of registers */
@@ -2129,6 +2199,12 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
       return NULL;
    }
 
+   if (n->Comment) {
+      inst = new_instruction(emitInfo, OPCODE_NOP);
+      inst->Comment = _mesa_strdup(n->Comment);
+      inst = NULL;
+   }
+
    switch (n->Opcode) {
    case IR_SEQ:
       /* sequence of two sub-trees */
@@ -2190,12 +2266,15 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_NOISE2:
    case IR_NOISE3:
    case IR_NOISE4:
+   case IR_NRM4:
+   case IR_NRM3:
    /* binary */
    case IR_ADD:
    case IR_SUB:
    case IR_MUL:
    case IR_DOT4:
    case IR_DOT3:
+   case IR_DOT2:
    case IR_CROSS:
    case IR_MIN:
    case IR_MAX:
@@ -2208,6 +2287,7 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_POW:
    /* trinary operators */
    case IR_LRP:
+   case IR_CMP:
       return emit_arith(emitInfo, n);
 
    case IR_EQUAL:
@@ -2219,6 +2299,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_TEX:
    case IR_TEXB:
    case IR_TEXP:
+   case IR_TEX_SH:
+   case IR_TEXB_SH:
+   case IR_TEXP_SH:
       return emit_tex(emitInfo, n);
    case IR_NEG:
       return emit_negation(emitInfo, n);
@@ -2362,10 +2445,20 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo)
 
 
 
-
+/**
+ * Convert the IR tree into GPU instructions.
+ * \param n  root of IR tree
+ * \param vt  variable table
+ * \param prog  program to put GPU instructions into
+ * \param pragmas  controls codegen options
+ * \param withEnd  if true, emit END opcode at end
+ * \param log  log for emitting errors/warnings/info
+ */
 GLboolean
 _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
-                 struct gl_program *prog, GLboolean withEnd,
+                 struct gl_program *prog,
+                 const struct gl_sl_pragmas *pragmas,
+                 GLboolean withEnd,
                  slang_info_log *log)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -2382,7 +2475,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
 
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
    emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
-   emitInfo.EmitComments = ctx->Shader.EmitComments;
+   emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug;
    emitInfo.EmitBeginEndSub = GL_TRUE;
 
    if (!emitInfo.EmitCondCodes) {
@@ -2398,7 +2491,9 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
       maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4;
    }
    if (prog->Parameters->NumParameters > maxUniforms) {
-      slang_info_log_error(log, "Constant/uniform register limit exceeded");
+      slang_info_log_error(log, "Constant/uniform register limit exceeded "
+                           "(max=%u vec4)", maxUniforms);
+
       return GL_FALSE;
    }