From: Roland Scheidegger Date: Mon, 18 Sep 2017 02:52:26 +0000 (+0200) Subject: llvmpipe, gallivm: implement lod queries (LODQ opcode) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=886626960bca51bdfc0880e3830c0a95ea143c4c;p=mesa.git llvmpipe, gallivm: implement lod queries (LODQ opcode) This uses all the existing code to calculate lod values for mip linear filtering. Though we'll have to disable the simplifications (if we know some parts of the lod calculation won't actually matter for filtering purposes due to mip clamps etc.). For better or worse, we'll also disable lod calculation hacks (mostly should make a difference for cube maps) always - the issue with per-pixel lod being difficult is mostly because we then have different mipmaps needed for the actual texel fetch, which isn't a problem with lodq. We still use approximation for the log2 - for that reason I believe the float part of the lod is only accurate to about 4-5 bits (and one bit less with 1d textures actually) which is hopefully good enough (though d3d10 technically requires 6 bits - could use quadratic interpolation instead of linear to get 8 bits or so). Since lodq requires unclamped lod, we also have to move some sampler key calculations to texture sampling code - even if we know we're going to access mipmap 0 we still have to calculate lod and apply lod_bias for lodq. Passes piglit ARB_texture_query_lod tests (after having fixed the test). Reviewed-by: Jose Fonseca --- diff --git a/docs/features.txt b/docs/features.txt index fe412f6607a..c186dc70da3 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -131,7 +131,7 @@ GL 4.0, GLSL 4.00 --- all DONE: i965/gen7+, nvc0, r600, radeonsi GL_ARB_texture_buffer_object_rgb32 DONE (i965/gen6+, llvmpipe, softpipe, swr) GL_ARB_texture_cube_map_array DONE (i965/gen6+, nv50, llvmpipe, softpipe) GL_ARB_texture_gather DONE (i965/gen6+, nv50, llvmpipe, softpipe, swr) - GL_ARB_texture_query_lod DONE (i965, nv50, softpipe) + GL_ARB_texture_query_lod DONE (i965, nv50, llvmpipe, softpipe) GL_ARB_transform_feedback2 DONE (i965/gen6+, nv50, llvmpipe, softpipe, swr) GL_ARB_transform_feedback3 DONE (i965/gen7+, llvmpipe, softpipe, swr) diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c index a1dc61d40f6..db3d9d65c9c 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c @@ -156,19 +156,19 @@ lp_sampler_static_sampler_state(struct lp_static_sampler_state *state, state->wrap_r = sampler->wrap_r; state->min_img_filter = sampler->min_img_filter; state->mag_img_filter = sampler->mag_img_filter; + state->min_mip_filter = sampler->min_mip_filter; state->seamless_cube_map = sampler->seamless_cube_map; if (sampler->max_lod > 0.0f) { - state->min_mip_filter = sampler->min_mip_filter; - } else { - state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + state->max_lod_pos = 1; + } + + if (sampler->lod_bias != 0.0f) { + state->lod_bias_non_zero = 1; } if (state->min_mip_filter != PIPE_TEX_MIPFILTER_NONE || state->min_img_filter != state->mag_img_filter) { - if (sampler->lod_bias != 0.0f) { - state->lod_bias_non_zero = 1; - } /* If min_lod == max_lod we can greatly simplify mipmap selection. * This is a case that occurs during automatic mipmap generation. @@ -234,7 +234,7 @@ lp_build_rho(struct lp_build_sample_context *bld, unsigned length = coord_bld->type.length; unsigned num_quads = length / 4; boolean rho_per_quad = rho_bld->type.length != length; - boolean no_rho_opt = (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) && (dims > 1); + boolean no_rho_opt = bld->no_rho_approx && (dims > 1); unsigned i; LLVMValueRef i32undef = LLVMGetUndef(LLVMInt32TypeInContext(gallivm->context)); LLVMValueRef rho_xvec, rho_yvec; @@ -694,6 +694,7 @@ lp_build_ilog2_sqrt(struct lp_build_context *bld, */ void lp_build_lod_selector(struct lp_build_sample_context *bld, + boolean is_lodq, unsigned texture_unit, unsigned sampler_unit, LLVMValueRef s, @@ -704,6 +705,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, LLVMValueRef lod_bias, /* optional */ LLVMValueRef explicit_lod, /* optional */ unsigned mip_filter, + LLVMValueRef *out_lod, LLVMValueRef *out_lod_ipart, LLVMValueRef *out_lod_fpart, LLVMValueRef *out_lod_positive) @@ -736,7 +738,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, * I have no clue about the (undocumented) wishes of d3d9/d3d10 here! */ - if (bld->static_sampler_state->min_max_lod_equal) { + if (bld->static_sampler_state->min_max_lod_equal && !is_lodq) { /* User is forcing sampling from a particular mipmap level. * This is hit during mipmap generation. */ @@ -756,7 +758,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, } else { LLVMValueRef rho; - boolean rho_squared = ((gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) && + boolean rho_squared = (bld->no_rho_approx && (bld->dims > 1)) || cube_rho; rho = lp_build_rho(bld, texture_unit, s, t, r, cube_rho, derivs); @@ -765,7 +767,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, * Compute lod = log2(rho) */ - if (!lod_bias && + if (!lod_bias && !is_lodq && !bld->static_sampler_state->lod_bias_non_zero && !bld->static_sampler_state->apply_max_lod && !bld->static_sampler_state->apply_min_lod) { @@ -792,8 +794,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, return; } if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR && - !(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR) && - !rho_squared) { + !bld->no_brilinear && !rho_squared) { /* * This can't work if rho is squared. Not sure if it could be * fixed while keeping it worthwile, could also do sqrt here @@ -839,6 +840,10 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, lod = LLVMBuildFAdd(builder, lod, sampler_lod_bias, "sampler_lod_bias"); } + if (is_lodq) { + *out_lod = lod; + } + /* clamp lod */ if (bld->static_sampler_state->apply_max_lod) { LLVMValueRef max_lod = @@ -856,13 +861,18 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, lod = lp_build_max(lodf_bld, lod, min_lod); } + + if (is_lodq) { + *out_lod_fpart = lod; + return; + } } *out_lod_positive = lp_build_cmp(lodf_bld, PIPE_FUNC_GREATER, lod, lodf_bld->zero); if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { - if (!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) { + if (!bld->no_brilinear) { lp_build_brilinear_lod(lodf_bld, lod, BRILINEAR_FACTOR, out_lod_ipart, out_lod_fpart); } @@ -1679,9 +1689,7 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld, maxasat = lp_build_max(coord_bld, as, at); ar_ge_as_at = lp_build_cmp(coord_bld, PIPE_FUNC_GEQUAL, ar, maxasat); - if (need_derivs && (derivs_in || - ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) && - (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX)))) { + if (need_derivs && (derivs_in || (bld->no_quad_lod && bld->no_rho_approx))) { /* * XXX: This is really really complex. * It is a bit overkill to use this for implicit derivatives as well, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h index 9ec051a340b..c00997b8983 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h @@ -82,7 +82,8 @@ enum lp_sampler_lod_control { enum lp_sampler_op_type { LP_SAMPLER_OP_TEXTURE, LP_SAMPLER_OP_FETCH, - LP_SAMPLER_OP_GATHER + LP_SAMPLER_OP_GATHER, + LP_SAMPLER_OP_LODQ }; @@ -165,6 +166,7 @@ struct lp_static_sampler_state unsigned normalized_coords:1; unsigned min_max_lod_equal:1; /**< min_lod == max_lod ? */ unsigned lod_bias_non_zero:1; + unsigned max_lod_pos:1; unsigned apply_min_lod:1; /**< min_lod > 0 ? */ unsigned apply_max_lod:1; /**< max_lod < last_level ? */ unsigned seamless_cube_map:1; @@ -321,6 +323,10 @@ struct lp_build_sample_context /** number of lod values (valid are 1, length/4, length) */ unsigned num_lods; + boolean no_quad_lod; + boolean no_brilinear; + boolean no_rho_approx; + /** regular scalar float type */ struct lp_type float_type; struct lp_build_context float_bld; @@ -486,6 +492,7 @@ lp_sampler_static_texture_state(struct lp_static_texture_state *state, void lp_build_lod_selector(struct lp_build_sample_context *bld, + boolean is_lodq, unsigned texture_index, unsigned sampler_index, LLVMValueRef s, @@ -496,6 +503,7 @@ lp_build_lod_selector(struct lp_build_sample_context *bld, LLVMValueRef lod_bias, /* optional */ LLVMValueRef explicit_lod, /* optional */ unsigned mip_filter, + LLVMValueRef *out_lod, LLVMValueRef *out_lod_ipart, LLVMValueRef *out_lod_fpart, LLVMValueRef *out_lod_positive); diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c index 1539849b2d6..b67a089c47b 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c @@ -1829,6 +1829,7 @@ lp_build_layer_coord(struct lp_build_sample_context *bld, */ static void lp_build_sample_common(struct lp_build_sample_context *bld, + boolean is_lodq, unsigned texture_index, unsigned sampler_index, LLVMValueRef *coords, @@ -1836,6 +1837,7 @@ lp_build_sample_common(struct lp_build_sample_context *bld, LLVMValueRef lod_bias, /* optional */ LLVMValueRef explicit_lod, /* optional */ LLVMValueRef *lod_pos_or_zero, + LLVMValueRef *lod, LLVMValueRef *lod_fpart, LLVMValueRef *ilevel0, LLVMValueRef *ilevel1) @@ -1908,15 +1910,44 @@ lp_build_sample_common(struct lp_build_sample_context *bld, * Compute the level of detail (float). */ if (min_filter != mag_filter || - mip_filter != PIPE_TEX_MIPFILTER_NONE) { + mip_filter != PIPE_TEX_MIPFILTER_NONE || is_lodq) { /* Need to compute lod either to choose mipmap levels or to * distinguish between minification/magnification with one mipmap level. */ - lp_build_lod_selector(bld, texture_index, sampler_index, + lp_build_lod_selector(bld, is_lodq, texture_index, sampler_index, coords[0], coords[1], coords[2], cube_rho, derivs, lod_bias, explicit_lod, - mip_filter, + mip_filter, lod, &lod_ipart, lod_fpart, lod_pos_or_zero); + if (is_lodq) { + LLVMValueRef last_level; + last_level = bld->dynamic_state->last_level(bld->dynamic_state, + bld->gallivm, + bld->context_ptr, + texture_index); + first_level = bld->dynamic_state->first_level(bld->dynamic_state, + bld->gallivm, + bld->context_ptr, + texture_index); + last_level = lp_build_sub(&bld->int_bld, last_level, first_level); + last_level = lp_build_int_to_float(&bld->float_bld, last_level); + last_level = lp_build_broadcast_scalar(&bld->lodf_bld, last_level); + + switch (mip_filter) { + case PIPE_TEX_MIPFILTER_NONE: + *lod_fpart = bld->lodf_bld.zero; + break; + case PIPE_TEX_MIPFILTER_NEAREST: + *lod_fpart = lp_build_round(&bld->lodf_bld, *lod_fpart); + /* fallthrough */ + case PIPE_TEX_MIPFILTER_LINEAR: + *lod_fpart = lp_build_clamp(&bld->lodf_bld, *lod_fpart, + bld->lodf_bld.zero, last_level); + break; + } + return; + } + } else { lod_ipart = bld->lodi_bld.zero; *lod_pos_or_zero = bld->lodi_bld.zero; @@ -2522,7 +2553,7 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, enum lp_sampler_op_type op_type; LLVMValueRef lod_bias = NULL; LLVMValueRef explicit_lod = NULL; - boolean op_is_tex; + boolean op_is_tex, op_is_lodq, op_is_gather; if (0) { enum pipe_format fmt = static_texture_state->format; @@ -2537,6 +2568,8 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, LP_SAMPLER_OP_TYPE_SHIFT; op_is_tex = op_type == LP_SAMPLER_OP_TEXTURE; + op_is_lodq = op_type == LP_SAMPLER_OP_LODQ; + op_is_gather = op_type == LP_SAMPLER_OP_GATHER; if (lod_control == LP_SAMPLER_LOD_BIAS) { lod_bias = lod; @@ -2582,6 +2615,16 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, bld.format_desc = util_format_description(static_texture_state->format); bld.dims = dims; + if (gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD || op_is_lodq) { + bld.no_quad_lod = TRUE; + } + if (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX || op_is_lodq) { + bld.no_rho_approx = TRUE; + } + if (gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR || op_is_lodq) { + bld.no_brilinear = TRUE; + } + bld.vector_width = lp_type_width(type); bld.float_type = lp_type_float(32); @@ -2611,12 +2654,13 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, bld.texel_type = lp_type_int_vec(type.width, type.width * type.length); } - if (!static_texture_state->level_zero_only) { + if (!static_texture_state->level_zero_only || + !static_sampler_state->max_lod_pos || op_is_lodq) { derived_sampler_state.min_mip_filter = static_sampler_state->min_mip_filter; } else { derived_sampler_state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; } - if (op_type == LP_SAMPLER_OP_GATHER) { + if (op_is_gather) { /* * gather4 is exactly like GL_LINEAR filtering but in the end skipping * the actual filtering. Using mostly the same paths, so cube face @@ -2677,11 +2721,11 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, */ bld.num_mips = bld.num_lods = 1; - if ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) && - (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) && - (static_texture_state->target == PIPE_TEXTURE_CUBE || - static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) && - (op_is_tex && mip_filter != PIPE_TEX_MIPFILTER_NONE)) { + if (bld.no_quad_lod && bld.no_rho_approx && + ((mip_filter != PIPE_TEX_MIPFILTER_NONE && op_is_tex && + (static_texture_state->target == PIPE_TEXTURE_CUBE || + static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY)) || + op_is_lodq)) { /* * special case for using per-pixel lod even for implicit lod, * which is generally never required (ok by APIs) except to please @@ -2689,6 +2733,8 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, * can cause derivatives to be different for pixels outside the primitive * due to the major axis division even if pre-project derivatives are * looking normal). + * For lodq, we do it to simply avoid scalar pack / unpack (albeit for + * cube maps we do indeed get per-pixel lod values). */ bld.num_mips = type.length; bld.num_lods = type.length; @@ -2802,6 +2848,32 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, newcoords[i] = coords[i]; } + if (util_format_is_pure_integer(static_texture_state->format) && + !util_format_has_depth(bld.format_desc) && op_is_tex && + (static_sampler_state->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR || + static_sampler_state->min_img_filter == PIPE_TEX_FILTER_LINEAR || + static_sampler_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR)) { + /* + * Bail if impossible filtering is specified (the awkard additional + * depth check is because it is legal in gallium to have things like S8Z24 + * here which would say it's pure int despite such formats should sample + * the depth component). + * In GL such filters make the texture incomplete, this makes it robust + * against state trackers which set this up regardless (we'd crash in the + * lerp later otherwise). + * At least in some apis it may be legal to use such filters with lod + * queries and/or gather (at least for gather d3d10 says only the wrap + * bits are really used hence filter bits are likely simply ignored). + * For fetch, we don't get valid samplers either way here. + */ + unsigned chan; + LLVMValueRef zero = lp_build_zero(gallivm, type); + for (chan = 0; chan < 4; chan++) { + texel_out[chan] = zero; + } + return; + } + if (0) { /* For debug: no-op texture sampling */ lp_build_sample_nop(gallivm, @@ -2818,33 +2890,9 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, else { LLVMValueRef lod_fpart = NULL, lod_positive = NULL; - LLVMValueRef ilevel0 = NULL, ilevel1 = NULL; + LLVMValueRef ilevel0 = NULL, ilevel1 = NULL, lod = NULL; boolean use_aos; - if (util_format_is_pure_integer(static_texture_state->format) && - !util_format_has_depth(bld.format_desc) && - (static_sampler_state->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR || - static_sampler_state->min_img_filter == PIPE_TEX_FILTER_LINEAR || - static_sampler_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR)) { - /* - * Bail if impossible filtering is specified (the awkard additional - * depth check is because it is legal in gallium to have things like S8Z24 - * here which would say it's pure int despite such formats should sample - * the depth component). - * In GL such filters make the texture incomplete, this makes it robust - * against state trackers which set this up regardless (we'd crash in the - * lerp later (except for gather)). - * Must do this after fetch_texel code since with GL state tracker we'll - * get some junk sampler for buffer textures. - */ - unsigned chan; - LLVMValueRef zero = lp_build_zero(gallivm, type); - for (chan = 0; chan < 4; chan++) { - texel_out[chan] = zero; - } - return; - } - use_aos = util_format_fits_8unorm(bld.format_desc) && op_is_tex && /* not sure this is strictly needed or simply impossible */ @@ -2885,12 +2933,19 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, derived_sampler_state.wrap_r); } - lp_build_sample_common(&bld, texture_index, sampler_index, + lp_build_sample_common(&bld, op_is_lodq, texture_index, sampler_index, newcoords, derivs, lod_bias, explicit_lod, - &lod_positive, &lod_fpart, + &lod_positive, &lod, &lod_fpart, &ilevel0, &ilevel1); + if (op_is_lodq) { + texel_out[0] = lod_fpart; + texel_out[1] = lod; + texel_out[2] = texel_out[3] = bld.coord_bld.zero; + return; + } + if (use_aos && static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) { /* The aos path doesn't do seamless filtering so simply add cube layer * to face now. @@ -2937,6 +2992,9 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, /* Setup our build context */ memset(&bld4, 0, sizeof bld4); + bld4.no_quad_lod = bld.no_quad_lod; + bld4.no_rho_approx = bld.no_rho_approx; + bld4.no_brilinear = bld.no_brilinear; bld4.gallivm = bld.gallivm; bld4.context_ptr = bld.context_ptr; bld4.static_texture_state = bld.static_texture_state; @@ -2964,8 +3022,7 @@ lp_build_sample_soa_code(struct gallivm_state *gallivm, bld4.texel_type.length = 4; bld4.num_mips = bld4.num_lods = 1; - if ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) && - (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) && + if (bld4.no_quad_lod && bld4.no_rho_approx && (static_texture_state->target == PIPE_TEXTURE_CUBE || static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) && (op_is_tex && mip_filter != PIPE_TEX_MIPFILTER_NONE)) { diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c index f16c579f38d..3e47372b5cf 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c @@ -3145,6 +3145,18 @@ tg4_emit( emit_data->output, 2, LP_SAMPLER_OP_GATHER); } +static void +lodq_emit( + const struct lp_build_tgsi_action * action, + struct lp_build_tgsi_context * bld_base, + struct lp_build_emit_data * emit_data) +{ + struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base); + + emit_tex(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_NONE, + emit_data->output, 1, LP_SAMPLER_OP_LODQ); +} + static void txq_emit( const struct lp_build_tgsi_action * action, @@ -3875,6 +3887,7 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm, bld.bld_base.op_actions[TGSI_OPCODE_TXB2].emit = txb2_emit; bld.bld_base.op_actions[TGSI_OPCODE_TXL2].emit = txl2_emit; bld.bld_base.op_actions[TGSI_OPCODE_TG4].emit = tg4_emit; + bld.bld_base.op_actions[TGSI_OPCODE_LODQ].emit = lodq_emit; /* DX10 sampling ops */ bld.bld_base.op_actions[TGSI_OPCODE_SAMPLE].emit = sample_emit; bld.bld_base.op_actions[TGSI_OPCODE_SAMPLE_B].emit = sample_b_emit; diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 482eac3d6c4..53171162a54 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -252,7 +252,6 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param) case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: return 4; case PIPE_CAP_TEXTURE_GATHER_SM5: - case PIPE_CAP_TEXTURE_QUERY_LOD: case PIPE_CAP_SAMPLE_SHADING: case PIPE_CAP_TEXTURE_GATHER_OFFSETS: return 0; @@ -265,6 +264,7 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param) return 1; case PIPE_CAP_FAKE_SW_MSAA: return 1; + case PIPE_CAP_TEXTURE_QUERY_LOD: case PIPE_CAP_CONDITIONAL_RENDER_INVERTED: case PIPE_CAP_TGSI_ARRAY_COMPONENTS: case PIPE_CAP_DOUBLES: