ARB prog parser: Set NumAttributes based on the number of attribs read
[mesa.git] / src / mesa / shader / program.c
index 723c46ee8cf7f83f47229d7380a91124ab00f9c6..4623ff60de6b5c5a7fe64f11ec44a314b8fa9cbb 100644 (file)
@@ -53,6 +53,15 @@ _mesa_init_program(GLcontext *ctx)
 {
    GLuint i;
 
+   /*
+    * If this assertion fails, we need to increase the field
+    * size for register indexes.
+    */
+   ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
+          <= (1 << INST_INDEX_BITS));
+   ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
+          <= (1 << INST_INDEX_BITS));
+
    ctx->Program.ErrorPos = -1;
    ctx->Program.ErrorString = _mesa_strdup("");
 
@@ -120,6 +129,43 @@ _mesa_free_program_data(GLcontext *ctx)
 }
 
 
+/**
+ * Update the default program objects in the given context to reference those
+ * specified in the shared state and release those referencing the old
+ * shared state.
+ */
+void
+_mesa_update_default_objects_program(GLcontext *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+                            (struct gl_vertex_program *)
+                            ctx->Shared->DefaultVertexProgram);
+   assert(ctx->VertexProgram.Current);
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+                            (struct gl_fragment_program *)
+                            ctx->Shared->DefaultFragmentProgram);
+   assert(ctx->FragmentProgram.Current);
+#endif
+
+   /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+   if (ctx->ATIFragmentShader.Current) {
+      ctx->ATIFragmentShader.Current->RefCount--;
+      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
+         _mesa_free(ctx->ATIFragmentShader.Current);
+      }
+   }
+   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
+   assert(ctx->ATIFragmentShader.Current);
+   ctx->ATIFragmentShader.Current->RefCount++;
+#endif
+}
+
+
 /**
  * Set the vertex/fragment program error state (position and error string).
  * This is generally called from within the parsers.
@@ -211,7 +257,7 @@ struct gl_program *
 _mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog,
                              GLenum target, GLuint id)
 {
-   if (prog) 
+   if (prog)
       return _mesa_init_program_struct( ctx, &prog->Base, target, id );
    else
       return NULL;
@@ -225,7 +271,7 @@ struct gl_program *
 _mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
                            GLenum target, GLuint id)
 {
-   if (prog) 
+   if (prog)
       return _mesa_init_program_struct( ctx, &prog->Base, target, id );
    else
       return NULL;
@@ -238,7 +284,7 @@ _mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
  * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
  * device driver function to implement OO deriviation with additional
  * types not understood by this function.
- * 
+ *
  * \param ctx  context
  * \param id   program id/number
  * \param target  program target/type
@@ -247,19 +293,24 @@ _mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
 struct gl_program *
 _mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
 {
+   struct gl_program *prog;
    switch (target) {
    case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
-      return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
+   case GL_VERTEX_STATE_PROGRAM_NV:
+      prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
                                        target, id );
+      break;
    case GL_FRAGMENT_PROGRAM_NV:
    case GL_FRAGMENT_PROGRAM_ARB:
-      return _mesa_init_fragment_program(ctx,
+      prog =_mesa_init_fragment_program(ctx,
                                          CALLOC_STRUCT(gl_fragment_program),
                                          target, id );
+      break;
    default:
       _mesa_problem(ctx, "bad target in _mesa_new_program");
-      return NULL;
+      prog = NULL;
    }
+   return prog;
 }
 
 
@@ -278,7 +329,7 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
 
    if (prog == &_mesa_DummyProgram)
       return;
-                 
+
    if (prog->String)
       _mesa_free(prog->String);
 
@@ -331,7 +382,11 @@ _mesa_reference_program(GLcontext *ctx,
    assert(ptr);
    if (*ptr && prog) {
       /* sanity check */
