Gen4-6 don'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 ctx->Depth.Func changes. do_wm_prog looks for a compiled program in the cache based off of brw_wm_prog_key, and if it doesn't find one, recompiles. So we simply need to add the depth comparison function to the key; the _NEW_DEPTH dirty bit was already in-place. Of course, this is unnecessary in every other case, so I leave key->depth_comparison_func as 0 unless it's actually relevant. Signed-off-by: Kenneth Graunke <kenn...@whitecape.org> --- src/mesa/drivers/dri/i965/brw_fs_emit.cpp | 4 +- src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 51 ++++++++++++++++++++++++-- src/mesa/drivers/dri/i965/brw_wm.h | 1 + 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp index 636ef4e..8bd8b01 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp @@ -276,7 +276,7 @@ fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src) if (inst->shadow_compare && intel->gen >= 7) { msg_type = GEN7_SAMPLER_MESSAGE_SAMPLE_DERIVS_COMPARE; } else { - assert(intel->gen >= 7 || !inst->shadow_compare); // shadow comparisons not supported on gen5-6 yet. + /* TXD with shadow comparison is handled specially pre-Ivybridge */ msg_type = GEN5_SAMPLER_MESSAGE_SAMPLE_DERIVS; } break; @@ -316,7 +316,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 + /* TXD with shadow comparison is handled specially pre-Ivybridge */ 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 03687ce..67344bd 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp @@ -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; @@ -934,6 +934,21 @@ fs_visitor::visit(ir_texture *ir) int sampler = _mesa_get_sampler_uniform_value(ir->sampler, prog, &fp->Base); sampler = fp->Base.SamplerUnits[sampler]; + /* Pre-Ivybridge 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 || intel->gen > 7; + if (ir->shadow_comparitor && !hw_compare_supported) { + /* Mark that this program is only valid for the current glDepthFunc */ + c->key.depth_compare_func = ctx->Depth.Func; + + /* No need to even sample for GL_ALWAYS or GL_NEVER...bail early */ + if (ctx->Depth.Func == GL_ALWAYS) + return swizzle_shadow_result(ir, fs_reg(1.0f), sampler); + else if (ctx->Depth.Func == GL_NEVER) + return swizzle_shadow_result(ir, fs_reg(0.0f), sampler); + } + this->result = reg_undef; ir->coordinate->accept(this); fs_reg coordinate = this->result; @@ -1044,8 +1059,38 @@ fs_visitor::visit(ir_texture *ir) this->result = dst; - if (ir->shadow_comparitor) - inst->shadow_compare = true; + if (ir->shadow_comparitor) { + if (hw_compare_supported) { + inst->shadow_compare = true; + } else { + fs_reg result = fs_reg(this, glsl_type::vec4_type); + fs_reg z = coordinate; + z.reg_offset = 2; + + /* FINISHME: This needs to be done pre-filtering. */ + + uint32_t conditional = 0; + switch (ctx->Depth.Func) { + /* 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 ctx->Depth.Func"); + } + + /* r = (coordinate.z < sample result) ? 1.0 : 0.0 */ + inst = emit(BRW_OPCODE_MOV, result, fs_reg(0.0f)); + inst = emit(BRW_OPCODE_CMP, reg_null_f, z, dst); + inst->conditional_mod = conditional; + inst = emit(BRW_OPCODE_MOV, result, fs_reg(1.0f)); + inst->predicated = true; + + dst = result; + } + } swizzle_shadow_result(ir, dst, sampler); } diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index e244b55..0b284b6 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -67,6 +67,7 @@ struct brw_wm_prog_key { GLuint alpha_test:1; GLuint clamp_fragment_color:1; GLuint line_aa:2; + uint8_t depth_compare_func; /* 0 if irrelevant, GL_LESS etc. otherwise */ GLbitfield proj_attrib_mask; /**< one bit per fragment program attribute */ GLuint yuvtex_mask:16; -- 1.7.5.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev