/**
 * Emit a paired ALU instruction.
 */
static GLboolean emit_paired(void *data, struct radeon_pair_instruction *inst)
{
	PROG_CODE;

	if (code->inst_end >= 511) {
		error("emit_alu: Too many instructions");
		return GL_FALSE;
	}

	int ip = ++code->inst_end;

	code->inst[ip].inst5 = translate_rgb_op(inst->RGB.Opcode);
	code->inst[ip].inst4 = translate_alpha_op(inst->Alpha.Opcode);

	if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask)
		code->inst[ip].inst0 = R500_INST_TYPE_OUT;
	else
		code->inst[ip].inst0 = R500_INST_TYPE_ALU;
	code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT;

	code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11) | (inst->Alpha.WriteMask << 14);
	code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18);
	if (inst->Alpha.DepthWriteMask) {
		code->inst[ip].inst4 |= R500_ALPHA_W_OMASK;
		c->fp->writes_depth = GL_TRUE;
	}

	code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex);
	code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex);
	use_temporary(code, inst->Alpha.DestIndex);
	use_temporary(code, inst->RGB.DestIndex);

	if (inst->RGB.Saturate)
		code->inst[ip].inst0 |= R500_INST_RGB_CLAMP;
	if (inst->Alpha.Saturate)
		code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP;

	code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0]));
	code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1]));
	code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2]));

	code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2]));

	code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT;
	code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT;

	code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT;
	code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT;

	return GL_TRUE;
}
/**
 * Emit a single TEX instruction
 */
static int emit_tex(struct r300_fragment_program_compiler *c, struct rc_sub_instruction *inst)
{
	PROG_CODE;

	if (code->inst_end >= c->Base.max_alu_insts-1) {
		error("emit_tex: Too many instructions");
		return 0;
	}

	int ip = ++code->inst_end;

	code->inst[ip].inst0 = R500_INST_TYPE_TEX
		| (inst->DstReg.WriteMask << 11)
		| R500_INST_TEX_SEM_WAIT;
	code->inst[ip].inst1 = R500_TEX_ID(inst->TexSrcUnit)
		| R500_TEX_SEM_ACQUIRE | R500_TEX_IGNORE_UNCOVERED;

	if (inst->TexSrcTarget == RC_TEXTURE_RECT)
		code->inst[ip].inst1 |= R500_TEX_UNSCALED;

	switch (inst->Opcode) {
	case RC_OPCODE_KIL:
		code->inst[ip].inst1 |= R500_TEX_INST_TEXKILL;
		break;
	case RC_OPCODE_TEX:
		code->inst[ip].inst1 |= R500_TEX_INST_LD;
		break;
	case RC_OPCODE_TXB:
		code->inst[ip].inst1 |= R500_TEX_INST_LODBIAS;
		break;
	case RC_OPCODE_TXP:
		code->inst[ip].inst1 |= R500_TEX_INST_PROJ;
		break;
	default:
		error("emit_tex can't handle opcode %s\n", rc_get_opcode_info(inst->Opcode)->Name);
	}

	use_temporary(code, inst->SrcReg[0].Index);
	if (inst->Opcode != RC_OPCODE_KIL)
		use_temporary(code, inst->DstReg.Index);

	code->inst[ip].inst2 = R500_TEX_SRC_ADDR(inst->SrcReg[0].Index)
		| (translate_strq_swizzle(inst->SrcReg[0].Swizzle) << 8)
		| R500_TEX_DST_ADDR(inst->DstReg.Index)
		| R500_TEX_DST_R_SWIZ_R | R500_TEX_DST_G_SWIZ_G
		| R500_TEX_DST_B_SWIZ_B | R500_TEX_DST_A_SWIZ_A;

	return 1;
}
static int emit_tex(struct r300_emit_state * emit, struct rc_instruction * inst)
{
	unsigned int unit;
	unsigned int dest;
	unsigned int opcode;
	PROG_CODE;

	if (code->tex.length >= emit->compiler->Base.max_tex_insts) {
		error("Too many TEX instructions");
		return 0;
	}

	unit = inst->U.I.TexSrcUnit;
	dest = inst->U.I.DstReg.Index;

	switch(inst->U.I.Opcode) {
	case RC_OPCODE_KIL: opcode = R300_TEX_OP_KIL; break;
	case RC_OPCODE_TEX: opcode = R300_TEX_OP_LD; break;
	case RC_OPCODE_TXB: opcode = R300_TEX_OP_TXB; break;
	case RC_OPCODE_TXP: opcode = R300_TEX_OP_TXP; break;
	default:
		error("Unknown texture opcode %s", rc_get_opcode_info(inst->U.I.Opcode)->Name);
		return 0;
	}

	if (inst->U.I.Opcode == RC_OPCODE_KIL) {
		unit = 0;
		dest = 0;
	} else {
		use_temporary(code, dest);
	}

	use_temporary(code, inst->U.I.SrcReg[0].Index);

	code->tex.inst[code->tex.length++] =
		((inst->U.I.SrcReg[0].Index << R300_SRC_ADDR_SHIFT)
			& R300_SRC_ADDR_MASK)
		| ((dest << R300_DST_ADDR_SHIFT)
			& R300_DST_ADDR_MASK)
		| (unit << R300_TEX_ID_SHIFT)
		| (opcode << R300_TEX_INST_SHIFT)
		| (inst->U.I.SrcReg[0].Index >= R300_PFS_NUM_TEMP_REGS ?
			R400_SRC_ADDR_EXT_BIT : 0)
		| (dest >= R300_PFS_NUM_TEMP_REGS ?
			R400_DST_ADDR_EXT_BIT : 0)
		;
	return 1;
}
static unsigned int use_source(struct r500_fragment_program_code* code, struct radeon_pair_instruction_source src)
{
	if (src.File == RC_FILE_CONSTANT) {
		return src.Index | 0x100;
	} else if (src.File == RC_FILE_TEMPORARY) {
		use_temporary(code, src.Index);
		return src.Index;
	}

	return 0;
}
static unsigned int use_source(struct r300_fragment_program_code* code, struct rc_pair_instruction_source src)
{
	if (!src.Used)
		return 0;

	if (src.File == RC_FILE_CONSTANT) {
		return src.Index | (1 << 5);
	} else if (src.File == RC_FILE_TEMPORARY || src.File == RC_FILE_INPUT) {
		use_temporary(code, src.Index);
		return src.Index & 0x1f;
	}

	return 0;
}
Exemple #6
0
static unsigned int use_source(struct r500_fragment_program_code* code, struct rc_pair_instruction_source src)
{
	/* From docs:
	 *   Note that inline constants set the MSB of ADDR0 and clear ADDR0_CONST.
	 * MSB = 1 << 7 */
	if (!src.Used)
		return 1 << 7;

	if (src.File == RC_FILE_CONSTANT) {
		return src.Index | R500_RGB_ADDR0_CONST;
	} else if (src.File == RC_FILE_TEMPORARY || src.File == RC_FILE_INPUT) {
		use_temporary(code, src.Index);
		return src.Index;
	}

	return 0;
}
Exemple #7
0
/**
 * Emit a single TEX instruction
 */
