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