/** * Emit a paired ALU instruction. */ static GLboolean emit_paired(void *data, struct radeon_pair_instruction *inst) { PROG_CODE; if (code->inst_end >= 511) { error("emit_alu: Too many instructions"); return GL_FALSE; } int ip = ++code->inst_end; code->inst[ip].inst5 = translate_rgb_op(inst->RGB.Opcode); code->inst[ip].inst4 = translate_alpha_op(inst->Alpha.Opcode); if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) code->inst[ip].inst0 = R500_INST_TYPE_OUT; else code->inst[ip].inst0 = R500_INST_TYPE_ALU; code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT; code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11) | (inst->Alpha.WriteMask << 14); code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18); if (inst->Alpha.DepthWriteMask) { code->inst[ip].inst4 |= R500_ALPHA_W_OMASK; c->fp->writes_depth = GL_TRUE; } code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex); code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex); use_temporary(code, inst->Alpha.DestIndex); use_temporary(code, inst->RGB.DestIndex); if (inst->RGB.Saturate) code->inst[ip].inst0 |= R500_INST_RGB_CLAMP; if (inst->Alpha.Saturate) code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP; code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0])); code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1])); code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2])); code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0])); code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1])); code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2])); code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT; code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT; return GL_TRUE; }
/** * Emit a paired ALU instruction. */ static void emit_paired(struct r300_fragment_program_compiler *c, struct rc_pair_instruction *inst) { int ip; PROG_CODE; if (code->inst_end >= c->Base.max_alu_insts-1) { error("emit_alu: Too many instructions"); return; } ip = ++code->inst_end; /* Quirk: MDH/MDV (DDX/DDY) need a NOP on previous non-TEX instructions. */ if (inst->RGB.Opcode == RC_OPCODE_DDX || inst->Alpha.Opcode == RC_OPCODE_DDX || inst->RGB.Opcode == RC_OPCODE_DDY || inst->Alpha.Opcode == RC_OPCODE_DDY) { if (ip > 0) { alu_nop(c, ip - 1); } } code->inst[ip].inst5 = translate_rgb_op(c, inst->RGB.Opcode); code->inst[ip].inst4 = translate_alpha_op(c, inst->Alpha.Opcode); if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) { code->inst[ip].inst0 = R500_INST_TYPE_OUT; if (inst->WriteALUResult) { error("Cannot write output and ALU result at the same time"); return; } } else { code->inst[ip].inst0 = R500_INST_TYPE_ALU; } code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT; code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11); code->inst[ip].inst0 |= inst->Alpha.WriteMask ? 1 << 14 : 0; code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18); if (inst->Nop) { code->inst[ip].inst0 |= R500_INST_NOP; } if (inst->Alpha.DepthWriteMask) { code->inst[ip].inst4 |= R500_ALPHA_W_OMASK; c->code->writes_depth = 1; } code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex); code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex); use_temporary(code, inst->Alpha.DestIndex); use_temporary(code, inst->RGB.DestIndex); if (inst->RGB.Saturate) code->inst[ip].inst0 |= R500_INST_RGB_CLAMP; if (inst->Alpha.Saturate) code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP; /* Set the presubtract operation. */ switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_2RGB0; break; case RC_PRESUB_SUB: code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_MINUS_RGB0; break; case RC_PRESUB_ADD: code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_PLUS_RGB0; break; case RC_PRESUB_INV: code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_RGB0; break; default: break; } switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_2A0; break; case RC_PRESUB_SUB: code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_MINUS_A0; break; case RC_PRESUB_ADD: code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_PLUS_A0; break; case RC_PRESUB_INV: code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_A0; break; default: break; } code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0])); code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1])); code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2])); code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0])); code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1])); code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2])); code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT; code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT; code->inst[ip].inst3 |= R500_ALU_RGB_TARGET(inst->RGB.Target); code->inst[ip].inst4 |= R500_ALPHA_TARGET(inst->Alpha.Target); if (inst->WriteALUResult) { code->inst[ip].inst3 |= R500_ALU_RGB_WMASK; if (inst->WriteALUResult == RC_ALURESULT_X) code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_RED; else code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_ALPHA; code->inst[ip].inst0 |= translate_alu_result_op(c, inst->ALUResultCompare); } }
/** * Emit one paired ALU instruction. */ static int emit_alu(struct r300_emit_state * emit, struct rc_pair_instruction* inst) { int ip; int j; PROG_CODE; if (code->alu.length >= c->Base.max_alu_insts) { error("Too many ALU instructions"); return 0; } ip = code->alu.length++; code->alu.inst[ip].rgb_inst = translate_rgb_opcode(c, inst->RGB.Opcode); code->alu.inst[ip].alpha_inst = translate_alpha_opcode(c, inst->Alpha.Opcode); for(j = 0; j < 3; ++j) { /* Set the RGB address */ unsigned int src = use_source(code, inst->RGB.Src[j]); unsigned int arg; if (inst->RGB.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_RGB_MSB_BIT(j); code->alu.inst[ip].rgb_addr |= src << (6*j); /* Set the Alpha address */ src = use_source(code, inst->Alpha.Src[j]); if (inst->Alpha.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_A_MSB_BIT(j); code->alu.inst[ip].alpha_addr |= src << (6*j); arg = r300FPTranslateRGBSwizzle(inst->RGB.Arg[j].Source, inst->RGB.Arg[j].Swizzle); arg |= inst->RGB.Arg[j].Abs << 6; arg |= inst->RGB.Arg[j].Negate << 5; code->alu.inst[ip].rgb_inst |= arg << (7*j); arg = r300FPTranslateAlphaSwizzle(inst->Alpha.Arg[j].Source, inst->Alpha.Arg[j].Swizzle); arg |= inst->Alpha.Arg[j].Abs << 6; arg |= inst->Alpha.Arg[j].Negate << 5; code->alu.inst[ip].alpha_inst |= arg << (7*j); } /* Presubtract */ if (inst->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_1_MINUS_2_SRC0; break; case RC_PRESUB_ADD: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_SRC1_PLUS_SRC0; break; case RC_PRESUB_SUB: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_SRC1_MINUS_SRC0; break; case RC_PRESUB_INV: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_1_MINUS_SRC0; break; default: break; } } if (inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_1_MINUS_2_SRC0; break; case RC_PRESUB_ADD: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_SRC1_PLUS_SRC0; break; case RC_PRESUB_SUB: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_SRC1_MINUS_SRC0; break; case RC_PRESUB_INV: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_1_MINUS_SRC0; break; default: break; } } if (inst->RGB.Saturate) code->alu.inst[ip].rgb_inst |= R300_ALU_OUTC_CLAMP; if (inst->Alpha.Saturate) code->alu.inst[ip].alpha_inst |= R300_ALU_OUTA_CLAMP; if (inst->RGB.WriteMask) { use_temporary(code, inst->RGB.DestIndex); if (inst->RGB.DestIndex >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_RGB_MSB_BIT; code->alu.inst[ip].rgb_addr |= ((inst->RGB.DestIndex & 0x1f) << R300_ALU_DSTC_SHIFT) | (inst->RGB.WriteMask << R300_ALU_DSTC_REG_MASK_SHIFT); } if (inst->RGB.OutputWriteMask) { code->alu.inst[ip].rgb_addr |= (inst->RGB.OutputWriteMask << R300_ALU_DSTC_OUTPUT_MASK_SHIFT) | R300_RGB_TARGET(inst->RGB.Target); emit->node_flags |= R300_RGBA_OUT; } if (inst->Alpha.WriteMask) { use_temporary(code, inst->Alpha.DestIndex); if (inst->Alpha.DestIndex >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_A_MSB_BIT; code->alu.inst[ip].alpha_addr |= ((inst->Alpha.DestIndex & 0x1f) << R300_ALU_DSTA_SHIFT) | R300_ALU_DSTA_REG; } if (inst->Alpha.OutputWriteMask) { code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_OUTPUT | R300_ALPHA_TARGET(inst->Alpha.Target); emit->node_flags |= R300_RGBA_OUT; } if (inst->Alpha.DepthWriteMask) { code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_DEPTH; emit->node_flags |= R300_W_OUT; c->code->writes_depth = 1; } if (inst->Nop) code->alu.inst[ip].rgb_inst |= R300_ALU_INSERT_NOP; /* Handle Output Modifier * According to the r300 docs, there is no RC_OMOD_DISABLE for r300 */ if (inst->RGB.Omod) { if (inst->RGB.Omod == RC_OMOD_DISABLE) { rc_error(&c->Base, "RC_OMOD_DISABLE not supported"); } code->alu.inst[ip].rgb_inst |= (inst->RGB.Omod << R300_ALU_OUTC_MOD_SHIFT); } if (inst->Alpha.Omod) { if (inst->Alpha.Omod == RC_OMOD_DISABLE) { rc_error(&c->Base, "RC_OMOD_DISABLE not supported"); } code->alu.inst[ip].alpha_inst |= (inst->Alpha.Omod << R300_ALU_OUTC_MOD_SHIFT); } return 1; }
/** * Emit a paired ALU instruction. */ static void emit_paired(struct r300_fragment_program_compiler *c, struct rc_pair_instruction *inst) { PROG_CODE; if (code->inst_end >= 511) { error("emit_alu: Too many instructions"); return; } int ip = ++code->inst_end; code->inst[ip].inst5 = translate_rgb_op(c, inst->RGB.Opcode); code->inst[ip].inst4 = translate_alpha_op(c, inst->Alpha.Opcode); if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) { code->inst[ip].inst0 = R500_INST_TYPE_OUT; if (inst->WriteALUResult) { error("%s: cannot write output and ALU result at the same time"); return; } } else { code->inst[ip].inst0 = R500_INST_TYPE_ALU; } code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT; code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11) | (inst->Alpha.WriteMask << 14); code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18); if (inst->Alpha.DepthWriteMask) { code->inst[ip].inst4 |= R500_ALPHA_W_OMASK; c->code->writes_depth = 1; } code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex); code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex); use_temporary(code, inst->Alpha.DestIndex); use_temporary(code, inst->RGB.DestIndex); if (inst->RGB.Saturate) code->inst[ip].inst0 |= R500_INST_RGB_CLAMP; if (inst->Alpha.Saturate) code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP; code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0])); code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1])); code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2])); code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0])); code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1])); code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2])); code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT; code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT; code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT; code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT; code->inst[ip].inst3 |= R500_ALU_RGB_TARGET(inst->RGB.Target); code->inst[ip].inst4 |= R500_ALPHA_TARGET(inst->Alpha.Target); if (inst->WriteALUResult) { code->inst[ip].inst3 |= R500_ALU_RGB_WMASK; if (inst->WriteALUResult == RC_ALURESULT_X) code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_RED; else code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_ALPHA; code->inst[ip].inst0 |= translate_alu_result_op(c, inst->ALUResultCompare); } }