static int emit_tex(struct r300_fragment_program_compiler *c, struct rc_sub_instruction *inst)
{
	int ip;
	PROG_CODE;

	if (code->inst_end >= c->Base.max_alu_insts-1) {
		error("emit_tex: Too many instructions");
		return 0;
	}

	ip = ++code->inst_end;

	code->inst[ip].inst0 = R500_INST_TYPE_TEX
		| (inst->DstReg.WriteMask << 11)
		| R500_INST_TEX_SEM_WAIT;
	code->inst[ip].inst1 = R500_TEX_ID(inst->TexSrcUnit)
		| R500_TEX_SEM_ACQUIRE;

	if (inst->TexSrcTarget == RC_TEXTURE_RECT)
		code->inst[ip].inst1 |= R500_TEX_UNSCALED;

	switch (inst->Opcode) {
	case RC_OPCODE_KIL:
		code->inst[ip].inst1 |= R500_TEX_INST_TEXKILL;
		break;
	case RC_OPCODE_TEX:
		code->inst[ip].inst1 |= R500_TEX_INST_LD;
		break;
	case RC_OPCODE_TXB:
		code->inst[ip].inst1 |= R500_TEX_INST_LODBIAS;
		break;
	case RC_OPCODE_TXP:
		code->inst[ip].inst1 |= R500_TEX_INST_PROJ;
		break;
	case RC_OPCODE_TXD:
		code->inst[ip].inst1 |= R500_TEX_INST_DXDY;
		break;
	case RC_OPCODE_TXL:
		code->inst[ip].inst1 |= R500_TEX_INST_LOD;
		break;
	default:
		error("emit_tex can't handle opcode %s\n", rc_get_opcode_info(inst->Opcode)->Name);
	}

	use_temporary(code, inst->SrcReg[0].Index);
	if (inst->Opcode != RC_OPCODE_KIL)
		use_temporary(code, inst->DstReg.Index);

	code->inst[ip].inst2 = R500_TEX_SRC_ADDR(inst->SrcReg[0].Index)
		| (translate_strq_swizzle(inst->SrcReg[0].Swizzle) << 8)
		| R500_TEX_DST_ADDR(inst->DstReg.Index)
		| (GET_SWZ(inst->TexSwizzle, 0) << 24)
		| (GET_SWZ(inst->TexSwizzle, 1) << 26)
		| (GET_SWZ(inst->TexSwizzle, 2) << 28)
		| (GET_SWZ(inst->TexSwizzle, 3) << 30)
		;

	if (inst->Opcode == RC_OPCODE_TXD) {
		use_temporary(code, inst->SrcReg[1].Index);
		use_temporary(code, inst->SrcReg[2].Index);

		/* DX and DY parameters are specified in a separate register. */
		code->inst[ip].inst3 =
			R500_DX_ADDR(inst->SrcReg[1].Index) |
			(translate_strq_swizzle(inst->SrcReg[1].Swizzle) << 8) |
			R500_DY_ADDR(inst->SrcReg[2].Index) |
			(translate_strq_swizzle(inst->SrcReg[2].Swizzle) << 24);
	}

	return 1;
}
Exemple #8
0
/**
 * Emit a paired ALU instruction.
 */
