Ejemplo n.º 1
0
static void scan_write(void * data, struct rc_instruction * inst,
		rc_register_file file, unsigned int index, unsigned int chan)
{
	struct schedule_state * s = data;
	struct reg_value ** pv = get_reg_valuep(s, file, index, chan);

	if (!pv)
		return;

	DBG("%i: write %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan);

	struct reg_value * newv = memory_pool_malloc(&s->C->Pool, sizeof(*newv));
	memset(newv, 0, sizeof(*newv));

	newv->Writer = s->Current;

	if (*pv) {
		(*pv)->Next = newv;
		s->Current->NumDependencies++;
	}

	*pv = newv;

	if (s->Current->NumWriteValues >= 4) {
		rc_error(s->C, "%s: NumWriteValues overflow\n", __FUNCTION__);
	} else {
		s->Current->WriteValues[s->Current->NumWriteValues++] = newv;
	}
}
Ejemplo n.º 2
0
static void scan_read(void * data, struct rc_instruction * inst,
		rc_register_file file, unsigned int index, unsigned int chan)
{
	struct schedule_state * s = data;
	struct reg_value ** v = get_reg_valuep(s, file, index, chan);
	struct reg_value_reader * reader;

	if (!v)
		return;

	if (*v && (*v)->Writer == s->Current) {
		/* The instruction reads and writes to a register component.
		 * In this case, we only want to increment dependencies by one.
		 */
		return;
	}

	DBG("%i: read %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan);

	reader = memory_pool_malloc(&s->C->Pool, sizeof(*reader));
	reader->Reader = s->Current;
	if (!*v) {
		/* In this situation, the instruction reads from a register
		 * that hasn't been written to or read from in the current
		 * block. */
		*v = memory_pool_malloc(&s->C->Pool, sizeof(struct reg_value));
		memset(*v, 0, sizeof(struct reg_value));
		(*v)->Readers = reader;
	} else {
		reader->Next = (*v)->Readers;
		(*v)->Readers = reader;
		/* Only update the current instruction's dependencies if the
		 * register it reads from has been written to in this block. */
		if ((*v)->Writer) {
			s->Current->NumDependencies++;
		}
	}
	(*v)->NumReaders++;

	if (s->Current->NumReadValues >= 12) {
		rc_error(s->C, "%s: NumReadValues overflow\n", __FUNCTION__);
	} else {
		s->Current->ReadValues[s->Current->NumReadValues++] = *v;
	}
}
static int convert_rgb_to_alpha(
	struct schedule_state * s,
	struct schedule_instruction * sched_inst)
{
	struct rc_pair_instruction * pair_inst = &sched_inst->Instruction->U.P;
	unsigned int old_mask = pair_inst->RGB.WriteMask;
	unsigned int old_swz = rc_mask_to_swizzle(old_mask);
	const struct rc_opcode_info * info =
				rc_get_opcode_info(pair_inst->RGB.Opcode);
	int new_index = -1;
	unsigned int i;

	if (sched_inst->GlobalReaders.Abort)
		return 0;

	if (!pair_inst->RGB.WriteMask)
		return 0;

	if (!can_convert_opcode_to_alpha(pair_inst->RGB.Opcode)
	    || !can_convert_opcode_to_alpha(pair_inst->Alpha.Opcode)) {
		return 0;
	}

	assert(sched_inst->NumWriteValues == 1);

	if (!sched_inst->WriteValues[0]) {
		assert(0);
		return 0;
	}

	/* We start at the old index, because if we can reuse the same
	 * register and just change the swizzle then it is more likely we
	 * will be able to convert all the readers. */
	for (i = pair_inst->RGB.DestIndex; i < RC_REGISTER_MAX_INDEX; i++) {
		struct reg_value ** new_regvalp = get_reg_valuep(
						s, RC_FILE_TEMPORARY, i, 3);
		if (!*new_regvalp) {
			struct reg_value ** old_regvalp =
				get_reg_valuep(s,
					RC_FILE_TEMPORARY,
					pair_inst->RGB.DestIndex,
					rc_mask_to_swizzle(old_mask));
			new_index = i;
			*new_regvalp = *old_regvalp;
			*old_regvalp = NULL;
			new_regvalp = get_reg_valuep(s, RC_FILE_TEMPORARY, i, 3);
			break;
		}
	}
	if (new_index < 0) {
		return 0;
	}

	pair_inst->Alpha.Opcode = pair_inst->RGB.Opcode;
	pair_inst->Alpha.DestIndex = new_index;
	pair_inst->Alpha.WriteMask = 1;
	pair_inst->Alpha.Target = pair_inst->RGB.Target;
	pair_inst->Alpha.OutputWriteMask = pair_inst->RGB.OutputWriteMask;
	pair_inst->Alpha.DepthWriteMask = pair_inst->RGB.DepthWriteMask;
	pair_inst->Alpha.Saturate = pair_inst->RGB.Saturate;
	memcpy(pair_inst->Alpha.Arg, pair_inst->RGB.Arg,
						sizeof(pair_inst->Alpha.Arg));
	/* Move the swizzles into the first chan */
	for (i = 0; i < info->NumSrcRegs; i++) {
		unsigned int j;
		for (j = 0; j < 3; j++) {
			unsigned int swz = get_swz(pair_inst->Alpha.Arg[i].Swizzle, j);
			if (swz != RC_SWIZZLE_UNUSED) {
				pair_inst->Alpha.Arg[i].Swizzle = swz;
				break;
			}
		}
	}
	pair_inst->RGB.Opcode = RC_OPCODE_NOP;
	pair_inst->RGB.DestIndex = 0;
	pair_inst->RGB.WriteMask = 0;
	pair_inst->RGB.Target = 0;
	pair_inst->RGB.OutputWriteMask = 0;
	pair_inst->RGB.DepthWriteMask = 0;
	pair_inst->RGB.Saturate = 0;
	memset(pair_inst->RGB.Arg, 0, sizeof(pair_inst->RGB.Arg));

	for(i = 0; i < sched_inst->GlobalReaders.ReaderCount; i++) {
		struct rc_reader reader = sched_inst->GlobalReaders.Readers[i];
		rgb_to_alpha_remap(reader.Inst, reader.U.Arg,
					RC_FILE_TEMPORARY, old_swz, new_index);
	}
	return 1;
}
static void scan_read(void * data, struct rc_instruction * inst,
		rc_register_file file, unsigned int index, unsigned int chan)
{
	struct schedule_state * s = data;
	struct reg_value ** v = get_reg_valuep(s, file, index, chan);
	struct reg_value_reader * reader;

	if (!v)
		return;

	if (*v && (*v)->Writer == s->Current) {
		/* The instruction reads and writes to a register component.
		 * In this case, we only want to increment dependencies by one.
		 * Why?
		 * Because each instruction depends on the writers of its source
		 * registers _and_ the most recent writer of its destination
		 * register.  In this case, the current instruction (s->Current)
		 * has a dependency that both writes to one of its source
		 * registers and was the most recent writer to its destination
		 * register.  We have already marked this dependency in
		 * scan_write(), so we don't need to do it again.
		 */

		/* We need to make sure we are adding s->Current to the
		 * previous writer's list of TexReaders, if the previous writer
		 * was a TEX instruction.
		 */
		add_tex_reader(s, s->PrevWriter[chan], s->Current);

		return;
	}

	DBG("%i: read %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan);

	reader = memory_pool_malloc(&s->C->Pool, sizeof(*reader));
	reader->Reader = s->Current;
	if (!*v) {
		/* In this situation, the instruction reads from a register
		 * that hasn't been written to or read from in the current
		 * block. */
		*v = memory_pool_malloc(&s->C->Pool, sizeof(struct reg_value));
		memset(*v, 0, sizeof(struct reg_value));
		(*v)->Readers = reader;
	} else {
		reader->Next = (*v)->Readers;
		(*v)->Readers = reader;
		/* Only update the current instruction's dependencies if the
		 * register it reads from has been written to in this block. */
		if ((*v)->Writer) {
			add_tex_reader(s, (*v)->Writer, s->Current);
			s->Current->NumDependencies++;
		}
	}
	(*v)->NumReaders++;

	if (s->Current->NumReadValues >= 12) {
		rc_error(s->C, "%s: NumReadValues overflow\n", __FUNCTION__);
	} else {
		s->Current->ReadValues[s->Current->NumReadValues++] = *v;
	}
}