[Mesa-dev] [PATCH 7/8] i965/fs: Add support for TXD with shadow comparisons.

Kenneth Graunke kenneth at whitecape.org
Fri Jun 17 20:01:27 PDT 2011


Our hardware doesn't have a sample_d_c message, so we have to do a
regular sample_d and emit instructions to manually perform the
comparison.

This requires a state dependent recompile whenever the sampler's compare
mode or function change.  This adds the per-sampler comparison functions
to brw_wm_prog_key, but only sets them when the sampler's compare mode
is GL_COMPARE_R_TO_TEXTURE (i.e. only for shadow sampling).

Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
---
 src/mesa/drivers/dri/i965/brw_fs.cpp         |    3 +
 src/mesa/drivers/dri/i965/brw_fs_emit.cpp    |    4 +-
 src/mesa/drivers/dri/i965/brw_fs_visitor.cpp |   62 +++++++++++++++++++++++--
 src/mesa/drivers/dri/i965/brw_wm.c           |    2 +
 src/mesa/drivers/dri/i965/brw_wm.h           |   12 +++++
 5 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index 3a16afe..fd0740a 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -1686,6 +1686,9 @@ brw_fs_precompile(struct gl_context *ctx, struct gl_shader_program *prog)
    key.clamp_fragment_color = true;
 
    for (int i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+      if (fp->Base.ShadowSamplers & (1 << i))
+	 key.compare_funcs[i] = GL_LESS;
+
       /* FINISHME: depth compares might use (0,0,0,W) for example */
       key.tex_swizzles[i] = SWIZZLE_XYZW;
    }
diff --git a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
index 1c522cb..1d89b8f 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
@@ -273,7 +273,7 @@ fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
 	 }
 	 break;
       case FS_OPCODE_TXD:
-	 assert(!inst->shadow_compare);
+	 /* There is no sample_d_c message; comparisons are done manually */
 	 msg_type = GEN5_SAMPLER_MESSAGE_SAMPLE_DERIVS;
 	 break;
       }
@@ -312,7 +312,7 @@ fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
 	 }
 	 break;
       case FS_OPCODE_TXD:
-	 assert(!inst->shadow_compare); // not supported yet
+	 /* There is no sample_d_c message; comparisons are done manually */
 	 assert(inst->mlen == 7 || inst->mlen == 10);
 	 msg_type = BRW_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS;
 	 break;
diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
index 35bda58..6116b10 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
@@ -549,7 +549,7 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    /* g0 header. */
    mlen = 1;
 
