Exemplo n.º 1
0
/* This function calls the callback function (cb) for each source used by
 * the instruction.
 * */
void rc_for_all_reads_src(
	struct rc_instruction * inst,
	rc_read_src_fn cb,
	void * userdata)
{
	const struct rc_opcode_info * opcode =
					rc_get_opcode_info(inst->U.I.Opcode);

	/* This function only works with normal instructions. */
	if (inst->Type != RC_INSTRUCTION_NORMAL) {
		assert(0);
		return;
	}

	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {

		if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)
			continue;

		if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
			unsigned int i;
			unsigned int srcp_regs = rc_presubtract_src_reg_count(
						inst->U.I.PreSub.Opcode);
			for( i = 0; i < srcp_regs; i++) {
				cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
			}
		} else {
			cb(userdata, inst, &inst->U.I.SrcReg[src]);
		}
	}
}
Exemplo n.º 2
0
static void presub_nop(struct rc_instruction * emitted) {
	int prev_rgb_index, prev_alpha_index, i, num_src;

	/* We don't need a nop if the previous instruction is a TEX. */
	if (emitted->Prev->Type != RC_INSTRUCTION_PAIR) {
		return;
	}
	if (emitted->Prev->U.P.RGB.WriteMask)
		prev_rgb_index = emitted->Prev->U.P.RGB.DestIndex;
	else
		prev_rgb_index = -1;
	if (emitted->Prev->U.P.Alpha.WriteMask)
		prev_alpha_index = emitted->Prev->U.P.Alpha.DestIndex;
	else
		prev_alpha_index = 1;

	/* Check the previous rgb instruction */
	if (emitted->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used) {
		num_src = rc_presubtract_src_reg_count(
				emitted->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index);
		for (i = 0; i < num_src; i++) {
			unsigned int index = emitted->U.P.RGB.Src[i].Index;
			if (emitted->U.P.RGB.Src[i].File == RC_FILE_TEMPORARY
			    && (index  == prev_rgb_index
				|| index == prev_alpha_index)) {
				emitted->Prev->U.P.Nop = 1;
				return;
			}
		}
	}

	/* Check the previous alpha instruction. */
	if (!emitted->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used)
		return;

	num_src = rc_presubtract_src_reg_count(
				emitted->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
	for (i = 0; i < num_src; i++) {
		unsigned int index = emitted->U.P.Alpha.Src[i].Index;
		if(emitted->U.P.Alpha.Src[i].File == RC_FILE_TEMPORARY
		   && (index == prev_rgb_index || index == prev_alpha_index)) {
			emitted->Prev->U.P.Nop = 1;
			return;
		}
	}
}
static void mark_used_presub(struct rc_pair_sub_instruction * sub)
{
	if (sub->Src[RC_PAIR_PRESUB_SRC].Used) {
		unsigned int presub_reg_count = rc_presubtract_src_reg_count(
					sub->Src[RC_PAIR_PRESUB_SRC].Index);
		unsigned int i;
		for (i = 0; i < presub_reg_count; i++) {
			sub->Src[i].Used = 1;
		}
	}
}
Exemplo n.º 4
0
static void pair_foreach_source_callback(
	struct rc_pair_instruction * pair,
	void * data,
	rc_pair_foreach_src_fn cb,
	unsigned int swz,
	unsigned int src)
{
	/* swz > 3 means that the swizzle is either not used, or a constant
	 * swizzle (e.g. 0, 1, 0.5). */
	if(swz > 3)
		return;

	if(swz == RC_SWIZZLE_W) {
		if (src == RC_PAIR_PRESUB_SRC) {
			unsigned int i;
			unsigned int src_count = rc_presubtract_src_reg_count(
				pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
			for(i = 0; i < src_count; i++) {
				cb(data, &pair->Alpha.Src[i]);
			}
		} else {
			cb(data, &pair->Alpha.Src[src]);
		}
	} else {
		if (src == RC_PAIR_PRESUB_SRC) {
			unsigned int i;
			unsigned int src_count = rc_presubtract_src_reg_count(
				pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index);
			for(i = 0; i < src_count; i++) {
				cb(data, &pair->RGB.Src[i]);
			}
		}
		else {
			cb(data, &pair->RGB.Src[src]);
		}
	}
}
Exemplo n.º 5
0
static void pair_get_src_refmasks(unsigned int * refmasks,
					struct rc_pair_instruction * inst,
					unsigned int swz, unsigned int src)
{
	if (swz >= 4)
		return;

	if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
		if(src == RC_PAIR_PRESUB_SRC) {
			unsigned int i;
			int srcp_regs =
				rc_presubtract_src_reg_count(
				inst->RGB.Src[src].Index);
			for(i = 0; i < srcp_regs; i++) {
				refmasks[i] |= 1 << swz;
			}
		}
		else {
			refmasks[src] |= 1 << swz;
		}
	}

	if (swz == RC_SWIZZLE_W) {
		if (src == RC_PAIR_PRESUB_SRC) {
			unsigned int i;
			int srcp_regs = rc_presubtract_src_reg_count(
					inst->Alpha.Src[src].Index);
			for(i = 0; i < srcp_regs; i++) {
				refmasks[i] |= 1 << swz;
			}
		}
		else {
			refmasks[src] |= 1 << swz;
		}
	}
}
Exemplo n.º 6
0
static void remap_normal_instruction(struct rc_instruction * fullinst,
		rc_remap_register_fn cb, void * userdata)
{
	struct rc_sub_instruction * inst = &fullinst->U.I;
	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
	unsigned int remapped_presub = 0;

	if (opcode->HasDstReg) {
		rc_register_file file = inst->DstReg.File;
		unsigned int index = inst->DstReg.Index;

		cb(userdata, fullinst, &file, &index);

		inst->DstReg.File = file;
		inst->DstReg.Index = index;
	}

	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
		rc_register_file file = inst->SrcReg[src].File;
		unsigned int index = inst->SrcReg[src].Index;

		if (file == RC_FILE_PRESUB) {
			unsigned int i;
			unsigned int srcp_srcs = rc_presubtract_src_reg_count(
						inst->PreSub.Opcode);
			/* Make sure we only remap presubtract sources once in
			 * case more than one source register reads the
			 * presubtract result. */
			if (remapped_presub)
				continue;

			for(i = 0; i < srcp_srcs; i++) {
				file = inst->PreSub.SrcReg[i].File;
				index = inst->PreSub.SrcReg[i].Index;
				cb(userdata, fullinst, &file, &index);
				inst->PreSub.SrcReg[i].File = file;
				inst->PreSub.SrcReg[i].Index = index;
			}
			remapped_presub = 1;
		}
		else {
			cb(userdata, fullinst, &file, &index);

			inst->SrcReg[src].File = file;
			inst->SrcReg[src].Index = index;
		}
	}
}
Exemplo n.º 7
0
static void pair_sub_for_all_args(
	struct rc_instruction * fullinst,
	struct rc_pair_sub_instruction * sub,
	rc_pair_read_arg_fn cb,
	void * userdata)
{
	int i;
	const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);

	for(i = 0; i < info->NumSrcRegs; i++) {
		unsigned int src_type;

		src_type = rc_source_type_swz(sub->Arg[i].Swizzle);

		if (src_type == RC_SOURCE_NONE)
			continue;

		if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) {
			unsigned int presub_type;
			unsigned int presub_src_count;
			struct rc_pair_instruction_source * src_array;
			unsigned int j;

			if (src_type & RC_SOURCE_RGB) {
				presub_type = fullinst->
					U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;
				src_array = fullinst->U.P.RGB.Src;
			} else {
				presub_type = fullinst->
					U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;
				src_array = fullinst->U.P.Alpha.Src;
			}
			presub_src_count
				= rc_presubtract_src_reg_count(presub_type);
			for(j = 0; j < presub_src_count; j++) {
				cb(userdata, fullinst, &sub->Arg[i],
								&src_array[j]);
			}
		} else {
			struct rc_pair_instruction_source * src =
				rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);
			if (src) {
				cb(userdata, fullinst, &sub->Arg[i], src);
			}
		}
	}
}
Exemplo n.º 8
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;
}
Exemplo n.º 10
0
/**
 * Return the source slot where we installed the given register access,
 * or -1 if no slot was free anymore.
 */
