static void rgb_to_alpha_remap (
	struct rc_instruction * inst,
	struct rc_pair_instruction_arg * arg,
	rc_register_file old_file,
	rc_swizzle old_swz,
	unsigned int new_index)
{
	int new_src_index;
	unsigned int i;

	for (i = 0; i < 3; i++) {
		if (get_swz(arg->Swizzle, i) == old_swz) {
			SET_SWZ(arg->Swizzle, i, RC_SWIZZLE_W);
		}
	}
	new_src_index = rc_pair_alloc_source(&inst->U.P, 0, 1,
							old_file, new_index);
	/* This conversion is not possible, we must have made a mistake in
	 * is_rgb_to_alpha_possible. */
	if (new_src_index < 0) {
		assert(0);
		return;
	}

	arg->Source = new_src_index;
}
Beispiel #2
0
static int destructive_merge_instructions(
		struct rc_pair_instruction * rgb,
		struct rc_pair_instruction * alpha)
{
	const struct rc_opcode_info * opcode;
	assert(rgb->Alpha.Opcode == RC_OPCODE_NOP);
	assert(alpha->RGB.Opcode == RC_OPCODE_NOP);

	/* Presubtract registers need to be merged first so that registers
	 * needed by the presubtract operation can be placed in src0 and/or
	 * src1. */

	/* Merge the rgb presubtract registers. */
	const struct rc_opcode_info * rgb_info =
					rc_get_opcode_info(rgb->RGB.Opcode);
	if (alpha->RGB.Src[RC_PAIR_PRESUB_SRC].Used) {
		unsigned int srcp_src;
		unsigned int srcp_regs;
		if (rgb->RGB.Src[RC_PAIR_PRESUB_SRC].Used)
			return 0;
		srcp_regs = rc_presubtract_src_reg_count(
				alpha->RGB.Src[RC_PAIR_PRESUB_SRC].Index);
		for(srcp_src = 0; srcp_src < srcp_regs; srcp_src++) {
			unsigned int arg;
			int free_source;
			unsigned int one_way = 0;
			struct radeon_pair_instruction_source srcp =
						alpha->RGB.Src[srcp_src];
			struct radeon_pair_instruction_source temp;
			/* 2nd arg of 1 means this is an rgb source.
			 * 3rd arg of 0 means this is not an alpha source. */
			free_source = rc_pair_alloc_source(rgb, 1, 0,
							srcp.File, srcp.Index);
			/* If free_source < 0 then there are no free source
			 * slots. */
			if (free_source < 0)
				return 0;

			temp = rgb->RGB.Src[srcp_src];
			rgb->RGB.Src[srcp_src] = rgb->RGB.Src[free_source];
			/* srcp needs src0 and src1 to be the same */
			if (free_source < srcp_src) {
				if (!temp.Used)
					continue;
				free_source = rc_pair_alloc_source(rgb, 1, 0,
							srcp.File, srcp.Index);
				one_way = 1;
			} else {
				rgb->RGB.Src[free_source] = temp;
			}
			/* If free_source == srcp_src, then the presubtract
			 * source is already in the correct place. */
			if (free_source == srcp_src)
				continue;
			/* Shuffle the sources, so we can put the
			 * presubtract source in the correct place. */
			for (arg = 0; arg < rgb_info->NumSrcRegs; arg++) {
				/*If this arg does not read from an rgb source,
				 * do nothing. */
				if (rc_source_type_that_arg_reads(
					rgb->RGB.Arg[arg].Source,
					rgb->RGB.Arg[arg].Swizzle, 3)
							!= RC_PAIR_SOURCE_RGB) {
					continue;
				}
				if (rgb->RGB.Arg[arg].Source == srcp_src)
					rgb->RGB.Arg[arg].Source = free_source;
				/* We need to do this just in case register
				 * is one of the sources already, but in the
				 * wrong spot. */
				else if(rgb->RGB.Arg[arg].Source == free_source
								&& !one_way) {
					rgb->RGB.Arg[arg].Source = srcp_src;
				}
			}
		}
	}