-   if (ir->shadow_comparitor) {
+   if (ir->shadow_comparitor && ir->op != ir_txd) {
       for (int i = 0; i < ir->coordinate->type->vector_elements; i++) {
 	 fs_inst *inst = emit(BRW_OPCODE_MOV,
 			      fs_reg(MRF, base_mrf + mlen + i), coordinate);
@@ -744,7 +744,7 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    }
    mlen += ir->coordinate->type->vector_elements * reg_width;
 
-   if (ir->shadow_comparitor) {
+   if (ir->shadow_comparitor && ir->op != ir_txd) {
       mlen = MAX2(mlen, header_present + 4 * reg_width);
 
       this->result = reg_undef;
@@ -841,7 +841,7 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       base_mrf--;
    }
 
-   if (ir->shadow_comparitor) {
+   if (ir->shadow_comparitor && ir->op != ir_txd) {
       ir->shadow_comparitor->accept(this);
       emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
       mlen += reg_width;
@@ -937,6 +937,19 @@ fs_visitor::visit(ir_texture *ir)
    int sampler = _mesa_get_sampler_uniform_value(ir->sampler, prog, &fp->Base);
    sampler = fp->Base.SamplerUnits[sampler];
 
+   /* Our hardware doesn't have a sample_d_c message, so shadow compares
+    * for textureGrad/TXD need to be emulated with instructions.
+    */
+   bool hw_compare_supported = ir->op != ir_txd;
+   if (ir->shadow_comparitor && !hw_compare_supported) {
+      assert(c->key.compare_funcs[sampler] != GL_NONE);
+      /* No need to even sample for GL_ALWAYS or GL_NEVER...bail early */
+      if (c->key.compare_funcs[sampler] == GL_ALWAYS)
+	 return swizzle_result(ir, fs_reg(1.0f), sampler);
+      else if (c->key.compare_funcs[sampler] == GL_NEVER)
+	 return swizzle_result(ir, fs_reg(0.0f), sampler);
+   }
+
    this->result = reg_undef;
    ir->coordinate->accept(this);
    fs_reg coordinate = this->result;
@@ -1045,8 +1058,47 @@ fs_visitor::visit(ir_texture *ir)
 
    inst->sampler = sampler;
 
-   if (ir->shadow_comparitor)
-      inst->shadow_compare = true;
+   if (ir->shadow_comparitor) {
+      if (hw_compare_supported) {
+	 inst->shadow_compare = true;
+      } else {
+	 ir->shadow_comparitor->accept(this);
+	 fs_reg ref = this->result;
+
+	 fs_reg value = dst;
+	 dst = fs_reg(this, glsl_type::vec4_type);
+
+	 /* FINISHME: This needs to be done pre-filtering. */
+
+	 uint32_t conditional = 0;
+	 switch (c->key.compare_funcs[sampler]) {
+	 /* GL_ALWAYS and GL_NEVER were handled at the top of the function */
+	 case GL_LESS:     conditional = BRW_CONDITIONAL_L;   break;
+	 case GL_GREATER:  conditional = BRW_CONDITIONAL_G;   break;
+	 case GL_LEQUAL:   conditional = BRW_CONDITIONAL_LE;  break;
+	 case GL_GEQUAL:   conditional = BRW_CONDITIONAL_GE;  break;
+	 case GL_EQUAL:    conditional = BRW_CONDITIONAL_EQ;  break;
+	 case GL_NOTEQUAL: conditional = BRW_CONDITIONAL_NEQ; break;
+	 default: assert(!"Should not get here: bad shadow compare function");
+	 }
+
+	 /* Use conditional moves to load 0 or 1 as the result */
+	 this->current_annotation = "manual shadow comparison";
+	 for (int i = 0; i < 4; i++) {
+	    inst = emit(BRW_OPCODE_MOV, dst, fs_reg(0.0f));
+
+	    inst = emit(BRW_OPCODE_CMP, reg_null_f, ref, value);
+	    inst->conditional_mod = conditional;
+
+	    inst = emit(BRW_OPCODE_MOV, dst, fs_reg(1.0f));
+	    inst->predicated = true;
+
+	    dst.reg_offset++;
+	    value.reg_offset++;
+	 }
+	 dst.reg_offset = 0;
+      }
+   }
 
    swizzle_result(ir, dst, sampler);
 }
diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c
index 1aebd12..4d35ce1 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.c
+++ b/src/mesa/drivers/dri/i965/brw_wm.c
@@ -389,6 +389,8 @@ static void brw_wm_populate_key( struct brw_context *brw,
 	  * all 4 channels.
 	  */
 	 if (sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+	    key->compare_funcs[i] = sampler->CompareFunc;
+
 	    if (sampler->DepthMode == GL_ALPHA) {
 	       swizzles[0] = SWIZZLE_ZERO;
 	       swizzles[1] = SWIZZLE_ZERO;
diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h
index e244b55..29082c1 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.h
+++ b/src/mesa/drivers/dri/i965/brw_wm.h
@@ -68,6 +68,18 @@ struct brw_wm_prog_key {
    GLuint clamp_fragment_color:1;
    GLuint line_aa:2;
 
+   /**
+    * Per-sampler comparison functions:
+    *
+    * If comparison mode is GL_COMPARE_R_TO_TEXTURE, then this is set to one
+    * of GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL,
+    * GL_GEQUAL, or GL_ALWAYS.  Otherwise (comparison mode is GL_NONE), this
+    * field is irrelevant so it's left as GL_NONE (0).
+    *
+    * While this is a GLenum, all possible values fit in 16-bits.
+    */
+   uint16_t compare_funcs[BRW_MAX_TEX_UNIT];
+
    GLbitfield proj_attrib_mask; /**< one bit per fragment program attribute */
    GLuint yuvtex_mask:16;
    GLuint yuvtex_swap_mask:16;	/* UV swaped */
-- 
1.7.5.4



More information about the mesa-dev mailing list