-      ASSERT((*ptr)->Target == prog->Target);
+      if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
+         ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
+      else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
+         ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
+                prog->Target == GL_FRAGMENT_PROGRAM_NV);
    }
    if (*ptr == prog) {
       return;  /* no change */
@@ -341,15 +396,17 @@ _mesa_reference_program(GLcontext *ctx,
 
       /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
 #if 0
-      printf("Program %p %u 0x%x  Refcount-- to %d\n",
-             *ptr, (*ptr)->Id, (*ptr)->Target, (*ptr)->RefCount - 1);
+      printf("Program %p ID=%u Target=%s  Refcount-- to %d\n",
+             *ptr, (*ptr)->Id,
+             ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"),
+             (*ptr)->RefCount - 1);
 #endif
       ASSERT((*ptr)->RefCount > 0);
       (*ptr)->RefCount--;
 
       deleteFlag = ((*ptr)->RefCount == 0);
       /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
-      
+
       if (deleteFlag) {
          ASSERT(ctx);
          ctx->Driver.DeleteProgram(ctx, *ptr);
@@ -363,8 +420,10 @@ _mesa_reference_program(GLcontext *ctx,
       /*_glthread_LOCK_MUTEX(prog->Mutex);*/
       prog->RefCount++;
 #if 0
-      printf("Program %p %u 0x%x  Refcount++ to %d\n",
-             prog, prog->Id, prog->Target, prog->RefCount);
+      printf("Program %p ID=%u Target=%s  Refcount++ to %d\n",
+             prog, prog->Id,
+             (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"),
+             prog->RefCount);
 #endif
       /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
    }
@@ -402,6 +461,7 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
    clone->InputsRead = prog->InputsRead;
    clone->OutputsWritten = prog->OutputsWritten;
    clone->SamplersUsed = prog->SamplersUsed;
+   clone->ShadowSamplers = prog->ShadowSamplers;
    memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
 
    if (prog->Parameters)
@@ -504,6 +564,52 @@ _mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
    return GL_TRUE;
 }
 
+/**
+ * Delete 'count' instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+   const GLuint origLen = prog->NumInstructions;
+   const GLuint newLen = origLen - count;
+   struct prog_instruction *newInst;
+   GLuint i;
+
+   /* adjust branches */
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      if (inst->BranchTarget > 0) {
+         if (inst->BranchTarget > start) {
+            inst->BranchTarget -= count;
+         }
+      }
+   }
+
+   /* Alloc storage for new instructions */
+   newInst = _mesa_alloc_instructions(newLen);
+   if (!newInst) {
+      return GL_FALSE;
+   }
+
+   /* Copy 'start' instructions into new instruction buffer */
+   _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+   /* Copy the remaining/tail instructions to new inst buffer */
+   _mesa_copy_instructions(newInst + start,
+                           prog->Instructions + start + count,
+                           newLen - start);
+
+   /* free old instructions */
+   _mesa_free_instructions(prog->Instructions, origLen);
+
+   /* install new instructions */
+   prog->Instructions = newInst;
+   prog->NumInstructions = newLen;
+
+   return GL_TRUE;
+}
+
 
 /**
  * Search instructions for registers that match (oldFile, oldIndex),
@@ -633,7 +739,7 @@ _mesa_combine_programs(GLcontext *ctx,
       /* Connect color outputs of fprogA to color inputs of fprogB, via a
        * new temporary register.
        */
-      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) &&
+      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
           (progB_inputsRead & FRAG_BIT_COL0)) {
          GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY);
          if (tempReg < 0) {
@@ -643,7 +749,7 @@ _mesa_combine_programs(GLcontext *ctx,
          }
          /* replace writes to result.color[0] with tempReg */
          replace_registers(newInst, lenA,
-                           PROGRAM_OUTPUT, FRAG_RESULT_COLR,
+                           PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
                            PROGRAM_TEMPORARY, tempReg);
          /* replace reads from the input color with tempReg */
          replace_registers(newInst + lenA, lenB,
@@ -653,7 +759,7 @@ _mesa_combine_programs(GLcontext *ctx,
 
       /* compute combined program's InputsRead */
       inputsB = progB_inputsRead;
-      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) {
+      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
          inputsB &= ~(1 << FRAG_ATTRIB_COL0);
       }
       newProg->InputsRead = progA->InputsRead | inputsB;
@@ -714,3 +820,63 @@ _mesa_find_free_register(const struct gl_program *prog, GLuint regFile)
 
    return -1;
 }
+
+
+
+/**
+ * "Post-process" a GPU program.  This is intended to be used for debugging.
+ * Example actions include no-op'ing instructions or changing instruction
+ * behaviour.
+ */
+void
+_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog)
+{
+   static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
+   GLuint i;
+   GLuint whiteSwizzle;
+   GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
+                                                 white, 4, &whiteSwizzle);
+
+   (void) whiteIndex;
+
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
+
+      (void) n;
+
+      if (_mesa_is_tex_instruction(inst->Opcode)) {
+#if 0
+         /* replace TEX/TXP/TXB with MOV */
+         inst->Opcode = OPCODE_MOV;
+         inst->DstReg.WriteMask = WRITEMASK_XYZW;
+         inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+         inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+
+#if 0
+         /* disable shadow texture mode */
+         inst->TexShadow = 0;
+#endif
+      }
+
+      if (inst->Opcode == OPCODE_TXP) {
+#if 0
+         inst->Opcode = OPCODE_MOV;
+         inst->DstReg.WriteMask = WRITEMASK_XYZW;
+         inst->SrcReg[0].File = PROGRAM_CONSTANT;
+         inst->SrcReg[0].Index = whiteIndex;
+         inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+         inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+#if 0
+         inst->TexShadow = 0;
+#endif
+#if 0
+         inst->Opcode = OPCODE_TEX;
+         inst->TexShadow = 0;
+#endif
+      }
+
+   }
+}