	/* Merge the alpha presubtract registers */
	if (alpha->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) {
		unsigned int srcp_src;
		unsigned int srcp_regs;
		if(rgb->Alpha.Src[RC_PAIR_PRESUB_SRC].Used)
			return 0;

		srcp_regs = rc_presubtract_src_reg_count(
			alpha->Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
		for(srcp_src = 0; srcp_src < srcp_regs; srcp_src++) {
			unsigned int arg;
			int free_source;
			unsigned int one_way = 0;
			struct radeon_pair_instruction_source srcp =
						alpha->Alpha.Src[srcp_src];
			struct radeon_pair_instruction_source temp;
			/* 2nd arg of 0 means this is not an rgb source.
			 * 3rd arg of 1 means this is an alpha source. */
			free_source = rc_pair_alloc_source(rgb, 0, 1,
							srcp.File, srcp.Index);
			/* If free_source < 0 then there are no free source
			 * slots. */
			if (free_source < 0)
				return 0;

			temp = rgb->Alpha.Src[srcp_src];
			rgb->Alpha.Src[srcp_src] = rgb->Alpha.Src[free_source];
			/* srcp needs src0 and src1 to be the same. */
			if (free_source < srcp_src) {
				if (!temp.Used)
					continue;
				free_source = rc_pair_alloc_source(rgb, 0, 1,
							temp.File, temp.Index);
				one_way = 1;
			} else {
				rgb->Alpha.Src[free_source] = temp;
			}
			/* If free_source == srcp_src, then the presubtract
			 * source is already in the correct place. */
			if (free_source == srcp_src)
				continue;
			/* Shuffle the sources, so we can put the
			 * presubtract source in the correct place. */
			for(arg = 0; arg < rgb_info->NumSrcRegs; arg++) {
				/*If this arg does not read from an alpha
				 * source, do nothing. */
				if (rc_source_type_that_arg_reads(
					rgb->RGB.Arg[arg].Source,
					rgb->RGB.Arg[arg].Swizzle, 3)
						!= RC_PAIR_SOURCE_ALPHA) {
					continue;
				}
				if (rgb->RGB.Arg[arg].Source == srcp_src)
					rgb->RGB.Arg[arg].Source = free_source;
				else if (rgb->RGB.Arg[arg].Source == free_source
								&& !one_way) {
					rgb->RGB.Arg[arg].Source = srcp_src;
				}
			}
		}
	}

	/* Copy alpha args into rgb */
	opcode = rc_get_opcode_info(alpha->Alpha.Opcode);

	for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
		unsigned int srcrgb = 0;
		unsigned int srcalpha = 0;
		unsigned int oldsrc = alpha->Alpha.Arg[arg].Source;
		rc_register_file file = 0;
		unsigned int index = 0;

		if (alpha->Alpha.Arg[arg].Swizzle < 3) {
			srcrgb = 1;
			file = alpha->RGB.Src[oldsrc].File;
			index = alpha->RGB.Src[oldsrc].Index;
		} else if (alpha->Alpha.Arg[arg].Swizzle < 4) {
			srcalpha = 1;
			file = alpha->Alpha.Src[oldsrc].File;
			index = alpha->Alpha.Src[oldsrc].Index;
		}

		int source = rc_pair_alloc_source(rgb, srcrgb, srcalpha, file, index);
		if (source < 0)
			return 0;

		rgb->Alpha.Arg[arg].Source = source;
		rgb->Alpha.Arg[arg].Swizzle = alpha->Alpha.Arg[arg].Swizzle;
		rgb->Alpha.Arg[arg].Abs = alpha->Alpha.Arg[arg].Abs;
		rgb->Alpha.Arg[arg].Negate = alpha->Alpha.Arg[arg].Negate;
	}

