static void unalias_temporary(struct nqssadce_state* s, GLuint oldindex)
{
	GLuint newindex = _mesa_find_free_register(s->Program, PROGRAM_TEMPORARY);
	int ip;
	for(ip = 0; ip < s->IP; ++ip) {
		struct prog_instruction* inst = s->Program->Instructions + ip;
		if (inst->DstReg.File == PROGRAM_TEMPORARY && inst->DstReg.Index == oldindex)
			inst->DstReg.Index = newindex;
		unalias_srcregs(inst, oldindex, newindex);
	}
	unalias_srcregs(s->Program->Instructions + s->IP, oldindex, newindex);
}
static struct prog_instruction* track_used_srcreg(struct nqssadce_state* s,
	struct prog_instruction *inst, GLint src, GLuint sourced)
{
	int i;
	GLuint deswz_source = 0;

	for(i = 0; i < 4; ++i) {
		if (GET_BIT(sourced, i)) {
			GLuint swz = GET_SWZ(inst->SrcReg[src].Swizzle, i);
			deswz_source |= 1 << swz;
		} else {
			inst->SrcReg[src].Swizzle &= ~(7 << (3*i));
			inst->SrcReg[src].Swizzle |= SWIZZLE_NIL << (3*i);
		}
	}

	if (!s->Descr->IsNativeSwizzle(inst->Opcode, inst->SrcReg[src])) {
		struct prog_dst_register dstreg = inst->DstReg;
		dstreg.File = PROGRAM_TEMPORARY;
		dstreg.Index = _mesa_find_free_register(s->Program, PROGRAM_TEMPORARY);
		dstreg.WriteMask = sourced;

		s->Descr->BuildSwizzle(s, dstreg, inst->SrcReg[src]);

		inst = s->Program->Instructions + s->IP;
		inst->SrcReg[src].File = PROGRAM_TEMPORARY;
		inst->SrcReg[src].Index = dstreg.Index;
		inst->SrcReg[src].Swizzle = 0;
		inst->SrcReg[src].NegateBase = 0;
		inst->SrcReg[src].Abs = 0;
		inst->SrcReg[src].NegateAbs = 0;
		for(i = 0; i < 4; ++i) {
			if (GET_BIT(sourced, i))
				inst->SrcReg[src].Swizzle |= i << (3*i);
			else
				inst->SrcReg[src].Swizzle |= SWIZZLE_NIL << (3*i);
		}
		deswz_source = sourced;
	}

	struct register_state *regstate = get_reg_state(s, inst->SrcReg[src].File, inst->SrcReg[src].Index);
	if (regstate)
		regstate->Sourced |= deswz_source & 0xf;

	return inst;
}
/**
 * Transform the program to support fragment.position.
 *
 * Introduce a small fragment at the start of the program that will be
 * the only code that directly reads the FRAG_ATTRIB_WPOS input.
 * All other code pieces that reference that input will be rewritten
 * to read from a newly allocated temporary.
 *
 * \todo if/when r5xx supports the radeon_program architecture, this is a
 * likely candidate for code sharing.
 */
static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler)
{
	GLuint InputsRead = compiler->fp->mesa_program.Base.InputsRead;

	if (!(InputsRead & FRAG_BIT_WPOS))
		return;

	static gl_state_index tokens[STATE_LENGTH] = {
		STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0
	};
	struct prog_instruction *fpi;
	GLuint window_index;
	int i = 0;
	GLuint tempregi = _mesa_find_free_register(compiler->program, PROGRAM_TEMPORARY);

	_mesa_insert_instructions(compiler->program, 0, 3);
	fpi = compiler->program->Instructions;

	/* perspective divide */
	fpi[i].Opcode = OPCODE_RCP;

	fpi[i].DstReg.File = PROGRAM_TEMPORARY;
	fpi[i].DstReg.Index = tempregi;
	fpi[i].DstReg.WriteMask = WRITEMASK_W;
	fpi[i].DstReg.CondMask = COND_TR;

	fpi[i].SrcReg[0].File = PROGRAM_INPUT;
	fpi[i].SrcReg[0].Index = FRAG_ATTRIB_WPOS;
	fpi[i].SrcReg[0].Swizzle = SWIZZLE_WWWW;
	i++;

	fpi[i].Opcode = OPCODE_MUL;

	fpi[i].DstReg.File = PROGRAM_TEMPORARY;
	fpi[i].DstReg.Index = tempregi;
	fpi[i].DstReg.WriteMask = WRITEMASK_XYZ;
	fpi[i].DstReg.CondMask = COND_TR;

	fpi[i].SrcReg[0].File = PROGRAM_INPUT;
	fpi[i].SrcReg[0].Index = FRAG_ATTRIB_WPOS;
	fpi[i].SrcReg[0].Swizzle = SWIZZLE_XYZW;

	fpi[i].SrcReg[1].File = PROGRAM_TEMPORARY;
	fpi[i].SrcReg[1].Index = tempregi;
	fpi[i].SrcReg[1].Swizzle = SWIZZLE_WWWW;
	i++;

	/* viewport transformation */
	window_index = _mesa_add_state_reference(compiler->program->Parameters, tokens);

	fpi[i].Opcode = OPCODE_MAD;

	fpi[i].DstReg.File = PROGRAM_TEMPORARY;
	fpi[i].DstReg.Index = tempregi;
	fpi[i].DstReg.WriteMask = WRITEMASK_XYZ;
	fpi[i].DstReg.CondMask = COND_TR;

	fpi[i].SrcReg[0].File = PROGRAM_TEMPORARY;
	fpi[i].SrcReg[0].Index = tempregi;
	fpi[i].SrcReg[0].Swizzle =
	    MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);

	fpi[i].SrcReg[1].File = PROGRAM_STATE_VAR;
	fpi[i].SrcReg[1].Index = window_index;
	fpi[i].SrcReg[1].Swizzle =
	    MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);

	fpi[i].SrcReg[2].File = PROGRAM_STATE_VAR;
	fpi[i].SrcReg[2].Index = window_index;
	fpi[i].SrcReg[2].Swizzle =
	    MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
	i++;

	for (; i < compiler->program->NumInstructions; ++i) {
		int reg;
		for (reg = 0; reg < 3; reg++) {
			if (fpi[i].SrcReg[reg].File == PROGRAM_INPUT &&
			    fpi[i].SrcReg[reg].Index == FRAG_ATTRIB_WPOS) {
				fpi[i].SrcReg[reg].File = PROGRAM_TEMPORARY;
				fpi[i].SrcReg[reg].Index = tempregi;
			}
		}
	}
}
예제 #4
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;
}
예제 #5
0
/**
 * 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++;
            }
        }
    }
}
예제 #6
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;
}