summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c')
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c339
1 files changed, 199 insertions, 140 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
index ddce590ee6..530afa5e08 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Corbin Simpson
+ * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com>
*
* All Rights Reserved.
*
@@ -46,31 +47,61 @@ static struct rc_src_register shadow_ambient(struct r300_fragment_program_compil
return reg;
}
-static void lower_texture_rect(struct r300_fragment_program_compiler *compiler,
- struct rc_instruction *inst)
+static void scale_texcoords(struct r300_fragment_program_compiler *compiler,
+ struct rc_instruction *inst,
+ unsigned state_constant)
{
- struct rc_instruction *inst_rect;
+ struct rc_instruction *inst_mov;
+
unsigned temp = rc_find_free_temporary(&compiler->Base);
- if (inst->U.I.TexSrcTarget == RC_TEXTURE_RECT ||
- compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords) {
- inst_rect = rc_insert_new_instruction(&compiler->Base, inst->Prev);
+ inst_mov = rc_insert_new_instruction(&compiler->Base, inst->Prev);
- inst_rect->U.I.Opcode = RC_OPCODE_MUL;
- inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_rect->U.I.DstReg.Index = temp;
- inst_rect->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- inst_rect->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
- inst_rect->U.I.SrcReg[1].Index =
- rc_constants_add_state(&compiler->Base.Program.Constants,
- RC_STATE_R300_TEXRECT_FACTOR, inst->U.I.TexSrcUnit);
+ inst_mov->U.I.Opcode = RC_OPCODE_MUL;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+ inst_mov->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
+ inst_mov->U.I.SrcReg[1].Index =
+ rc_constants_add_state(&compiler->Base.Program.Constants,
+ state_constant, inst->U.I.TexSrcUnit);
- reset_srcreg(&inst->U.I.SrcReg[0]);
- inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
- inst->U.I.SrcReg[0].Index = temp;
+ reset_srcreg(&inst->U.I.SrcReg[0]);
+ inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst->U.I.SrcReg[0].Index = temp;
+}
- inst->U.I.TexSrcTarget = RC_TEXTURE_2D;
- }
+static void projective_divide(struct r300_fragment_program_compiler *compiler,
+ struct rc_instruction *inst)
+{
+ struct rc_instruction *inst_mul, *inst_rcp;
+
+ unsigned temp = rc_find_free_temporary(&compiler->Base);
+
+ inst_rcp = rc_insert_new_instruction(&compiler->Base, inst->Prev);
+ inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
+ inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_rcp->U.I.DstReg.Index = temp;
+ inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
+ inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+ /* Because the input can be arbitrarily swizzled,
+ * read the component mapped to W. */
+ inst_rcp->U.I.SrcReg[0].Swizzle =
+ RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3));
+
+ inst_mul = rc_insert_new_instruction(&compiler->Base, inst->Prev);
+ inst_mul->U.I.Opcode = RC_OPCODE_MUL;
+ inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mul->U.I.DstReg.Index = temp;
+ inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+ inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
+ inst_mul->U.I.SrcReg[1].Index = temp;
+ inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
+
+ reset_srcreg(&inst->U.I.SrcReg[0]);
+ inst->U.I.Opcode = RC_OPCODE_TEX;
+ inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst->U.I.SrcReg[0].Index = temp;
}
/**
@@ -88,6 +119,9 @@ int radeonTransformTEX(
{
struct r300_fragment_program_compiler *compiler =
(struct r300_fragment_program_compiler*)data;
+ rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode;
+ int is_rect = inst->U.I.TexSrcTarget == RC_TEXTURE_RECT ||
+ compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords;
if (inst->U.I.Opcode != RC_OPCODE_TEX &&
inst->U.I.Opcode != RC_OPCODE_TXB &&
@@ -141,16 +175,18 @@ int radeonTransformTEX(
inst_rcp->U.I.DstReg.Index = tmp_recip_w;
inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- inst_rcp->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW;
+ inst_rcp->U.I.SrcReg[0].Swizzle =
+ RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3));
}
- /* Perspective-divide r by W (if it's TXP) and add the texture sample (see below). */
+ /* Perspective-divide Z by W (if it's TXP) and add the texture sample (see below). */
tmp_sum = rc_find_free_temporary(c);
inst_mad = rc_insert_new_instruction(c, inst_rcp ? inst_rcp : inst);
inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
inst_mad->U.I.DstReg.Index = tmp_sum;
inst_mad->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_ZZZZ;
+ inst_mad->U.I.SrcReg[0].Swizzle =
+ RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 2));
if (inst->U.I.Opcode == RC_OPCODE_TXP) {
inst_mad->U.I.Opcode = RC_OPCODE_MAD;
inst_mad->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
@@ -206,11 +242,22 @@ int radeonTransformTEX(
}
}
- /* Texture wrap modes don't work on NPOT textures or texrects.
- *
- * The game plan is simple. We have two flags, fake_npot and
- * non_normalized_coords, as well as a tex target. The RECT tex target
- * will make the emitted code use non-scaled texcoords.
+ /* R300 cannot sample from rectangles and the wrap mode fallback needs
+ * normalized coordinates anyway. */
+ if (inst->U.I.Opcode != RC_OPCODE_KIL &&
+ is_rect && (!c->is_r500 || wrapmode != RC_WRAP_NONE)) {
+ scale_texcoords(compiler, inst, RC_STATE_R300_TEXRECT_FACTOR);
+ inst->U.I.TexSrcTarget = RC_TEXTURE_2D;
+ }
+
+ /* Divide by W if needed. */
+ if (inst->U.I.Opcode == RC_OPCODE_TXP &&
+ (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT ||
+ compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch)) {
+ projective_divide(compiler, inst);
+ }
+
+ /* Texture wrap modes don't work on NPOT textures.
*
* Non-wrapped/clamped texcoords with NPOT are free in HW. Repeat and
* mirroring are not. If we need to repeat, we do:
@@ -235,128 +282,140 @@ int radeonTransformTEX(
* ~ C & M. ;)
*/
if (inst->U.I.Opcode != RC_OPCODE_KIL &&
- (inst->U.I.TexSrcTarget == RC_TEXTURE_RECT ||
- compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot ||
- compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords)) {
- rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode;
-
- /* R300 cannot sample from rectangles. */
- if (!c->is_r500) {
- lower_texture_rect(compiler, inst);
- }
-
- if (compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot &&
- wrapmode != RC_WRAP_NONE) {
+ wrapmode != RC_WRAP_NONE) {
+ struct rc_instruction *inst_mov;
+ unsigned temp = rc_find_free_temporary(c);
+
+ if (wrapmode == RC_WRAP_REPEAT) {
+ /* Both instructions will be paired up. */
+ struct rc_instruction *inst_frc = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_frc->U.I.Opcode = RC_OPCODE_FRC;
+ inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_frc->U.I.DstReg.Index = temp;
+ inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_frc->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+ } else if (wrapmode == RC_WRAP_MIRRORED_REPEAT) {
+ /*
+ * Function:
+ * f(v) = 1 - abs(frac(v * 0.5) * 2 - 1)
+ *
+ * Code:
+ * MUL temp, src0, 0.5
+ * FRC temp, temp
+ * MAD temp, temp, 2, -1
+ * ADD temp, 1, -abs(temp)
+ */
+
+ struct rc_instruction *inst_mul, *inst_frc, *inst_mad, *inst_add;
+ unsigned two, two_swizzle;
+
+ inst_mul = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_mul->U.I.Opcode = RC_OPCODE_MUL;
+ inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mul->U.I.DstReg.Index = temp;
+ inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+ inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_HHHH;
+
+ inst_frc = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_frc->U.I.Opcode = RC_OPCODE_FRC;
+ inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_frc->U.I.DstReg.Index = temp;
+ inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_frc->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst_frc->U.I.SrcReg[0].Index = temp;
+ inst_frc->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
+
+ two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2, &two_swizzle);
+ inst_mad = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_mad->U.I.Opcode = RC_OPCODE_MAD;
+ inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mad->U.I.DstReg.Index = temp;
+ inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst_mad->U.I.SrcReg[0].Index = temp;
+ inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
+ inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
+ inst_mad->U.I.SrcReg[1].Index = two;
+ inst_mad->U.I.SrcReg[1].Swizzle = two_swizzle;
+ inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_1111;
+ inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZ;
+
+ inst_add = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_add->U.I.Opcode = RC_OPCODE_ADD;
+ inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_add->U.I.DstReg.Index = temp;
+ inst_add->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
+ inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
+ inst_add->U.I.SrcReg[1].Index = temp;
+ inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
+ inst_add->U.I.SrcReg[1].Abs = 1;
+ inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZ;
+ } else if (wrapmode == RC_WRAP_MIRRORED_CLAMP) {
+ /*
+ * Mirrored clamp modes are bloody simple, we just use abs
+ * to mirror [0, 1] into [-1, 0]. This works for
+ * all modes i.e. CLAMP, CLAMP_TO_EDGE, and CLAMP_TO_BORDER.
+ */
struct rc_instruction *inst_mov;
- unsigned temp = rc_find_free_temporary(c);
-
- /* For NPOT fallback, we need normalized coordinates anyway. */
- if (c->is_r500) {
- lower_texture_rect(compiler, inst);
- }
-
- if (wrapmode == RC_WRAP_REPEAT) {
- /* Both instructions will be paired up. */
- struct rc_instruction *inst_frc = rc_insert_new_instruction(c, inst->Prev);
-
- inst_frc->U.I.Opcode = RC_OPCODE_FRC;
- inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_frc->U.I.DstReg.Index = temp;
- inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_frc->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- } else if (wrapmode == RC_WRAP_MIRRORED_REPEAT) {
- /*
- * Function:
- * f(v) = 1 - abs(frac(v * 0.5) * 2 - 1)
- *
- * Code:
- * MUL temp, src0, 0.5
- * FRC temp, temp
- * MAD temp, temp, 2, -1
- * ADD temp, 1, -abs(temp)
- */
-
- struct rc_instruction *inst_mul, *inst_frc, *inst_mad, *inst_add;
- unsigned two, two_swizzle;
-
- inst_mul = rc_insert_new_instruction(c, inst->Prev);
-
- inst_mul->U.I.Opcode = RC_OPCODE_MUL;
- inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_mul->U.I.DstReg.Index = temp;
- inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_HHHH;
-
- inst_frc = rc_insert_new_instruction(c, inst->Prev);
-
- inst_frc->U.I.Opcode = RC_OPCODE_FRC;
- inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_frc->U.I.DstReg.Index = temp;
- inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_frc->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
- inst_frc->U.I.SrcReg[0].Index = temp;
- inst_frc->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
-
- two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2, &two_swizzle);
- inst_mad = rc_insert_new_instruction(c, inst->Prev);
-
- inst_mad->U.I.Opcode = RC_OPCODE_MAD;
- inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_mad->U.I.DstReg.Index = temp;
- inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
- inst_mad->U.I.SrcReg[0].Index = temp;
- inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
- inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
- inst_mad->U.I.SrcReg[1].Index = two;
- inst_mad->U.I.SrcReg[1].Swizzle = two_swizzle;
- inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_1111;
- inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZ;
-
- inst_add = rc_insert_new_instruction(c, inst->Prev);
-
- inst_add->U.I.Opcode = RC_OPCODE_ADD;
- inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_add->U.I.DstReg.Index = temp;
- inst_add->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
- inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
- inst_add->U.I.SrcReg[1].Index = temp;
- inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
- inst_add->U.I.SrcReg[1].Abs = 1;
- inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZ;
- } else if (wrapmode == RC_WRAP_MIRRORED_CLAMP) {
- /*
- * Mirrored clamp modes are bloody simple, we just use abs
- * to mirror [0, 1] into [-1, 0]. This works for
- * all modes i.e. CLAMP, CLAMP_TO_EDGE, and CLAMP_TO_BORDER.
- */
- struct rc_instruction *inst_mov;
-
- inst_mov = rc_insert_new_instruction(c, inst->Prev);
-
- inst_mov->U.I.Opcode = RC_OPCODE_MOV;
- inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
- inst_mov->U.I.DstReg.Index = temp;
- inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
- inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
- inst_mov->U.I.SrcReg[0].Abs = 1;
- }
- /* Preserve W for TXP/TXB. */
inst_mov = rc_insert_new_instruction(c, inst->Prev);
inst_mov->U.I.Opcode = RC_OPCODE_MOV;
inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
inst_mov->U.I.DstReg.Index = temp;
- inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
-
- reset_srcreg(&inst->U.I.SrcReg[0]);
- inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
- inst->U.I.SrcReg[0].Index = temp;
+ inst_mov->U.I.SrcReg[0].Abs = 1;
}
+
+ /* Preserve W for TXP/TXB. */
+ inst_mov = rc_insert_new_instruction(c, inst->Prev);
+
+ inst_mov->U.I.Opcode = RC_OPCODE_MOV;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+
+ reset_srcreg(&inst->U.I.SrcReg[0]);
+ inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst->U.I.SrcReg[0].Index = temp;
+ }
+
+ if (inst->U.I.Opcode != RC_OPCODE_KIL &&
+ compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch) {
+ struct rc_instruction *inst_mov;
+ unsigned temp = rc_find_free_temporary(c);
+
+ /* Saturate XYZ. */
+ inst_mov = rc_insert_new_instruction(c, inst->Prev);
+ inst_mov->U.I.Opcode = RC_OPCODE_MOV;
+ inst_mov->U.I.SaturateMode = RC_SATURATE_ZERO_ONE;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+
+ /* Copy W. */
+ inst_mov = rc_insert_new_instruction(c, inst->Prev);
+ inst_mov->U.I.Opcode = RC_OPCODE_MOV;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+
+ reset_srcreg(&inst->U.I.SrcReg[0]);
+ inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst->U.I.SrcReg[0].Index = temp;
+
+ scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR);
}
/* Cannot write texture to output registers (all chips) or with masks (non-r500) */