1 /* 2 * Copyright Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "dxil_nir_lower_int_samplers.h" 25 #include "nir_builder.h" 26 #include "nir_builtin_builder.h" 27 28 static bool 29 lower_sample_to_txf_for_integer_tex_filter(const nir_instr *instr, 30 UNUSED const void *_options) 31 { 32 if (instr->type != nir_instr_type_tex) 33 return false; 34 35 nir_tex_instr *tex = nir_instr_as_tex(instr); 36 if (tex->op != nir_texop_tex && 37 tex->op != nir_texop_txb && 38 tex->op != nir_texop_txl && 39 tex->op != nir_texop_txd) 40 return false; 41 42 return (tex->dest_type & (nir_type_int | nir_type_uint)); 43 } 44 45 static nir_ssa_def * 46 dx_get_texture_lod(nir_builder *b, nir_tex_instr *tex) 47 { 48 nir_tex_instr *tql; 49 50 unsigned num_srcs = 0; 51 for (unsigned i = 0; i < tex->num_srcs; i++) { 52 if (tex->src[i].src_type == nir_tex_src_coord || 53 tex->src[i].src_type == nir_tex_src_texture_deref || 54 tex->src[i].src_type == nir_tex_src_sampler_deref || 55 tex->src[i].src_type == nir_tex_src_texture_offset || 56 tex->src[i].src_type == nir_tex_src_sampler_offset || 57 tex->src[i].src_type == nir_tex_src_texture_handle || 58 tex->src[i].src_type == nir_tex_src_sampler_handle) 59 num_srcs++; 60 } 61 62 tql = nir_tex_instr_create(b->shader, num_srcs); 63 tql->op = nir_texop_lod; 64 unsigned coord_components = tex->coord_components; 65 if (tex->is_array) 66 --coord_components; 67 68 tql->coord_components = coord_components; 69 tql->sampler_dim = tex->sampler_dim; 70 tql->is_shadow = tex->is_shadow; 71 tql->is_new_style_shadow = tex->is_new_style_shadow; 72 tql->texture_index = tex->texture_index; 73 tql->sampler_index = tex->sampler_index; 74 tql->dest_type = nir_type_float32; 75 76 /* The coordinate needs special handling because we might have 77 * to strip the array index. Don't clutter the code with an additional 78 * check for is_array though, in the worst case we create an additional 79 * move the the optimization will remove later again. */ 80 int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord); 81 nir_ssa_def *ssa_src = nir_channels(b, tex->src[coord_index].src.ssa, 82 (1 << coord_components) - 1); 83 nir_src src = nir_src_for_ssa(ssa_src); 84 nir_src_copy(&tql->src[0].src, &src); 85 tql->src[0].src_type = nir_tex_src_coord; 86 87 unsigned idx = 1; 88 for (unsigned i = 0; i < tex->num_srcs; i++) { 89 if (tex->src[i].src_type == nir_tex_src_texture_deref || 90 tex->src[i].src_type == nir_tex_src_sampler_deref || 91 tex->src[i].src_type == nir_tex_src_texture_offset || 92 tex->src[i].src_type == nir_tex_src_sampler_offset || 93 tex->src[i].src_type == nir_tex_src_texture_handle || 94 tex->src[i].src_type == nir_tex_src_sampler_handle) { 95 nir_src_copy(&tql->src[idx].src, &tex->src[i].src); 96 tql->src[idx].src_type = tex->src[i].src_type; 97 idx++; 98 } 99 } 100 101 nir_ssa_dest_init(&tql->instr, &tql->dest, 2, 32, NULL); 102 nir_builder_instr_insert(b, &tql->instr); 103 104 /* DirectX LOD only has a value in x channel */ 105 return nir_channel(b, &tql->dest.ssa, 0); 106 } 107 108 typedef struct { 109 nir_ssa_def *coords; 110 nir_ssa_def *use_border_color; 111 } wrap_result_t; 112 113 typedef struct { 114 nir_ssa_def *lod; 115 nir_ssa_def *size; 116 int ncoord_comp; 117 wrap_result_t wrap[3]; 118 } wrap_lower_param_t; 119 120 static void 121 wrap_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 122 { 123 /* clamp(coord, 0, size - 1) */ 124 wrap_params->coords = nir_fmin(b, nir_fsub(b, size, nir_imm_float(b, 1.0f)), 125 nir_fmax(b, wrap_params->coords, nir_imm_float(b, 0.0f))); 126 } 127 128 static void 129 wrap_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 130 { 131 /* mod(coord, size) 132 * This instruction must be exact, otherwise certain sizes result in 133 * incorrect sampling */ 134 wrap_params->coords = nir_fmod(b, wrap_params->coords, size); 135 nir_instr_as_alu(wrap_params->coords->parent_instr)->exact = true; 136 } 137 138 static nir_ssa_def * 139 mirror(nir_builder *b, nir_ssa_def *coord) 140 { 141 /* coord if >= 0, otherwise -(1 + coord) */ 142 return nir_bcsel(b, nir_fge(b, coord, nir_imm_float(b, 0.0f)), coord, 143 nir_fneg(b, nir_fadd(b, nir_imm_float(b, 1.0f), coord))); 144 } 145 146 static void 147 wrap_mirror_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 148 { 149 /* (size 1) mirror(mod(coord, 2 * size) size) */ 150 nir_ssa_def *coord_mod2size = nir_fmod(b, wrap_params->coords, nir_fmul(b, nir_imm_float(b, 2.0f), size)); 151 nir_instr_as_alu(coord_mod2size->parent_instr)->exact = true; 152 nir_ssa_def *a = nir_fsub(b, coord_mod2size, size); 153 wrap_params->coords = nir_fsub(b, nir_fsub(b, size, nir_imm_float(b, 1.0f)), mirror(b, a)); 154 } 155 156 static void 157 wrap_mirror_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 158 { 159 /* clamp(mirror(coord), 0, size - 1) */ 160 wrap_params->coords = nir_fmin(b, nir_fsub(b, size, nir_imm_float(b, 1.0f)), 161 nir_fmax(b, mirror(b, wrap_params->coords), nir_imm_float(b, 0.0f))); 162 } 163 164 static void 165 wrap_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 166 { 167 nir_ssa_def *is_low = nir_flt(b, wrap_params->coords, nir_imm_float(b, 0.0)); 168 nir_ssa_def *is_high = nir_fge(b, wrap_params->coords, size); 169 wrap_params->use_border_color = nir_ior(b, is_low, is_high); 170 } 171 172 static void 173 wrap_mirror_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_ssa_def *size) 174 { 175 /* We have to take care of the boundaries */ 176 nir_ssa_def *is_low = nir_flt(b, wrap_params->coords, nir_fmul(b, size, nir_imm_float(b, -1.0))); 177 nir_ssa_def *is_high = nir_flt(b, nir_fmul(b, size, nir_imm_float(b, 2.0)), wrap_params->coords); 178 wrap_params->use_border_color = nir_ior(b, is_low, is_high); 179 180 /* Within the boundaries this acts like mirror_repeat */ 181 wrap_mirror_repeat(b, wrap_params, size); 182 183 } 184 185 static wrap_result_t 186 wrap_coords(nir_builder *b, nir_ssa_def *coords, enum pipe_tex_wrap wrap, 187 nir_ssa_def *size) 188 { 189 wrap_result_t result = {coords, nir_imm_false(b)}; 190 191 switch (wrap) { 192 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 193 wrap_clamp_to_edge(b, &result, size); 194 break; 195 case PIPE_TEX_WRAP_REPEAT: 196 wrap_repeat(b, &result, size); 197 break; 198 case PIPE_TEX_WRAP_MIRROR_REPEAT: 199 wrap_mirror_repeat(b, &result, size); 200 break; 201 case PIPE_TEX_WRAP_MIRROR_CLAMP: 202 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 203 wrap_mirror_clamp_to_edge(b, &result, size); 204 break; 205 case PIPE_TEX_WRAP_CLAMP: 206 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 207 wrap_clamp(b, &result, size); 208 break; 209 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 210 wrap_mirror_clamp(b, &result, size); 211 break; 212 } 213 return result; 214 } 215 216 static nir_ssa_def * 217 load_bordercolor(nir_builder *b, nir_tex_instr *tex, dxil_wrap_sampler_state *active_state, 218 const dxil_texture_swizzle_state *tex_swizzle) 219 { 220 nir_const_value const_value[4] = {{0}}; 221 int ndest_comp = nir_dest_num_components(tex->dest); 222 223 unsigned swizzle[4] = { 224 tex_swizzle->swizzle_r, 225 tex_swizzle->swizzle_g, 226 tex_swizzle->swizzle_b, 227 tex_swizzle->swizzle_a 228 }; 229 230 for (int i = 0; i < ndest_comp; ++i) { 231 switch (swizzle[i]) { 232 case PIPE_SWIZZLE_0: 233 const_value[i].f32 = 0; 234 break; 235 case PIPE_SWIZZLE_1: 236 const_value[i].i32 = 1; 237 break; 238 case PIPE_SWIZZLE_X: 239 case PIPE_SWIZZLE_Y: 240 case PIPE_SWIZZLE_Z: 241 case PIPE_SWIZZLE_W: 242 const_value[i].f32 = active_state->border_color[swizzle[i]]; 243 break; 244 default: 245 unreachable("Unexpected swizzle value"); 246 } 247 } 248 249 return nir_build_imm(b, ndest_comp, 32, const_value); 250 } 251 252 static nir_tex_instr * 253 create_txf_from_tex(nir_builder *b, nir_tex_instr *tex) 254 { 255 nir_tex_instr *txf; 256 257 unsigned num_srcs = 0; 258 for (unsigned i = 0; i < tex->num_srcs; i++) { 259 if (tex->src[i].src_type == nir_tex_src_texture_deref || 260 tex->src[i].src_type == nir_tex_src_texture_offset || 261 tex->src[i].src_type == nir_tex_src_texture_handle) 262 num_srcs++; 263 } 264 265 txf = nir_tex_instr_create(b->shader, num_srcs); 266 txf->op = nir_texop_txf; 267 txf->coord_components = tex->coord_components; 268 txf->sampler_dim = tex->sampler_dim; 269 txf->is_array = tex->is_array; 270 txf->is_shadow = tex->is_shadow; 271 txf->is_new_style_shadow = tex->is_new_style_shadow; 272 txf->texture_index = tex->texture_index; 273 txf->sampler_index = tex->sampler_index; 274 txf->dest_type = tex->dest_type; 275 276 unsigned idx = 0; 277 for (unsigned i = 0; i < tex->num_srcs; i++) { 278 if (tex->src[i].src_type == nir_tex_src_texture_deref || 279 tex->src[i].src_type == nir_tex_src_texture_offset || 280 tex->src[i].src_type == nir_tex_src_texture_handle) { 281 nir_src_copy(&txf->src[idx].src, &tex->src[i].src); 282 txf->src[idx].src_type = tex->src[i].src_type; 283 idx++; 284 } 285 } 286 287 nir_ssa_dest_init(&txf->instr, &txf->dest, 288 nir_tex_instr_dest_size(txf), 32, NULL); 289 nir_builder_instr_insert(b, &txf->instr); 290 291 return txf; 292 } 293 294 static nir_ssa_def * 295 load_texel(nir_builder *b, nir_tex_instr *tex, wrap_lower_param_t *params) 296 { 297 nir_ssa_def *texcoord = NULL; 298 299 /* Put coordinates back together */ 300 switch (tex->coord_components) { 301 case 1: 302 texcoord = params->wrap[0].coords; 303 break; 304 case 2: 305 texcoord = nir_vec2(b, params->wrap[0].coords, params->wrap[1].coords); 306 break; 307 case 3: 308 texcoord = nir_vec3(b, params->wrap[0].coords, params->wrap[1].coords, params->wrap[2].coords); 309 break; 310 default: 311 ; 312 } 313 314 texcoord = nir_f2i32(b, texcoord); 315 316 nir_tex_instr *load = create_txf_from_tex(b, tex); 317 nir_tex_instr_add_src(load, nir_tex_src_lod, nir_src_for_ssa(params->lod)); 318 nir_tex_instr_add_src(load, nir_tex_src_coord, nir_src_for_ssa(texcoord)); 319 b->cursor = nir_after_instr(&load->instr); 320 return &load->dest.ssa; 321 } 322 323 typedef struct { 324 dxil_wrap_sampler_state *aws; 325 float max_bias; 326 nir_ssa_def *size; 327 int ncoord_comp; 328 } lod_params; 329 330 static nir_ssa_def * 331 evalute_active_lod(nir_builder *b, nir_tex_instr *tex, lod_params *params) 332 { 333 static nir_ssa_def *lod = NULL; 334 335 /* Later we use min_lod for clamping the LOD to a legal value */ 336 float min_lod = MAX2(params->aws->min_lod, 0.0f); 337 338 /* Evaluate the LOD to be used for the texel fetch */ 339 if (unlikely(tex->op == nir_texop_txl)) { 340 int lod_index = nir_tex_instr_src_index(tex, nir_tex_src_lod); 341 /* if we have an explicite LOD, take it */ 342 lod = tex->src[lod_index].src.ssa; 343 } else if (unlikely(tex->op == nir_texop_txd)) { 344 int ddx_index = nir_tex_instr_src_index(tex, nir_tex_src_ddx); 345 int ddy_index = nir_tex_instr_src_index(tex, nir_tex_src_ddy); 346 assert(ddx_index >= 0 && ddy_index >= 0); 347 348 nir_ssa_def *grad = nir_fmax(b, 349 tex->src[ddx_index].src.ssa, 350 tex->src[ddy_index].src.ssa); 351 352 nir_ssa_def *r = nir_fmul(b, grad, nir_i2f32(b, params->size)); 353 nir_ssa_def *rho = nir_channel(b, r, 0); 354 for (int i = 1; i < params->ncoord_comp; ++i) 355 rho = nir_fmax(b, rho, nir_channel(b, r, i)); 356 lod = nir_flog2(b, rho); 357 } else if (b->shader->info.stage == MESA_SHADER_FRAGMENT){ 358 lod = dx_get_texture_lod(b, tex); 359 } else { 360 /* Only fragment shaders provide the gradient information to evaluate a LOD, 361 * so force 0 otherwise */ 362 lod = nir_imm_float(b, 0.0); 363 } 364 365 /* Evaluate bias according to OpenGL (4.6 (Compatibility Profile) October 22, 2019), 366 * sec. 8.14.1, eq. (8.9) 367 * 368 * lod' = lambda + CLAMP(bias_texobj + bias_texunit + bias_shader) 369 * 370 * bias_texobj is the value of TEXTURE_LOD_BIAS for the bound texture object. ... 371 * bias_textunt is the value of TEXTURE_LOD_BIAS for the current texture unit, ... 372 * bias shader is the value of the optional bias parameter in the texture 373 * lookup functions available to fragment shaders. ... The sum of these values 374 * is clamped to the range [bias_max, bias_max] where bias_max is the value 375 * of the implementation defined constant MAX_TEXTURE_LOD_BIAS. 376 * In core contexts the value bias_texunit is dropped from above equation. 377 * 378 * Gallium provides the value lod_bias as the sum of bias_texobj and bias_texunit 379 * in compatibility contexts and as bias_texobj in core contexts, hence the 380 * implementation here is the same in both cases. 381 */ 382 nir_ssa_def *lod_bias = nir_imm_float(b, params->aws->lod_bias); 383 384 if (unlikely(tex->op == nir_texop_txb)) { 385 int bias_index = nir_tex_instr_src_index(tex, nir_tex_src_bias); 386 lod_bias = nir_fadd(b, lod_bias, tex->src[bias_index].src.ssa); 387 } 388 389 lod = nir_fadd(b, lod, nir_fclamp(b, lod_bias, 390 nir_imm_float(b, -params->max_bias), 391 nir_imm_float(b, params->max_bias))); 392 393 /* Clamp lod according to ibid. eq. (8.10) */ 394 lod = nir_fmax(b, lod, nir_imm_float(b, min_lod)); 395 396 /* If the max lod is > max_bias = log2(max_texture_size), the lod will be clamped 397 * by the number of levels, no need to clamp it againt the max_lod first. */ 398 if (params->aws->max_lod <= params->max_bias) 399 lod = nir_fmin(b, lod, nir_imm_float(b, params->aws->max_lod)); 400 401 /* Pick nearest LOD */ 402 lod = nir_f2i32(b, nir_fround_even(b, lod)); 403 404 /* cap actual lod by number of available levels */ 405 return nir_imin(b, lod, nir_imm_int(b, params->aws->last_level)); 406 } 407 408 typedef struct { 409 dxil_wrap_sampler_state *wrap_states; 410 dxil_texture_swizzle_state *tex_swizzles; 411 float max_bias; 412 } sampler_states; 413 414 415 static nir_ssa_def * 416 lower_sample_to_txf_for_integer_tex_impl(nir_builder *b, nir_instr *instr, 417 void *options) 418 { 419 sampler_states *states = (sampler_states *)options; 420 wrap_lower_param_t params = {0}; 421 422 nir_tex_instr *tex = nir_instr_as_tex(instr); 423 dxil_wrap_sampler_state *active_wrap_state = &states->wrap_states[tex->sampler_index]; 424 425 b->cursor = nir_before_instr(instr); 426 427 int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord); 428 nir_ssa_def *old_coord = tex->src[coord_index].src.ssa; 429 params.ncoord_comp = tex->coord_components; 430 if (tex->is_array) 431 params.ncoord_comp -= 1; 432 433 /* This helper to get the texture size always uses LOD 0, and DirectX doesn't support 434 * giving another LOD when querying the texture size */ 435 nir_ssa_def *size0 = nir_get_texture_size(b, tex); 436 437 params.lod = nir_imm_int(b, 0); 438 439 if (active_wrap_state->last_level > 0) { 440 lod_params p = { 441 .aws = active_wrap_state, 442 .max_bias = states->max_bias, 443 .size = size0, 444 .ncoord_comp = params.ncoord_comp 445 }; 446 params.lod = evalute_active_lod(b, tex, &p); 447 448 /* Evaluate actual level size*/ 449 params.size = nir_i2f32(b, nir_imax(b, nir_ishr(b, size0, params.lod), 450 nir_imm_int(b, 1))); 451 } else { 452 params.size = nir_i2f32(b, size0); 453 } 454 455 nir_ssa_def *new_coord = old_coord; 456 if (!active_wrap_state->is_nonnormalized_coords) { 457 /* Evaluate the integer lookup coordinates for the requested LOD, don't touch the 458 * array index */ 459 if (!tex->is_array) { 460 new_coord = nir_fmul(b, params.size, old_coord); 461 } else { 462 nir_ssa_def *array_index = nir_channel(b, old_coord, params.ncoord_comp); 463 int mask = (1 << params.ncoord_comp) - 1; 464 nir_ssa_def *coord = nir_fmul(b, nir_channels(b, params.size, mask), 465 nir_channels(b, old_coord, mask)); 466 switch (params.ncoord_comp) { 467 case 1: 468 new_coord = nir_vec2(b, coord, array_index); 469 break; 470 case 2: 471 new_coord = nir_vec3(b, nir_channel(b, coord, 0), 472 nir_channel(b, coord, 1), 473 array_index); 474 break; 475 default: 476 unreachable("unsupported number of non-array coordinates"); 477 } 478 } 479 } 480 481 nir_ssa_def *coord_help[3]; 482 for (int i = 0; i < params.ncoord_comp; ++i) 483 coord_help[i] = nir_ffloor(b, nir_channel(b, new_coord, i)); 484 485 // Note: array index needs to be rounded to nearest before clamp rather than floored 486 if (tex->is_array) 487 coord_help[params.ncoord_comp] = nir_fround_even(b, nir_channel(b, new_coord, params.ncoord_comp)); 488 489 /* Correct the texture coordinates for the offsets. */ 490 int offset_index = nir_tex_instr_src_index(tex, nir_tex_src_offset); 491 if (offset_index >= 0) { 492 nir_ssa_def *offset = tex->src[offset_index].src.ssa; 493 for (int i = 0; i < params.ncoord_comp; ++i) 494 coord_help[i] = nir_fadd(b, coord_help[i], nir_i2f32(b, nir_channel(b, offset, i))); 495 } 496 497 nir_ssa_def *use_border_color = nir_imm_false(b); 498 499 if (!active_wrap_state->skip_boundary_conditions) { 500 501 for (int i = 0; i < params.ncoord_comp; ++i) { 502 params.wrap[i] = wrap_coords(b, coord_help[i], active_wrap_state->wrap[i], nir_channel(b, params.size, i)); 503 use_border_color = nir_ior(b, use_border_color, params.wrap[i].use_border_color); 504 } 505 506 if (tex->is_array) 507 params.wrap[params.ncoord_comp] = 508 wrap_coords(b, coord_help[params.ncoord_comp], 509 PIPE_TEX_WRAP_CLAMP_TO_EDGE, 510 nir_i2f32(b, nir_channel(b, size0, params.ncoord_comp))); 511 } else { 512 /* When we emulate a cube map by using a texture array, the coordinates are always 513 * in range, and we don't have to take care of boundary conditions */ 514 for (unsigned i = 0; i < 3; ++i) { 515 params.wrap[i].coords = coord_help[i]; 516 params.wrap[i].use_border_color = nir_imm_false(b); 517 } 518 } 519 520 const dxil_texture_swizzle_state one2one = { 521 PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W 522 }; 523 524 nir_if *border_if = nir_push_if(b, use_border_color); 525 const dxil_texture_swizzle_state *swizzle = states->tex_swizzles ? 526 &states->tex_swizzles[tex->sampler_index]: 527 &one2one; 528 529 nir_ssa_def *border_color = load_bordercolor(b, tex, active_wrap_state, swizzle); 530 nir_if *border_else = nir_push_else(b, border_if); 531 nir_ssa_def *sampler_color = load_texel(b, tex, ¶ms); 532 nir_pop_if(b, border_else); 533 534 return nir_if_phi(b, border_color, sampler_color); 535 } 536 537 /* Sampling from integer textures is not allowed in DirectX, so we have 538 * to use texel fetches. For this we have to scale the coordiantes 539 * to be integer based, and evaluate the LOD the texel fetch has to be 540 * applied on, and take care of the boundary conditions . 541 */ 542 bool 543 dxil_lower_sample_to_txf_for_integer_tex(nir_shader *s, 544 dxil_wrap_sampler_state *wrap_states, 545 dxil_texture_swizzle_state *tex_swizzles, 546 float max_bias) 547 { 548 sampler_states states = {wrap_states, tex_swizzles, max_bias}; 549 550 bool result = 551 nir_shader_lower_instructions(s, 552 lower_sample_to_txf_for_integer_tex_filter, 553 lower_sample_to_txf_for_integer_tex_impl, 554 &states); 555 return result; 556 } 557