Mesa (master): r300g: fix RG/LATC1_SNORM by doing UNORM-> SNORM conversion in the shader

Marek Olšák mareko at kemper.freedesktop.org
Mon Apr 4 21:38:28 PDT 2011


Module: Mesa
Branch: master
Commit: b3011ea60cc36a888da031ebac932d67473f4521
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b3011ea60cc36a888da031ebac932d67473f4521

Author: Marek Olšák <maraeo at gmail.com>
Date:   Tue Apr  5 06:21:26 2011 +0200

r300g: fix RG/LATC1_SNORM by doing UNORM->SNORM conversion in the shader

---

 src/gallium/drivers/r300/r300_fs.c                 |   37 +++++++++-----
 src/gallium/drivers/r300/r300_state_derived.c      |    7 ++-
 src/gallium/drivers/r300/r300_texture.c            |   45 +++++++++++------
 src/gallium/drivers/r300/r300_texture.h            |    4 ++
 src/mesa/drivers/dri/r300/compiler/radeon_code.h   |   12 +++-
 .../drivers/dri/r300/compiler/radeon_program_tex.c |   54 ++++++++++++++++++-
 6 files changed, 123 insertions(+), 36 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c
index 37fe662..e3a1bc4 100644
--- a/src/gallium/drivers/r300/r300_fs.c
+++ b/src/gallium/drivers/r300/r300_fs.c
@@ -22,6 +22,7 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
 
+#include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
@@ -34,6 +35,7 @@
 #include "r300_screen.h"
 #include "r300_fs.h"
 #include "r300_reg.h"
+#include "r300_texture.h"
 #include "r300_tgsi_to_rc.h"
 
 #include "radeon_code.h"
@@ -148,7 +150,6 @@ static void get_external_state(
     struct r300_textures_state *texstate = r300->textures_state.state;
     struct r300_rs_state *rs = r300->rs_state.state;
     unsigned i;
-    unsigned char *swizzle;
 
     state->frag_clamp = rs ? rs->rs.clamp_fragment_color : 0;
 
@@ -161,27 +162,37 @@ static void get_external_state(
             continue;
         }
 
-        t = r300_resource(texstate->sampler_views[i]->base.texture);
+        t = r300_resource(v->base.texture);
 
         if (s->state.compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
             state->unit[i].compare_mode_enabled = 1;
 
-            /* Pass depth texture swizzling to the compiler. */
-            if (texstate->sampler_views[i]) {
-                swizzle = texstate->sampler_views[i]->swizzle;
-
-                state->unit[i].depth_texture_swizzle =
-                    RC_MAKE_SWIZZLE(swizzle[0], swizzle[1],
-                                    swizzle[2], swizzle[3]);
-            } else {
-                state->unit[i].depth_texture_swizzle = RC_SWIZZLE_XYZW;
-            }
-
             /* Fortunately, no need to translate this. */
             state->unit[i].texture_compare_func = s->state.compare_func;
         }
 
         state->unit[i].non_normalized_coords = !s->state.normalized_coords;
+        state->unit[i].convert_unorm_to_snorm =
+                v->base.format == PIPE_FORMAT_RGTC1_SNORM ||
+                v->base.format == PIPE_FORMAT_LATC1_SNORM;
+
+        /* Pass texture swizzling to the compiler, some lowering passes need it. */
+        if (v->base.format == PIPE_FORMAT_RGTC1_SNORM ||
+            v->base.format == PIPE_FORMAT_LATC1_SNORM) {
+            unsigned char swizzle[4];
+
+            util_format_combine_swizzles(swizzle,
+                            util_format_description(v->base.format)->swizzle,
+                            v->swizzle);
+
+            state->unit[i].texture_swizzle =
+                    RC_MAKE_SWIZZLE(swizzle[0], swizzle[1],
+                                    swizzle[2], swizzle[3]);
+        } else if (state->unit[i].compare_mode_enabled) {
+            state->unit[i].texture_swizzle =
+                RC_MAKE_SWIZZLE(v->swizzle[0], v->swizzle[1],
+                                v->swizzle[2], v->swizzle[3]);
+        }
 
         /* XXX this should probably take into account STR, not just S. */
         if (t->tex.is_npot) {
diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c
index 50cde55..02fc121 100644
--- a/src/gallium/drivers/r300/r300_state_derived.c
+++ b/src/gallium/drivers/r300/r300_state_derived.c
@@ -650,8 +650,13 @@ static uint32_t r300_get_border_color(enum pipe_format format,
     if (util_format_is_compressed(format)) {
         switch (format) {
         case PIPE_FORMAT_RGTC1_SNORM:
-        case PIPE_FORMAT_RGTC1_UNORM:
         case PIPE_FORMAT_LATC1_SNORM:
+            border_swizzled[0] = border_swizzled[0] < 0 ?
+                                 border_swizzled[0]*0.5+1 :
+                                 border_swizzled[0]*0.5;
+            /* Pass through. */
+
+        case PIPE_FORMAT_RGTC1_UNORM:
         case PIPE_FORMAT_LATC1_UNORM:
             /* Add 1/32 to round the border color instead of truncating. */
             /* The Y component is used for the border color. */
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c
index 6214380..ea6d982 100644
--- a/src/gallium/drivers/r300/r300_texture.c
+++ b/src/gallium/drivers/r300/r300_texture.c
@@ -39,6 +39,18 @@
 
 #include "pipe/p_screen.h"
 
+void util_format_combine_swizzles(unsigned char *dst,
+                                  const unsigned char *swz1,
+                                  const unsigned char *swz2)
+{
+    unsigned i;
+
+    for (i = 0; i < 4; i++) {
+        dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ?
+                 swz1[swz2[i]] : swz2[i];
+    }
+}
+
 unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format,
                                    const unsigned char *swizzle_view,
                                    boolean dxtc_swizzle)
@@ -61,10 +73,7 @@ unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format,
 
     if (swizzle_view) {
         /* Combine two sets of swizzles. */
-        for (i = 0; i < 4; i++) {
-            swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ?
-                         swizzle_format[swizzle_view[i]] : swizzle_view[i];
-        }
+        util_format_combine_swizzles(swizzle, swizzle_format, swizzle_view);
     } else {
         memcpy(swizzle, swizzle_format, 4);
     }
@@ -171,17 +180,22 @@ uint32_t r300_translate_texformat(enum pipe_format format,
             }
     }
 
-    if (util_format_is_compressed(format) &&
-        dxtc_swizzle &&
-        format != PIPE_FORMAT_RGTC2_UNORM &&
-        format != PIPE_FORMAT_RGTC2_SNORM &&
-        format != PIPE_FORMAT_LATC2_UNORM &&
-        format != PIPE_FORMAT_LATC2_SNORM) {
-        result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view,
-                                            TRUE);
-    } else {
-        result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view,
-                                            FALSE);
+    /* Add swizzling. */
+    /* The RGTC1_SNORM and LATC1_SNORM swizzle is done in the shader. */
+    if (format != PIPE_FORMAT_RGTC1_SNORM &&
+        format != PIPE_FORMAT_LATC1_SNORM) {
+        if (util_format_is_compressed(format) &&
+            dxtc_swizzle &&
+            format != PIPE_FORMAT_RGTC2_UNORM &&
+            format != PIPE_FORMAT_RGTC2_SNORM &&
+            format != PIPE_FORMAT_LATC2_UNORM &&
+            format != PIPE_FORMAT_LATC2_SNORM) {
+            result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view,
+                                                TRUE);
+        } else {
+            result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view,
+                                                FALSE);
+        }
     }
 
     /* S3TC formats. */