	/* Copy alpha opcode into rgb */
	rgb->Alpha.Opcode = alpha->Alpha.Opcode;
	rgb->Alpha.DestIndex = alpha->Alpha.DestIndex;
	rgb->Alpha.WriteMask = alpha->Alpha.WriteMask;
	rgb->Alpha.OutputWriteMask = alpha->Alpha.OutputWriteMask;
	rgb->Alpha.DepthWriteMask = alpha->Alpha.DepthWriteMask;
	rgb->Alpha.Saturate = alpha->Alpha.Saturate;

	/* Merge ALU result writing */
	if (alpha->WriteALUResult) {
		if (rgb->WriteALUResult)
			return 0;

		rgb->WriteALUResult = alpha->WriteALUResult;
		rgb->ALUResultCompare = alpha->ALUResultCompare;
	}

	return 1;
}
/* This is a helper function for destructive_merge_instructions().  It helps
 * merge presubtract sources from two instructions and makes sure the
 * presubtract sources end up in the correct spot.  This function assumes that
 * dst_full is an rgb instruction, meaning that it has a vector instruction(rgb)
 * but no scalar instruction (alpha).
 * @return 0 if merging the presubtract sources fails.
 * @retrun 1 if merging the presubtract sources succeeds.
 */
static int merge_presub_sources(
	struct rc_pair_instruction * dst_full,
	struct rc_pair_sub_instruction src,
	unsigned int type)
{
	unsigned int srcp_src, srcp_regs, is_rgb, is_alpha;
	struct rc_pair_sub_instruction * dst_sub;
	const struct rc_opcode_info * info;

	assert(dst_full->Alpha.Opcode == RC_OPCODE_NOP);

	switch(type) {
	case RC_SOURCE_RGB:
		is_rgb = 1;
		is_alpha = 0;
		dst_sub = &dst_full->RGB;
		break;
	case RC_SOURCE_ALPHA:
		is_rgb = 0;
		is_alpha = 1;
		dst_sub = &dst_full->Alpha;
		break;
	default:
		assert(0);
		return 0;
	}

	info = rc_get_opcode_info(dst_full->RGB.Opcode);

	if (dst_sub->Src[RC_PAIR_PRESUB_SRC].Used)
		return 0;

	srcp_regs = rc_presubtract_src_reg_count(
					src.Src[RC_PAIR_PRESUB_SRC].Index);
	for(srcp_src = 0; srcp_src < srcp_regs; srcp_src++) {
		unsigned int arg;
		int free_source;
		unsigned int one_way = 0;
		struct rc_pair_instruction_source srcp = src.Src[srcp_src];
		struct rc_pair_instruction_source temp;

		free_source = rc_pair_alloc_source(dst_full, is_rgb, is_alpha,
							srcp.File, srcp.Index);

		/* If free_source < 0 then there are no free source
		 * slots. */
		if (free_source < 0)
			return 0;

		temp = dst_sub->Src[srcp_src];
		dst_sub->Src[srcp_src] = dst_sub->Src[free_source];

		/* srcp needs src0 and src1 to be the same */
		if (free_source < srcp_src) {
			if (!temp.Used)
				continue;
			free_source = rc_pair_alloc_source(dst_full, is_rgb,
					is_alpha, temp.File, temp.Index);
			if (free_source < 0)
				return 0;
			one_way = 1;
		} else {
			dst_sub->Src[free_source] = temp;
		}

		/* If free_source == srcp_src, then the presubtract
		 * source is already in the correct place. */
		if (free_source == srcp_src)
			continue;

		/* Shuffle the sources, so we can put the
		 * presubtract source in the correct place. */
		for(arg = 0; arg < info->NumSrcRegs; arg++) {
			/*If this arg does not read from an rgb source,
			 * do nothing. */
			if (!(rc_source_type_swz(dst_full->RGB.Arg[arg].Swizzle,
								3) & type)) {
				continue;
			}

			if (dst_full->RGB.Arg[arg].Source == srcp_src)
				dst_full->RGB.Arg[arg].Source = free_source;
			/* We need to do this just in case register
			 * is one of the sources already, but in the
			 * wrong spot. */
			else if(dst_full->RGB.Arg[arg].Source == free_source
							&& !one_way) {
				dst_full->RGB.Arg[arg].Source = srcp_src;
			}
		}
	}
	return 1;
}
/* This function assumes that rgb.Alpha and alpha.RGB are unused */
static int destructive_merge_instructions(
		struct rc_pair_instruction * rgb,
		struct rc_pair_instruction * alpha)
{
	const struct rc_opcode_info * opcode;

