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; } }
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; } }