@@ -212,7 +226,6 @@ uint32_t r300_translate_texformat(enum pipe_format format,
         switch (format) {
             case PIPE_FORMAT_RGTC1_SNORM:
             case PIPE_FORMAT_LATC1_SNORM:
-                result |= sign_bit[2];
             case PIPE_FORMAT_LATC1_UNORM:
             case PIPE_FORMAT_RGTC1_UNORM:
                 return R500_TX_FORMAT_ATI1N | result;
diff --git a/src/gallium/drivers/r300/r300_texture.h b/src/gallium/drivers/r300/r300_texture.h
index 158a387..4586bb2 100644
--- a/src/gallium/drivers/r300/r300_texture.h
+++ b/src/gallium/drivers/r300/r300_texture.h
@@ -35,6 +35,10 @@ struct r300_texture_desc;
 struct r300_resource;
 struct r300_screen;
 
+void util_format_combine_swizzles(unsigned char *dst,
+                                  const unsigned char *swz1,
+                                  const unsigned char *swz2);
+
 unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format,
                                    const unsigned char *swizzle_view,
                                    boolean dxtc_swizzle);
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_code.h b/src/mesa/drivers/dri/r300/compiler/radeon_code.h
index 35360aa..67e6acf 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_code.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_code.h
@@ -132,10 +132,10 @@ typedef enum {
 struct r300_fragment_program_external_state {
 	struct {
 		/**
-		 * If the sampler is used as a shadow sampler,
-		 * this field contains swizzle depending on the depth texture mode.
+		 * This field contains swizzle for some lowering passes
+		 * (shadow comparison, unorm->snorm conversion)
 		 */
-		unsigned depth_texture_swizzle:12;
+		unsigned texture_swizzle:12;
 
 		/**
 		 * If the sampler is used as a shadow sampler,
@@ -172,6 +172,12 @@ struct r300_fragment_program_external_state {
 		 * and right before texture fetch. The scaling factor is given by
 		 * RC_STATE_R300_TEXSCALE_FACTOR. */
 		unsigned clamp_and_scale_before_fetch : 1;
+
+		/**
+		 * Fetch RGTC1_SNORM or LATC1_SNORM as UNORM and convert UNORM -> SNORM
+		 * in the shader.
+		 */
+		unsigned convert_unorm_to_snorm:1;
 	} unit[16];
 
 	unsigned frag_clamp:1;
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 9722580..cef448e 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
@@ -48,7 +48,7 @@ static struct rc_src_register shadow_fail_value(struct r300_fragment_program_com
 	}
 
 	reg.Swizzle = combine_swizzles(reg.Swizzle,
-				compiler->state.unit[tmu].depth_texture_swizzle);
+				compiler->state.unit[tmu].texture_swizzle);
 	return reg;
 }
 
@@ -59,7 +59,7 @@ static struct rc_src_register shadow_pass_value(struct r300_fragment_program_com
 
 	reg.File = RC_FILE_NONE;
 	reg.Swizzle = combine_swizzles(RC_SWIZZLE_1111,
-				compiler->state.unit[tmu].depth_texture_swizzle);
+				compiler->state.unit[tmu].texture_swizzle);
 	return reg;
 }
 
