コード例 #1
0
ファイル: programopt.c プロジェクト: LunarG/VulkanTools
/**
 * Scan/rewrite program to remove reads of custom (output) registers.
 * The passed type has to be PROGRAM_OUTPUT.
 * On some hardware, trying to read an output register causes trouble.
 * So, rewrite the program to use a temporary register in this case.
 */
void
_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
{
    GLuint i;
    GLint outputMap[VARYING_SLOT_MAX];
    GLuint numVaryingReads = 0;
    GLboolean usedTemps[MAX_PROGRAM_TEMPS];
    GLuint firstTemp = 0;

    _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
                              usedTemps, MAX_PROGRAM_TEMPS);

    assert(type == PROGRAM_OUTPUT);

    for (i = 0; i < VARYING_SLOT_MAX; i++)
        outputMap[i] = -1;

    /* look for instructions which read from varying vars */
    for (i = 0; i < prog->NumInstructions; i++) {
        struct prog_instruction *inst = prog->Instructions + i;
        const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
        GLuint j;
        for (j = 0; j < numSrc; j++) {
            if (inst->SrcReg[j].File == type) {
                /* replace the read with a temp reg */
                const GLuint var = inst->SrcReg[j].Index;
                if (outputMap[var] == -1) {
                    numVaryingReads++;
                    outputMap[var] = _mesa_find_free_register(usedTemps,
                                     MAX_PROGRAM_TEMPS,
                                     firstTemp);
                    firstTemp = outputMap[var] + 1;
                }
                inst->SrcReg[j].File = PROGRAM_TEMPORARY;
                inst->SrcReg[j].Index = outputMap[var];
            }
        }
    }

    if (numVaryingReads == 0)
        return; /* nothing to be done */

    /* look for instructions which write to the varying vars identified above */
    for (i = 0; i < prog->NumInstructions; i++) {
        struct prog_instruction *inst = prog->Instructions + i;
        if (inst->DstReg.File == type &&
                outputMap[inst->DstReg.Index] >= 0) {
            /* change inst to write to the temp reg, instead of the varying */
            inst->DstReg.File = PROGRAM_TEMPORARY;
            inst->DstReg.Index = outputMap[inst->DstReg.Index];
        }
    }

    /* insert new instructions to copy the temp vars to the varying vars */
    {
        struct prog_instruction *inst;
        GLint endPos, var;

        /* Look for END instruction and insert the new varying writes */
        endPos = -1;
        for (i = 0; i < prog->NumInstructions; i++) {
            struct prog_instruction *inst = prog->Instructions + i;
            if (inst->Opcode == OPCODE_END) {
                endPos = i;
                _mesa_insert_instructions(prog, i, numVaryingReads);
                break;
            }
        }

        assert(endPos >= 0);

        /* insert new MOV instructions here */
        inst = prog->Instructions + endPos;
        for (var = 0; var < VARYING_SLOT_MAX; var++) {
            if (outputMap[var] >= 0) {
                /* MOV VAR[var], TEMP[tmp]; */
                inst->Opcode = OPCODE_MOV;
                inst->DstReg.File = type;
                inst->DstReg.Index = var;
                inst->SrcReg[0].File = PROGRAM_TEMPORARY;
                inst->SrcReg[0].Index = outputMap[var];
                inst++;
            }
        }
    }
}
コード例 #2
0
ファイル: program.c プロジェクト: GunioRobot/mesa-7.10.2-PS3
/**
 * 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;
}