struct tgsi_src_register* src)
{
switch (src->File) {
+ case TGSI_FILE_NULL:
+ return 0;
case TGSI_FILE_INPUT:
/* XXX may be wrong */
return src->Index;
return src->Index + assembler->temp_offset;
break;
case TGSI_FILE_IMMEDIATE:
- return src->Index + assembler->imm_offset | (1 << 8);
+ return (src->Index + assembler->imm_offset) | (1 << 8);
break;
case TGSI_FILE_CONSTANT:
/* XXX magic */
struct tgsi_dst_register* dst)
{
switch (dst->File) {
+ case TGSI_FILE_NULL:
+ /* This happens during KIL instructions. */
+ return 0;
+ break;
case TGSI_FILE_OUTPUT:
return 0;
break;
static INLINE uint32_t r500_rgb_swiz(struct tgsi_full_src_register* reg)
{
/* Only the first 9 bits... */
- return r500_rgba_swiz(reg) & 0x1ff;
+ return (r500_rgba_swiz(reg) & 0x1ff) |
+ (reg->SrcRegister.Negate ? (1 << 9) : 0) |
+ (reg->SrcRegisterExtMod.Absolute ? (1 << 10) : 0);
}
static INLINE uint32_t r500_alpha_swiz(struct tgsi_full_src_register* reg)
{
/* Only the last 3 bits... */
- return r500_rgba_swiz(reg) >> 9;
+ return (r500_rgba_swiz(reg) >> 9) |
+ (reg->SrcRegister.Negate ? (1 << 9) : 0) |
+ (reg->SrcRegisterExtMod.Absolute ? (1 << 10) : 0);
+}
+
+static INLINE uint32_t r300_rgb_op(unsigned op)
+{
+ switch (op) {
+ case TGSI_OPCODE_MOV:
+ return R300_ALU_OUTC_CMP;
+ default:
+ return 0;
+ }
}
-static INLINE uint32_t r500_sop_swiz(struct tgsi_full_src_register* reg)
+static INLINE uint32_t r300_alpha_op(unsigned op)
{
- /* Only the first 3 bits... */
- return r500_rgba_swiz(reg) & 0x7;
+ switch (op) {
+ case TGSI_OPCODE_MOV:
+ return R300_ALU_OUTA_CMP;
+ default:
+ return 0;
+ }
}
static INLINE uint32_t r500_rgba_op(unsigned op)
case TGSI_OPCODE_RCP:
case TGSI_OPCODE_RSQ:
return R500_ALU_RGBA_OP_SOP;
+ case TGSI_OPCODE_FRC:
+ return R500_ALU_RGBA_OP_FRC;
case TGSI_OPCODE_DP3:
return R500_ALU_RGBA_OP_DP3;
case TGSI_OPCODE_DP4:
case TGSI_OPCODE_DPH:
return R500_ALU_RGBA_OP_DP4;
+ case TGSI_OPCODE_ABS:
+ case TGSI_OPCODE_CMP:
+ case TGSI_OPCODE_MOV:
+ case TGSI_OPCODE_SWZ:
+ return R500_ALU_RGBA_OP_CMP;
+ case TGSI_OPCODE_ADD:
case TGSI_OPCODE_MAD:
+ case TGSI_OPCODE_MUL:
+ case TGSI_OPCODE_SUB:
return R500_ALU_RGBA_OP_MAD;
default:
return 0;
return R500_ALPHA_OP_RCP;
case TGSI_OPCODE_RSQ:
return R500_ALPHA_OP_RSQ;
+ case TGSI_OPCODE_FRC:
+ return R500_ALPHA_OP_FRC;
case TGSI_OPCODE_DP3:
case TGSI_OPCODE_DP4:
case TGSI_OPCODE_DPH:
return R500_ALPHA_OP_DP;
+ case TGSI_OPCODE_ABS:
+ case TGSI_OPCODE_CMP:
+ case TGSI_OPCODE_MOV:
+ case TGSI_OPCODE_SWZ:
+ return R500_ALPHA_OP_CMP;
+ case TGSI_OPCODE_ADD:
case TGSI_OPCODE_MAD:
+ case TGSI_OPCODE_MUL:
+ case TGSI_OPCODE_SUB:
return R500_ALPHA_OP_MAD;
default:
return 0;
}
}
+static INLINE uint32_t r500_tex_op(unsigned op)
+{
+ switch (op) {
+ case TGSI_OPCODE_KIL:
+ return R500_TEX_INST_TEXKILL;
+ case TGSI_OPCODE_TEX:
+ return R500_TEX_INST_LD;
+ case TGSI_OPCODE_TXB:
+ return R500_TEX_INST_LODBIAS;
+ case TGSI_OPCODE_TXP:
+ return R500_TEX_INST_PROJ;
+ default:
+ return 0;
+ }
+}
+
+static INLINE void r300_emit_maths(struct r300_fragment_shader* fs,
+ struct r300_fs_asm* assembler,
+ struct tgsi_full_src_register* src,
+ struct tgsi_full_dst_register* dst,
+ unsigned op,
+ unsigned count)
+{
+ int i = fs->alu_instruction_count;
+
+ fs->instructions[i].alu_rgb_inst = R300_RGB_SWIZA(R300_ALU_ARGC_SRC0C_XYZ) |
+ R300_RGB_SWIZB(R300_ALU_ARGC_SRC0C_XYZ) |
+ R300_RGB_SWIZC(R300_ALU_ARGC_ZERO) |
+ r300_rgb_op(op);
+ fs->instructions[i].alu_rgb_addr = R300_RGB_ADDR0(0) | R300_RGB_ADDR1(0) |
+ R300_RGB_ADDR2(0) | R300_ALU_DSTC_OUTPUT_XYZ;
+ fs->instructions[i].alu_alpha_inst = R300_ALPHA_SWIZA(R300_ALU_ARGA_SRC0A) |
+ R300_ALPHA_SWIZB(R300_ALU_ARGA_SRC0A) |
+ R300_ALPHA_SWIZC(R300_ALU_ARGA_ZERO) |
+ r300_alpha_op(op);
+ fs->instructions[i].alu_alpha_addr = R300_ALPHA_ADDR0(0) |
+ R300_ALPHA_ADDR1(0) | R300_ALPHA_ADDR2(0) | R300_ALU_DSTA_OUTPUT;
+
+ fs->alu_instruction_count++;
+}
+
/* Setup an ALU operation. */
static INLINE void r500_emit_alu(struct r500_fragment_shader* fs,
struct r300_fs_asm* assembler,
R500_ALU_WMASK(dst->DstRegister.WriteMask);
}
- fs->instructions[i].inst0 |=
- R500_INST_TEX_SEM_WAIT |
- R500_INST_RGB_CLAMP | R500_INST_ALPHA_CLAMP;
+ fs->instructions[i].inst0 |= R500_INST_TEX_SEM_WAIT;
+
+ fs->instructions[i].inst4 =
+ R500_ALPHA_ADDRD(r300_fs_dst(assembler, &dst->DstRegister));
+ fs->instructions[i].inst5 =
+ R500_ALU_RGBA_ADDRD(r300_fs_dst(assembler, &dst->DstRegister));
}
static INLINE void r500_emit_maths(struct r500_fragment_shader* fs,
struct tgsi_full_src_register* src,
struct tgsi_full_dst_register* dst,
unsigned op,
- unsigned count,
- boolean is_sop)
+ unsigned count)
{
int i = fs->instruction_count;
R500_RGB_ADDR2(r300_fs_src(assembler, &src[2].SrcRegister));
fs->instructions[i].inst2 =
R500_ALPHA_ADDR2(r300_fs_src(assembler, &src[2].SrcRegister));
- fs->instructions[i].inst5 =
- R500_ALU_RGBA_ALPHA_SEL_C_SRC2 |
+ fs->instructions[i].inst5 |=
+ R500_ALU_RGBA_SEL_C_SRC2 |
R500_SWIZ_RGBA_C(r500_rgb_swiz(&src[2])) |
+ R500_ALU_RGBA_ALPHA_SEL_C_SRC2 |
R500_SWIZ_ALPHA_C(r500_alpha_swiz(&src[2]));
case 2:
fs->instructions[i].inst1 |=
fs->instructions[i].inst3 =
R500_ALU_RGB_SEL_B_SRC1 |
R500_SWIZ_RGB_B(r500_rgb_swiz(&src[1]));
- fs->instructions[i].inst4 =
+ fs->instructions[i].inst4 |=
R500_SWIZ_ALPHA_B(r500_alpha_swiz(&src[1])) |
R500_ALPHA_SEL_B_SRC1;
case 1:
R500_ALU_RGB_SEL_A_SRC0 |
R500_SWIZ_RGB_A(r500_rgb_swiz(&src[0]));
fs->instructions[i].inst4 |=
- R500_SWIZ_ALPHA_A(is_sop ? r500_sop_swiz(&src[0]) :
- r500_alpha_swiz(&src[0])) |
+ R500_SWIZ_ALPHA_A(r500_alpha_swiz(&src[0])) |
R500_ALPHA_SEL_A_SRC0;
break;
}
fs->instruction_count++;
}
-static INLINE void r500_emit_mov(struct r500_fragment_shader* fs,
- struct r300_fs_asm* assembler,
- struct tgsi_full_src_register* src,
- struct tgsi_full_dst_register* dst)
-{
- int i = fs->instruction_count;
-
- r500_emit_alu(fs, assembler, dst);
-
- fs->instructions[i].inst1 =
- R500_RGB_ADDR0(r300_fs_src(assembler, &src->SrcRegister));
- fs->instructions[i].inst2 =
- R500_ALPHA_ADDR0(r300_fs_src(assembler, &src->SrcRegister));
- fs->instructions[i].inst3 = R500_ALU_RGB_SEL_A_SRC0 |
- R500_SWIZ_RGB_A(r500_rgb_swiz(src)) |
- R500_ALU_RGB_SEL_B_SRC0 |
- R500_SWIZ_RGB_B(r500_rgb_swiz(src));
- fs->instructions[i].inst4 = R500_ALPHA_OP_CMP |
- R500_SWIZ_ALPHA_A(r500_alpha_swiz(src)) |
- R500_SWIZ_ALPHA_B(r500_alpha_swiz(src));
- fs->instructions[i].inst5 =
- R500_ALU_RGBA_OP_CMP | R500_ALU_RGBA_R_SWIZ_0 |
- R500_ALU_RGBA_G_SWIZ_0 | R500_ALU_RGBA_B_SWIZ_0 |
- R500_ALU_RGBA_A_SWIZ_0;
-
- fs->instruction_count++;
-}
-
static INLINE void r500_emit_tex(struct r500_fragment_shader* fs,
struct r300_fs_asm* assembler,
- uint32_t op,
struct tgsi_full_src_register* src,
- struct tgsi_full_dst_register* dst)
+ struct tgsi_full_dst_register* dst,
+ uint32_t op)
{
int i = fs->instruction_count;
R500_TEX_WMASK(dst->DstRegister.WriteMask) |
R500_INST_TEX_SEM_WAIT;
fs->instructions[i].inst1 = R500_TEX_ID(0) |
- R500_TEX_SEM_ACQUIRE | R500_TEX_IGNORE_UNCOVERED |
- R500_TEX_INST_PROJ;
+ R500_TEX_SEM_ACQUIRE | //R500_TEX_IGNORE_UNCOVERED |
+ r500_tex_op(op);
fs->instructions[i].inst2 =
R500_TEX_SRC_ADDR(r300_fs_src(assembler, &src->SrcRegister)) |
R500_SWIZ_TEX_STRQ(r500_strq_swiz(src)) |
R500_TEX_DST_R_SWIZ_R | R500_TEX_DST_G_SWIZ_G |
R500_TEX_DST_B_SWIZ_B | R500_TEX_DST_A_SWIZ_A;
- fs->instruction_count++;
+ if (dst->DstRegister.File == TGSI_FILE_OUTPUT) {
+ fs->instructions[i].inst2 |=
+ R500_TEX_DST_ADDR(assembler->temp_count +
+ assembler->temp_offset);
+
+ fs->instruction_count++;
+
+ /* Setup and emit a MOV. */
+ src[0].SrcRegister.Index = assembler->temp_count;
+ src[0].SrcRegister.File = TGSI_FILE_TEMPORARY;
+
+ src[1] = src[0];
+ src[2] = r500_constant_zero;
+ r500_emit_maths(fs, assembler, src, dst, TGSI_OPCODE_MOV, 3);
+ } else {
+ fs->instruction_count++;
+ }
+}
+
+static void r300_fs_instruction(struct r300_fragment_shader* fs,
+ struct r300_fs_asm* assembler,
+ struct tgsi_full_instruction* inst)
+{
+ switch (inst->Instruction.Opcode) {
+ case TGSI_OPCODE_MOV:
+ /* src0 -> src1 and src2 forced to zero */
+ inst->FullSrcRegisters[1] = inst->FullSrcRegisters[0];
+ inst->FullSrcRegisters[2] = r500_constant_zero;
+ r300_emit_maths(fs, assembler, inst->FullSrcRegisters,
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
+ break;
+ case TGSI_OPCODE_END:
+ break;
+ default:
+ debug_printf("r300: fs: Bad opcode %d\n",
+ inst->Instruction.Opcode);
+ break;
+ }
}
static void r500_fs_instruction(struct r500_fragment_shader* fs,
struct r300_fs_asm* assembler,
struct tgsi_full_instruction* inst)
{
- int i;
/* Switch between opcodes. When possible, prefer using the official
* AMD/ATI names for opcodes, please, as it facilitates using the
* documentation. */
switch (inst->Instruction.Opcode) {
+ /* The simple scalar ops. */
case TGSI_OPCODE_EX2:
+ case TGSI_OPCODE_LG2:
+ case TGSI_OPCODE_RCP:
+ case TGSI_OPCODE_RSQ:
+ /* Copy red swizzle to alpha for src0 */
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleW =
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleX;
+ inst->FullSrcRegisters[0].SrcRegister.SwizzleW =
+ inst->FullSrcRegisters[0].SrcRegister.SwizzleX;
+ /* Fall through */
+ case TGSI_OPCODE_FRC:
r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
- &inst->FullDstRegisters[0], inst->Instruction.Opcode, 1,
- true);
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 1);
break;
+
+ /* The dot products. */
+ case TGSI_OPCODE_DPH:
+ /* Set alpha swizzle to one for src0 */
+ if (!inst->FullSrcRegisters[0].SrcRegister.Extended) {
+ inst->FullSrcRegisters[0].SrcRegister.Extended = TRUE;
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleX =
+ inst->FullSrcRegisters[0].SrcRegister.SwizzleX;
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleY =
+ inst->FullSrcRegisters[0].SrcRegister.SwizzleY;
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleZ =
+ inst->FullSrcRegisters[0].SrcRegister.SwizzleZ;
+ }
+ inst->FullSrcRegisters[0].SrcRegisterExtSwz.ExtSwizzleW =
+ TGSI_EXTSWIZZLE_ONE;
+ /* Fall through */
case TGSI_OPCODE_DP3:
case TGSI_OPCODE_DP4:
r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
- &inst->FullDstRegisters[0], inst->Instruction.Opcode, 2,
- false);
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 2);
break;
- case TGSI_OPCODE_DPH:
+
+ /* Simple three-source operations. */
+ case TGSI_OPCODE_CMP:
+ /* Swap src0 and src2 */
+ inst->FullSrcRegisters[3] = inst->FullSrcRegisters[2];
+ inst->FullSrcRegisters[2] = inst->FullSrcRegisters[0];
+ inst->FullSrcRegisters[0] = inst->FullSrcRegisters[3];
+ r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
+ break;
+
+ /* The MAD variants. */
+ case TGSI_OPCODE_SUB:
+ /* Just like ADD, but flip the negation on src1 first */
+ inst->FullSrcRegisters[1].SrcRegister.Negate =
+ !inst->FullSrcRegisters[1].SrcRegister.Negate;
+ /* Fall through */
+ case TGSI_OPCODE_ADD:
+ /* Force src0 to one, move all registers over */
+ inst->FullSrcRegisters[2] = inst->FullSrcRegisters[1];
+ inst->FullSrcRegisters[1] = inst->FullSrcRegisters[0];
+ inst->FullSrcRegisters[0] = r500_constant_one;
r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
- &inst->FullDstRegisters[0], inst->Instruction.Opcode, 2,
- false);
- /* Force alpha swizzle to one */
- i = fs->instruction_count - 1;
- fs->instructions[i].inst4 &= ~R500_SWIZ_ALPHA_A(0x7);
- fs->instructions[i].inst4 |= R500_SWIZ_ALPHA_A(R500_SWIZZLE_ONE);
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
break;
case TGSI_OPCODE_MUL:
/* Force our src2 to zero */
inst->FullSrcRegisters[2] = r500_constant_zero;
r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
- &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3,
- false);
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
break;
case TGSI_OPCODE_MAD:
r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
- &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3,
- false);
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
break;
+
+ /* The MOV variants. */
+ case TGSI_OPCODE_ABS:
+ /* Set absolute value modifiers. */
+ inst->FullSrcRegisters[0].SrcRegisterExtMod.Absolute = TRUE;
+ /* Fall through */
case TGSI_OPCODE_MOV:
case TGSI_OPCODE_SWZ:
- r500_emit_mov(fs, assembler, &inst->FullSrcRegisters[0],
- &inst->FullDstRegisters[0]);
+ /* src0 -> src1 and src2 forced to zero */
+ inst->FullSrcRegisters[1] = inst->FullSrcRegisters[0];
+ inst->FullSrcRegisters[2] = r500_constant_zero;
+ r500_emit_maths(fs, assembler, inst->FullSrcRegisters,
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode, 3);
break;
+
+ /* The texture instruction set. */
+ case TGSI_OPCODE_KIL:
+ case TGSI_OPCODE_TEX:
+ case TGSI_OPCODE_TXB:
case TGSI_OPCODE_TXP:
- r500_emit_tex(fs, assembler, 0, &inst->FullSrcRegisters[0],
- &inst->FullDstRegisters[0]);
+ r500_emit_tex(fs, assembler, &inst->FullSrcRegisters[0],
+ &inst->FullDstRegisters[0], inst->Instruction.Opcode);
break;
+
+ /* This is the end. My only friend, the end. */
case TGSI_OPCODE_END:
break;
default:
inst->Instruction.Opcode);
break;
}
+
+ /* Clamp, if saturation flags are set. */
+ if (inst->Instruction.Saturate == TGSI_SAT_ZERO_ONE) {
+ fs->instructions[fs->instruction_count - 1].inst0 |=
+ R500_INST_RGB_CLAMP | R500_INST_ALPHA_CLAMP;
+ }
}
-static void r500_fs_finalize(struct r500_fragment_shader* fs,
+static void r300_fs_finalize(struct r3xx_fragment_shader* fs,
struct r300_fs_asm* assembler)
{
- /* XXX subtly wrong */
- fs->shader.stack_size = assembler->temp_offset;
+ fs->stack_size = assembler->temp_count + assembler->temp_offset;
+}
+static void r500_fs_finalize(struct r500_fragment_shader* fs,
+ struct r300_fs_asm* assembler)
+{
/* XXX should this just go with OPCODE_END? */
fs->instructions[fs->instruction_count - 1].inst0 |=
R500_INST_LAST;
}
void r300_translate_fragment_shader(struct r300_context* r300,
- struct r300_fragment_shader* fs)
-{
- struct tgsi_parse_context parser;
-
- tgsi_parse_init(&parser, fs->shader.state.tokens);
-
- while (!tgsi_parse_end_of_tokens(&parser)) {
- tgsi_parse_token(&parser);
- }
-
- r300_copy_passthrough_shader(fs);
-}
-
-void r500_translate_fragment_shader(struct r300_context* r300,
- struct r500_fragment_shader* fs)
+ struct r3xx_fragment_shader* fs)
{
struct tgsi_parse_context parser;
int i;
+ boolean is_r500 = r300_screen(r300->context.screen)->caps->is_r500;
struct r300_constant_buffer* consts =
&r300->shader_constants[PIPE_SHADER_FRAGMENT];
/* Setup starting offset for immediates. */
assembler->imm_offset = consts->user_count;
- tgsi_parse_init(&parser, fs->shader.state.tokens);
+ /* Make sure we start at the beginning of the shader. */
+ if (is_r500) {
+ ((struct r500_fragment_shader*)fs)->instruction_count = 0;
+ }
+
+ tgsi_parse_init(&parser, fs->state.tokens);
while (!tgsi_parse_end_of_tokens(&parser)) {
tgsi_parse_token(&parser);
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
debug_printf("r300: Emitting immediate to constant buffer, "
- "position %d\n", consts->user_count);
+ "position %d\n",
+ assembler->imm_offset + assembler->imm_count);
/* I am not amused by the length of these. */
for (i = 0; i < 4; i++) {
- consts->constants[assembler->imm_offset][i] =
+ consts->constants[assembler->imm_offset +
+ assembler->imm_count][i] =
parser.FullToken.FullImmediate.u.ImmediateFloat32[i]
.Float;
}
assembler->imm_count++;
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
- r500_fs_instruction(fs, assembler,
- &parser.FullToken.FullInstruction);
+ if (is_r500) {
+ r500_fs_instruction((struct r500_fragment_shader*)fs,
+ assembler, &parser.FullToken.FullInstruction);
+ } else {
+ r300_fs_instruction((struct r300_fragment_shader*)fs,
+ assembler, &parser.FullToken.FullInstruction);
+ }
break;
}
-
}
- debug_printf("r300: %d texs and %d colors, first free reg is %d\n",
+ debug_printf("r300: fs: %d texs and %d colors, first free reg is %d\n",
assembler->tex_count, assembler->color_count,
assembler->tex_count + assembler->color_count);
consts->count = consts->user_count + assembler->imm_count;
- debug_printf("r300: %d total constants, "
+ debug_printf("r300: fs: %d total constants, "
"%d from user and %d from immediates\n", consts->count,
consts->user_count, assembler->imm_count);
- r500_fs_finalize(fs, assembler);
-
- tgsi_dump(fs->shader.state.tokens);
- r500_fs_dump(fs);
+ r300_fs_finalize(fs, assembler);
+ if (is_r500) {
+ r500_fs_finalize((struct r500_fragment_shader*)fs, assembler);
+ }
- //r500_copy_passthrough_shader(fs);
+ tgsi_dump(fs->state.tokens);
+ /* XXX finish r300 dumper too */
+ if (is_r500) {
+ r500_fs_dump((struct r500_fragment_shader*)fs);
+ }
tgsi_parse_free(&parser);
FREE(assembler);