static void emit_paired(struct r300_fragment_program_compiler *c, struct rc_pair_instruction *inst)
{
	int ip;
	PROG_CODE;

	if (code->inst_end >= c->Base.max_alu_insts-1) {
		error("emit_alu: Too many instructions");
		return;
	}

	ip = ++code->inst_end;

	/* Quirk: MDH/MDV (DDX/DDY) need a NOP on previous non-TEX instructions. */
	if (inst->RGB.Opcode == RC_OPCODE_DDX || inst->Alpha.Opcode == RC_OPCODE_DDX ||
		inst->RGB.Opcode == RC_OPCODE_DDY || inst->Alpha.Opcode == RC_OPCODE_DDY) {
		if (ip > 0) {
			alu_nop(c, ip - 1);
		}
	}

	code->inst[ip].inst5 = translate_rgb_op(c, inst->RGB.Opcode);
	code->inst[ip].inst4 = translate_alpha_op(c, inst->Alpha.Opcode);

	if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) {
		code->inst[ip].inst0 = R500_INST_TYPE_OUT;
		if (inst->WriteALUResult) {
			error("Cannot write output and ALU result at the same time");
			return;
		}
	} else {
		code->inst[ip].inst0 = R500_INST_TYPE_ALU;
	}
	code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT;

	code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11);
	code->inst[ip].inst0 |= inst->Alpha.WriteMask ? 1 << 14 : 0;
	code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18);
	if (inst->Nop) {
		code->inst[ip].inst0 |= R500_INST_NOP;
	}
	if (inst->Alpha.DepthWriteMask) {
		code->inst[ip].inst4 |= R500_ALPHA_W_OMASK;
		c->code->writes_depth = 1;
	}

	code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex);
	code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex);
	use_temporary(code, inst->Alpha.DestIndex);
	use_temporary(code, inst->RGB.DestIndex);

	if (inst->RGB.Saturate)
		code->inst[ip].inst0 |= R500_INST_RGB_CLAMP;
	if (inst->Alpha.Saturate)
		code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP;

	/* Set the presubtract operation. */
	switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) {
		case RC_PRESUB_BIAS:
			code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_2RGB0;
			break;
		case RC_PRESUB_SUB:
			code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_MINUS_RGB0;
			break;
		case RC_PRESUB_ADD:
			code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_PLUS_RGB0;
			break;
		case RC_PRESUB_INV:
			code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_RGB0;
			break;
		default:
			break;
	}
	switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) {
		case RC_PRESUB_BIAS:
			code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_2A0;
			break;
		case RC_PRESUB_SUB:
			code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_MINUS_A0;
			break;
		case RC_PRESUB_ADD:
			code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_PLUS_A0;
			break;
		case RC_PRESUB_INV:
			code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_A0;
			break;
		default:
			break;
	}

	code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0]));
	code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1]));
	code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2]));

	code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2]));

	code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT;
	code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT;

	code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT;
	code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT;

	code->inst[ip].inst3 |= R500_ALU_RGB_TARGET(inst->RGB.Target);
	code->inst[ip].inst4 |= R500_ALPHA_TARGET(inst->Alpha.Target);

	if (inst->WriteALUResult) {
		code->inst[ip].inst3 |= R500_ALU_RGB_WMASK;

		if (inst->WriteALUResult == RC_ALURESULT_X)
			code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_RED;
		else
			code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_ALPHA;

		code->inst[ip].inst0 |= translate_alu_result_op(c, inst->ALUResultCompare);
	}
}
/**
 * Emit one paired ALU instruction.
 */