	assert(rgb->Alpha.Opcode == RC_OPCODE_NOP);
	assert(alpha->RGB.Opcode == RC_OPCODE_NOP);

	/* Presubtract registers need to be merged first so that registers
	 * needed by the presubtract operation can be placed in src0 and/or
	 * src1. */

	/* Merge the rgb presubtract registers. */
	if (alpha->RGB.Src[RC_PAIR_PRESUB_SRC].Used) {
		if (!merge_presub_sources(rgb, alpha->RGB, RC_SOURCE_RGB)) {
			return 0;
		}
	}
	/* Merge the alpha presubtract registers */
	if (alpha->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) {
		if(!merge_presub_sources(rgb,  alpha->Alpha, RC_SOURCE_ALPHA)){
			return 0;
		}
	}

	/* Copy alpha args into rgb */
	opcode = rc_get_opcode_info(alpha->Alpha.Opcode);

	for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
		unsigned int srcrgb = 0;
		unsigned int srcalpha = 0;
		unsigned int oldsrc = alpha->Alpha.Arg[arg].Source;
		rc_register_file file = 0;
		unsigned int index = 0;
		int source;

		if (alpha->Alpha.Arg[arg].Swizzle < 3) {
			srcrgb = 1;
			file = alpha->RGB.Src[oldsrc].File;
			index = alpha->RGB.Src[oldsrc].Index;
		} else if (alpha->Alpha.Arg[arg].Swizzle < 4) {
			srcalpha = 1;
			file = alpha->Alpha.Src[oldsrc].File;
			index = alpha->Alpha.Src[oldsrc].Index;
		}

		source = rc_pair_alloc_source(rgb, srcrgb, srcalpha, file, index);
		if (source < 0)
			return 0;

		rgb->Alpha.Arg[arg].Source = source;
		rgb->Alpha.Arg[arg].Swizzle = alpha->Alpha.Arg[arg].Swizzle;
		rgb->Alpha.Arg[arg].Abs = alpha->Alpha.Arg[arg].Abs;
		rgb->Alpha.Arg[arg].Negate = alpha->Alpha.Arg[arg].Negate;
	}

	/* Copy alpha opcode into rgb */
	rgb->Alpha.Opcode = alpha->Alpha.Opcode;
	rgb->Alpha.DestIndex = alpha->Alpha.DestIndex;
	rgb->Alpha.WriteMask = alpha->Alpha.WriteMask;
	rgb->Alpha.OutputWriteMask = alpha->Alpha.OutputWriteMask;
	rgb->Alpha.DepthWriteMask = alpha->Alpha.DepthWriteMask;
	rgb->Alpha.Saturate = alpha->Alpha.Saturate;

	/* Merge ALU result writing */
	if (alpha->WriteALUResult) {
		if (rgb->WriteALUResult)
			return 0;

		rgb->WriteALUResult = alpha->WriteALUResult;
		rgb->ALUResultCompare = alpha->ALUResultCompare;
	}

	return 1;
}
/**
 * Fill the given ALU instruction's opcodes and source operands into the given pair,
 * if possible.
 */
static void set_pair_instruction(struct r300_fragment_program_compiler *c,
	struct rc_pair_instruction * pair,
	struct rc_sub_instruction * inst)
{
	memset(pair, 0, sizeof(struct rc_pair_instruction));

	int needrgb, needalpha, istranscendent;
	classify_instruction(inst, &needrgb, &needalpha, &istranscendent);