int rc_pair_alloc_source(struct rc_pair_instruction *pair,
	unsigned int rgb, unsigned int alpha,
	rc_register_file file, unsigned int index)
{
	int candidate = -1;
	int candidate_quality = -1;
	unsigned int alpha_used = 0;
	unsigned int rgb_used = 0;
	int i;

	if ((!rgb && !alpha) || file == RC_FILE_NONE)
		return 0;

	/* Make sure only one presubtract operation is used per instruction. */
	if (file == RC_FILE_PRESUB) {
		if (rgb && pair->RGB.Src[RC_PAIR_PRESUB_SRC].Used
			&& index != pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index) {
				return -1;
		}

		if (alpha && pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Used
			&& index != pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) {
				return -1;
		}
	}

	for(i = 0; i < 3; ++i) {
		int q = 0;
		if (rgb) {
			if (pair->RGB.Src[i].Used) {
				if (pair->RGB.Src[i].File != file ||
				    pair->RGB.Src[i].Index != index) {
					rgb_used++;
					continue;
				}
				q++;
			}
		}
		if (alpha) {
			if (pair->Alpha.Src[i].Used) {
				if (pair->Alpha.Src[i].File != file ||
				    pair->Alpha.Src[i].Index != index) {
					alpha_used++;
					continue;
				}
				q++;
			}
		}
		if (q > candidate_quality) {
			candidate_quality = q;
			candidate = i;
		}
	}

	if (file == RC_FILE_PRESUB) {
		candidate = RC_PAIR_PRESUB_SRC;
	} else if (candidate < 0 || (rgb && rgb_used > 2)
			|| (alpha && alpha_used > 2)) {
		return -1;
	}

	/* candidate >= 0 */

	if (rgb) {
		pair->RGB.Src[candidate].Used = 1;
		pair->RGB.Src[candidate].File = file;
		pair->RGB.Src[candidate].Index = index;
		if (candidate == RC_PAIR_PRESUB_SRC) {
			/* For registers with the RC_FILE_PRESUB file,
			 * the index stores the presubtract op. */
			int src_regs = rc_presubtract_src_reg_count(index);
			for(i = 0; i < src_regs; i++) {
				pair->RGB.Src[i].Used = 1;
			}
		}
	}
	if (alpha) {
		pair->Alpha.Src[candidate].Used = 1;
		pair->Alpha.Src[candidate].File = file;
		pair->Alpha.Src[candidate].Index = index;
		if (candidate == RC_PAIR_PRESUB_SRC) {
			/* For registers with the RC_FILE_PRESUB file,
			 * the index stores the presubtract op. */
			int src_regs = rc_presubtract_src_reg_count(index);
			for(i=0; i < src_regs; i++) {
				pair->Alpha.Src[i].Used = 1;
			}
		}
	}

	return candidate;
}