static int emit_alu(struct r300_emit_state * emit, struct rc_pair_instruction* inst)
{
	int ip;
	int j;
	PROG_CODE;

	if (code->alu.length >= c->Base.max_alu_insts) {
		error("Too many ALU instructions");
		return 0;
	}

	ip = code->alu.length++;

	code->alu.inst[ip].rgb_inst = translate_rgb_opcode(c, inst->RGB.Opcode);
	code->alu.inst[ip].alpha_inst = translate_alpha_opcode(c, inst->Alpha.Opcode);

	for(j = 0; j < 3; ++j) {
		/* Set the RGB address */
		unsigned int src = use_source(code, inst->RGB.Src[j]);
		unsigned int arg;
		if (inst->RGB.Src[j].Index >= R300_PFS_NUM_TEMP_REGS)
			code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_RGB_MSB_BIT(j);

		code->alu.inst[ip].rgb_addr |= src << (6*j);

		/* Set the Alpha address */
		src = use_source(code, inst->Alpha.Src[j]);
		if (inst->Alpha.Src[j].Index >= R300_PFS_NUM_TEMP_REGS)
			code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_A_MSB_BIT(j);

		code->alu.inst[ip].alpha_addr |= src << (6*j);

		arg = r300FPTranslateRGBSwizzle(inst->RGB.Arg[j].Source, inst->RGB.Arg[j].Swizzle);
		arg |= inst->RGB.Arg[j].Abs << 6;
		arg |= inst->RGB.Arg[j].Negate << 5;
		code->alu.inst[ip].rgb_inst |= arg << (7*j);

		arg = r300FPTranslateAlphaSwizzle(inst->Alpha.Arg[j].Source, inst->Alpha.Arg[j].Swizzle);
		arg |= inst->Alpha.Arg[j].Abs << 6;
		arg |= inst->Alpha.Arg[j].Negate << 5;
		code->alu.inst[ip].alpha_inst |= arg << (7*j);
	}

	/* Presubtract */
	if (inst->RGB.Src[RC_PAIR_PRESUB_SRC].Used) {
		switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) {
		case RC_PRESUB_BIAS:
			code->alu.inst[ip].rgb_inst |=
						R300_ALU_SRCP_1_MINUS_2_SRC0;
			break;
		case RC_PRESUB_ADD:
			code->alu.inst[ip].rgb_inst |=
						R300_ALU_SRCP_SRC1_PLUS_SRC0;
			break;
		case RC_PRESUB_SUB:
			code->alu.inst[ip].rgb_inst |=
						R300_ALU_SRCP_SRC1_MINUS_SRC0;
			break;
		case RC_PRESUB_INV:
			code->alu.inst[ip].rgb_inst |=
						R300_ALU_SRCP_1_MINUS_SRC0;
			break;
		default:
			break;
		}
	}

	if (inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) {
		switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) {
		case RC_PRESUB_BIAS:
			code->alu.inst[ip].alpha_inst |=
						R300_ALU_SRCP_1_MINUS_2_SRC0;
			break;
		case RC_PRESUB_ADD:
			code->alu.inst[ip].alpha_inst |=
						R300_ALU_SRCP_SRC1_PLUS_SRC0;
			break;
		case RC_PRESUB_SUB:
			code->alu.inst[ip].alpha_inst |=
						R300_ALU_SRCP_SRC1_MINUS_SRC0;
			break;
		case RC_PRESUB_INV:
			code->alu.inst[ip].alpha_inst |=
						R300_ALU_SRCP_1_MINUS_SRC0;
			break;
		default:
			break;
		}
	}

	if (inst->RGB.Saturate)
		code->alu.inst[ip].rgb_inst |= R300_ALU_OUTC_CLAMP;
	if (inst->Alpha.Saturate)
		code->alu.inst[ip].alpha_inst |= R300_ALU_OUTA_CLAMP;

	if (inst->RGB.WriteMask) {
		use_temporary(code, inst->RGB.DestIndex);
		if (inst->RGB.DestIndex >= R300_PFS_NUM_TEMP_REGS)
			code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_RGB_MSB_BIT;
		code->alu.inst[ip].rgb_addr |=
			((inst->RGB.DestIndex & 0x1f) << R300_ALU_DSTC_SHIFT) |
			(inst->RGB.WriteMask << R300_ALU_DSTC_REG_MASK_SHIFT);
	}
	if (inst->RGB.OutputWriteMask) {
		code->alu.inst[ip].rgb_addr |=
            (inst->RGB.OutputWriteMask << R300_ALU_DSTC_OUTPUT_MASK_SHIFT) |
            R300_RGB_TARGET(inst->RGB.Target);
		emit->node_flags |= R300_RGBA_OUT;
	}

	if (inst->Alpha.WriteMask) {
		use_temporary(code, inst->Alpha.DestIndex);
		if (inst->Alpha.DestIndex >= R300_PFS_NUM_TEMP_REGS)
			code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_A_MSB_BIT;
		code->alu.inst[ip].alpha_addr |=
			((inst->Alpha.DestIndex & 0x1f) << R300_ALU_DSTA_SHIFT) |
			R300_ALU_DSTA_REG;
	}
	if (inst->Alpha.OutputWriteMask) {
		code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_OUTPUT |
            R300_ALPHA_TARGET(inst->Alpha.Target);
		emit->node_flags |= R300_RGBA_OUT;
	}
	if (inst->Alpha.DepthWriteMask) {
		code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_DEPTH;
		emit->node_flags |= R300_W_OUT;
		c->code->writes_depth = 1;
	}
	if (inst->Nop)
		code->alu.inst[ip].rgb_inst |= R300_ALU_INSERT_NOP;

	/* Handle Output Modifier
	 * According to the r300 docs, there is no RC_OMOD_DISABLE for r300 */
	if (inst->RGB.Omod) {
		if (inst->RGB.Omod == RC_OMOD_DISABLE) {
			rc_error(&c->Base, "RC_OMOD_DISABLE not supported");
		}
		code->alu.inst[ip].rgb_inst |=
			(inst->RGB.Omod << R300_ALU_OUTC_MOD_SHIFT);
	}
	if (inst->Alpha.Omod) {
		if (inst->Alpha.Omod == RC_OMOD_DISABLE) {
			rc_error(&c->Base, "RC_OMOD_DISABLE not supported");
		}
		code->alu.inst[ip].alpha_inst |=
			(inst->Alpha.Omod << R300_ALU_OUTC_MOD_SHIFT);
	}
	return 1;
}
static GLuint use_source(struct r500_fragment_program_code* code, struct radeon_pair_instruction_source src)
{
	if (!src.Constant)
		use_temporary(code, src.Index);
	return src.Index | src.Constant << 8;
}
/**
 * Emit a paired ALU instruction.
 */