	if (needrgb) {
		if (istranscendent)
			pair->RGB.Opcode = RC_OPCODE_REPL_ALPHA;
		else
			pair->RGB.Opcode = inst->Opcode;
		if (inst->SaturateMode == RC_SATURATE_ZERO_ONE)
			pair->RGB.Saturate = 1;
	}
	if (needalpha) {
		pair->Alpha.Opcode = inst->Opcode;
		if (inst->SaturateMode == RC_SATURATE_ZERO_ONE)
			pair->Alpha.Saturate = 1;
	}

	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
	int nargs = opcode->NumSrcRegs;
	int i;

	/* Special case for DDX/DDY (MDH/MDV). */
	if (inst->Opcode == RC_OPCODE_DDX || inst->Opcode == RC_OPCODE_DDY) {
		nargs++;
	}

	for(i = 0; i < opcode->NumSrcRegs; ++i) {
		int source;
		if (needrgb && !istranscendent) {
			unsigned int srcrgb = 0;
			unsigned int srcalpha = 0;
			int j;
			for(j = 0; j < 3; ++j) {
				unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, j);
				if (swz < 3)
					srcrgb = 1;
				else if (swz < 4)
					srcalpha = 1;
			}
			source = rc_pair_alloc_source(pair, srcrgb, srcalpha,
							inst->SrcReg[i].File, inst->SrcReg[i].Index);
			pair->RGB.Arg[i].Source = source;
			pair->RGB.Arg[i].Swizzle = inst->SrcReg[i].Swizzle & 0x1ff;
			pair->RGB.Arg[i].Abs = inst->SrcReg[i].Abs;
			pair->RGB.Arg[i].Negate = !!(inst->SrcReg[i].Negate & (RC_MASK_X | RC_MASK_Y | RC_MASK_Z));
		}
		if (needalpha) {
			unsigned int srcrgb = 0;
			unsigned int srcalpha = 0;
			unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, istranscendent ? 0 : 3);
			if (swz < 3)
				srcrgb = 1;
			else if (swz < 4)
				srcalpha = 1;
			source = rc_pair_alloc_source(pair, srcrgb, srcalpha,
							inst->SrcReg[i].File, inst->SrcReg[i].Index);
			pair->Alpha.Arg[i].Source = source;
			pair->Alpha.Arg[i].Swizzle = swz;
			pair->Alpha.Arg[i].Abs = inst->SrcReg[i].Abs;
			pair->Alpha.Arg[i].Negate = !!(inst->SrcReg[i].Negate & RC_MASK_W);
		}
	}

	/* Destination handling */
	if (inst->DstReg.File == RC_FILE_OUTPUT) {
        if (inst->DstReg.Index == c->OutputDepth) {
            pair->Alpha.DepthWriteMask |= GET_BIT(inst->DstReg.WriteMask, 3);
        } else {
            for (i = 0; i < 4; i++) {
                if (inst->DstReg.Index == c->OutputColor[i]) {
                    pair->RGB.Target = i;
                    pair->Alpha.Target = i;
                    pair->RGB.OutputWriteMask |=
                        inst->DstReg.WriteMask & RC_MASK_XYZ;
                    pair->Alpha.OutputWriteMask |=
                        GET_BIT(inst->DstReg.WriteMask, 3);
                    break;
                }
            }
        }
	} else {
		if (needrgb) {
			pair->RGB.DestIndex = inst->DstReg.Index;
			pair->RGB.WriteMask |= inst->DstReg.WriteMask & RC_MASK_XYZ;
		}
		if (needalpha) {
			pair->Alpha.DestIndex = inst->DstReg.Index;
			pair->Alpha.WriteMask |= GET_BIT(inst->DstReg.WriteMask, 3);
		}
	}

	if (inst->WriteALUResult) {
		pair->WriteALUResult = inst->WriteALUResult;
		pair->ALUResultCompare = inst->ALUResultCompare;
	}
}