From 6430df37736d71dd2bd6f1fe447d39f0b68cb567 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Fri, 10 Jun 2011 14:48:46 -0700 Subject: [PATCH] i965/fs: Add support for TXD with shadow comparisons. 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 Reviewed-by: Eric Anholt --- 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 1cd673919f8..b5ea943387d 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 1c522cbad02..1d89b8f1d11 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 35bda58cf54..6116b1081e8 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 f1c9985290c..b0dfdd536aa 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.c +++ b/src/mesa/drivers/dri/i965/brw_wm.c @@ -388,6 +388,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 e244b55a083..29082c19088 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 */ -- 2.30.2