Example #1
0
/**
 * Combine two programs into one.  Fix instructions so the outputs of
 * the first program go to the inputs of the second program.
 */
struct gl_program *
_mesa_combine_programs(GLcontext *ctx,
                       const struct gl_program *progA,
                       const struct gl_program *progB)
{
   struct prog_instruction *newInst;
   struct gl_program *newProg;
   const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
   const GLuint lenB = progB->NumInstructions;
   const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
   const GLuint newLength = lenA + lenB;
   GLbitfield inputsB;
   GLuint i;

   ASSERT(progA->Target == progB->Target);

   newInst = _mesa_alloc_instructions(newLength);
   if (!newInst)
      return GL_FALSE;

   _mesa_copy_instructions(newInst, progA->Instructions, lenA);
   _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);

   /* adjust branch / instruction addresses for B's instructions */
   for (i = 0; i < lenB; i++) {
      newInst[lenA + i].BranchTarget += lenA;
   }

   newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
   newProg->Instructions = newInst;
   newProg->NumInstructions = newLength;

   if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
      struct gl_fragment_program *fprogA, *fprogB, *newFprog;
      fprogA = (struct gl_fragment_program *) progA;
      fprogB = (struct gl_fragment_program *) progB;
      newFprog = (struct gl_fragment_program *) newProg;

      newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;

      /* Connect color outputs of fprogA to color inputs of fprogB, via a
       * new temporary register.
       */
      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) &&
          (progB->InputsRead & (1 << FRAG_ATTRIB_COL0))) {
         GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY);
         if (tempReg < 0) {
            _mesa_problem(ctx, "No free temp regs found in "
                          "_mesa_combine_programs(), using 31");
            tempReg = 31;
         }
         /* replace writes to result.color[0] with tempReg */
         replace_registers(newInst, lenA,
                           PROGRAM_OUTPUT, FRAG_RESULT_COLR,
                           PROGRAM_TEMPORARY, tempReg);
         /* replace reads from input.color[0] with tempReg */
         replace_registers(newInst + lenA, lenB,
                           PROGRAM_INPUT, FRAG_ATTRIB_COL0,
                           PROGRAM_TEMPORARY, tempReg);
      }

      inputsB = progB->InputsRead;
      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) {
         inputsB &= ~(1 << FRAG_ATTRIB_COL0);
      }
      newProg->InputsRead = progA->InputsRead | inputsB;
      newProg->OutputsWritten = progB->OutputsWritten;
      newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
   }
   else {
      /* vertex program */
      assert(0);      /* XXX todo */
   }

   /*
    * Merge parameters (uniforms, constants, etc)
    */
   newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
                                                       progB->Parameters);

   adjust_param_indexes(newInst + lenA, lenB, numParamsA);


   return newProg;
}
Example #2
0
/**
 * Combine two programs into one.  Fix instructions so the outputs of
 * the first program go to the inputs of the second program.
 */
struct gl_program *
_mesa_combine_programs(struct gl_context *ctx,
                       const struct gl_program *progA,
                       const struct gl_program *progB)
{
   struct prog_instruction *newInst;
   struct gl_program *newProg;
   const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
   const GLuint lenB = progB->NumInstructions;
   const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
   const GLuint newLength = lenA + lenB;
   GLboolean usedTemps[MAX_PROGRAM_TEMPS];
   GLuint firstTemp = 0;
   GLbitfield inputsB;
   GLuint i;

   ASSERT(progA->Target == progB->Target);

   newInst = _mesa_alloc_instructions(newLength);
   if (!newInst)
      return GL_FALSE;

   _mesa_copy_instructions(newInst, progA->Instructions, lenA);
   _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);

   /* adjust branch / instruction addresses for B's instructions */
   for (i = 0; i < lenB; i++) {
      newInst[lenA + i].BranchTarget += lenA;
   }

   newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
   newProg->Instructions = newInst;
   newProg->NumInstructions = newLength;

   /* find used temp regs (we may need new temps below) */
   _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
                             usedTemps, MAX_PROGRAM_TEMPS);

   if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
      struct gl_fragment_program *fprogA, *fprogB, *newFprog;
      GLbitfield progB_inputsRead = progB->InputsRead;
      GLint progB_colorFile, progB_colorIndex;

      fprogA = (struct gl_fragment_program *) progA;
      fprogB = (struct gl_fragment_program *) progB;
      newFprog = (struct gl_fragment_program *) newProg;

      newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;

      /* We'll do a search and replace for instances
       * of progB_colorFile/progB_colorIndex below...
       */
      progB_colorFile = PROGRAM_INPUT;
      progB_colorIndex = FRAG_ATTRIB_COL0;

      /*
       * The fragment program may get color from a state var rather than
       * a fragment input (vertex output) if it's constant.
       * See the texenvprogram.c code.
       * So, search the program's parameter list now to see if the program
       * gets color from a state var instead of a conventional fragment
       * input register.
       */
      for (i = 0; i < progB->Parameters->NumParameters; i++) {
         struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
         if (p->Type == PROGRAM_STATE_VAR &&
             p->StateIndexes[0] == STATE_INTERNAL &&
             p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
             (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) {
            progB_inputsRead |= FRAG_BIT_COL0;
            progB_colorFile = PROGRAM_STATE_VAR;
            progB_colorIndex = i;
            break;
         }
      }

      /* Connect color outputs of fprogA to color inputs of fprogB, via a
       * new temporary register.
       */
      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
          (progB_inputsRead & FRAG_BIT_COL0)) {
         GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
                                                  firstTemp);
         if (tempReg < 0) {
            _mesa_problem(ctx, "No free temp regs found in "
                          "_mesa_combine_programs(), using 31");
            tempReg = 31;
         }
         firstTemp = tempReg + 1;

         /* replace writes to result.color[0] with tempReg */
         replace_registers(newInst, lenA,
                           PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
                           PROGRAM_TEMPORARY, tempReg);
         /* replace reads from the input color with tempReg */
         replace_registers(newInst + lenA, lenB,
                           progB_colorFile, progB_colorIndex, /* search for */
                           PROGRAM_TEMPORARY, tempReg  /* replace with */ );
      }

      /* compute combined program's InputsRead */
      inputsB = progB_inputsRead;
      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
         inputsB &= ~(1 << FRAG_ATTRIB_COL0);
      }
      newProg->InputsRead = progA->InputsRead | inputsB;
      newProg->OutputsWritten = progB->OutputsWritten;
      newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
   }
   else {
      /* vertex program */
      assert(0);      /* XXX todo */
   }

   /*
    * Merge parameters (uniforms, constants, etc)
    */
   newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
                                                       progB->Parameters);

   adjust_param_indexes(newInst + lenA, lenB, numParamsA);


   return newProg;
}