@@ -256,7 +256,7 @@ int radeonTransformTEX(
 			inst_cmp->U.I.SrcReg[0].Index = tmp_sum;
 			inst_cmp->U.I.SrcReg[0].Swizzle =
 					combine_swizzles(RC_SWIZZLE_WWWW,
-							 compiler->state.unit[inst->U.I.TexSrcUnit].depth_texture_swizzle);
+							 compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle);
 			inst_cmp->U.I.SrcReg[pass] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit);
 			inst_cmp->U.I.SrcReg[fail] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit);
 
@@ -411,6 +411,7 @@ int radeonTransformTEX(
 		inst->U.I.SrcReg[0].Index = temp;
 	}
 
+	/* NPOT -> POT conversion for 3D textures. */
 	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;
@@ -440,6 +441,53 @@ int radeonTransformTEX(
 		scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR);
 	}
 
+	/* Convert SNORM-encoded ATI1N sampled as UNORM to SNORM.
+	 * Formula: dst = tex > 0.5 ? tex*2-2 : tex*2
+	 */
+	if (inst->U.I.Opcode != RC_OPCODE_KIL &&
+	    compiler->state.unit[inst->U.I.TexSrcUnit].convert_unorm_to_snorm) {
+		unsigned two, two_swizzle;
+		struct rc_instruction *inst_mul, *inst_mad, *inst_cnd;
+
+		two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2.35, &two_swizzle);
+
+		inst_mul = rc_insert_new_instruction(c, inst);
+		inst_mul->U.I.Opcode = RC_OPCODE_MUL;
+		inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
+		inst_mul->U.I.DstReg.Index = rc_find_free_temporary(c);
+		inst_mul->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+		inst_mul->U.I.SrcReg[0].Index = rc_find_free_temporary(c); /* redirected TEX output */
+		inst_mul->U.I.SrcReg[1].File = RC_FILE_CONSTANT; /* 2 */
+		inst_mul->U.I.SrcReg[1].Index = two;
+		inst_mul->U.I.SrcReg[1].Swizzle = two_swizzle;
+
+		inst_mad = rc_insert_new_instruction(c, inst_mul);
+		inst_mad->U.I.Opcode = RC_OPCODE_MAD;
+		inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
+		inst_mad->U.I.DstReg.Index = rc_find_free_temporary(c);
+		inst_mad->U.I.SrcReg[0] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */
+		inst_mad->U.I.SrcReg[1] = inst_mul->U.I.SrcReg[1]; /* 2 */
+		inst_mad->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[1]; /* 2 */
+		inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZW;
+
+		inst_cnd = rc_insert_new_instruction(c, inst_mad);
+		inst_cnd->U.I.Opcode = RC_OPCODE_CND;
+		inst_cnd->U.I.SaturateMode = inst->U.I.SaturateMode;
+		inst_cnd->U.I.DstReg = inst->U.I.DstReg;
+		inst_cnd->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+		inst_cnd->U.I.SrcReg[0].Index = inst_mad->U.I.DstReg.Index;
+		inst_cnd->U.I.SrcReg[0].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle;
+		inst_cnd->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
+		inst_cnd->U.I.SrcReg[1].Index = inst_mul->U.I.DstReg.Index;
+		inst_cnd->U.I.SrcReg[1].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle;
+		inst_cnd->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */
+
+		inst->U.I.SaturateMode = 0;
+		inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
+		inst->U.I.DstReg.Index = inst_mul->U.I.SrcReg[0].Index;
+		inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
+	}
+
 	/* Cannot write texture to output registers or with saturate (all chips),
 	 * or with masks (non-r500). */
 	if (inst->U.I.Opcode != RC_OPCODE_KIL &&



More information about the mesa-commit mailing list