static void emit_paired(struct r300_fragment_program_compiler *c, struct rc_pair_instruction *inst)
{
	PROG_CODE;

	if (code->inst_end >= 511) {
		error("emit_alu: Too many instructions");
		return;
	}

	int ip = ++code->inst_end;

	code->inst[ip].inst5 = translate_rgb_op(c, inst->RGB.Opcode);
	code->inst[ip].inst4 = translate_alpha_op(c, inst->Alpha.Opcode);

	if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) {
		code->inst[ip].inst0 = R500_INST_TYPE_OUT;
		if (inst->WriteALUResult) {
			error("%s: cannot write output and ALU result at the same time");
			return;
		}
	} else {
		code->inst[ip].inst0 = R500_INST_TYPE_ALU;
	}
	code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT;

	code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11) | (inst->Alpha.WriteMask << 14);
	code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18);
	if (inst->Alpha.DepthWriteMask) {
		code->inst[ip].inst4 |= R500_ALPHA_W_OMASK;
		c->code->writes_depth = 1;
	}

	code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex);
	code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex);
	use_temporary(code, inst->Alpha.DestIndex);
	use_temporary(code, inst->RGB.DestIndex);

	if (inst->RGB.Saturate)
		code->inst[ip].inst0 |= R500_INST_RGB_CLAMP;
	if (inst->Alpha.Saturate)
		code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP;

	code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0]));
	code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1]));
	code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2]));

	code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1]));
	code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2]));

	code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT;
	code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT;

	code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT;
	code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT;
	code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT;

    code->inst[ip].inst3 |= R500_ALU_RGB_TARGET(inst->RGB.Target);
    code->inst[ip].inst4 |= R500_ALPHA_TARGET(inst->Alpha.Target);

	if (inst->WriteALUResult) {
		code->inst[ip].inst3 |= R500_ALU_RGB_WMASK;

		if (inst->WriteALUResult == RC_ALURESULT_X)
			code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_RED;
		else
			code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_ALPHA;

		code->inst[ip].inst0 |= translate_alu_result_op(c, inst->ALUResultCompare);
	}
}