xref: /aosp_15_r20/external/mesa3d/src/intel/vulkan_hasvk/genX_state.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2015 Intel 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  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 
30 #include "anv_private.h"
31 
32 #include "common/intel_aux_map.h"
33 #include "common/intel_sample_positions.h"
34 #include "common/intel_pixel_hash.h"
35 #include "genxml/gen_macros.h"
36 #include "genxml/genX_pack.h"
37 
38 #include "vk_standard_sample_locations.h"
39 #include "vk_util.h"
40 #include "vk_format.h"
41 
42 static VkResult
init_render_queue_state(struct anv_queue * queue)43 init_render_queue_state(struct anv_queue *queue)
44 {
45    struct anv_device *device = queue->device;
46    uint32_t cmds[128];
47    struct anv_batch batch = {
48       .start = cmds,
49       .next = cmds,
50       .end = (void *) cmds + sizeof(cmds),
51    };
52 
53    anv_batch_emit(&batch, GENX(PIPELINE_SELECT), ps) {
54       ps.PipelineSelection = _3D;
55    }
56 
57    anv_batch_emit(&batch, GENX(3DSTATE_AA_LINE_PARAMETERS), aa);
58 
59    anv_batch_emit(&batch, GENX(3DSTATE_DRAWING_RECTANGLE), rect) {
60       rect.ClippedDrawingRectangleYMin = 0;
61       rect.ClippedDrawingRectangleXMin = 0;
62       rect.ClippedDrawingRectangleYMax = UINT16_MAX;
63       rect.ClippedDrawingRectangleXMax = UINT16_MAX;
64       rect.DrawingRectangleOriginY = 0;
65       rect.DrawingRectangleOriginX = 0;
66    }
67 
68 #if GFX_VER >= 8
69    anv_batch_emit(&batch, GENX(3DSTATE_WM_CHROMAKEY), ck);
70 
71    genX(emit_sample_pattern)(&batch, NULL);
72 
73    /* The BDW+ docs describe how to use the 3DSTATE_WM_HZ_OP instruction in the
74     * section titled, "Optimized Depth Buffer Clear and/or Stencil Buffer
75     * Clear." It mentions that the packet overrides GPU state for the clear
76     * operation and needs to be reset to 0s to clear the overrides. Depending
77     * on the kernel, we may not get a context with the state for this packet
78     * zeroed. Do it ourselves just in case. We've observed this to prevent a
79     * number of GPU hangs on ICL.
80     */
81    anv_batch_emit(&batch, GENX(3DSTATE_WM_HZ_OP), hzp);
82 #endif
83 
84    /* Set the "CONSTANT_BUFFER Address Offset Disable" bit, so
85     * 3DSTATE_CONSTANT_XS buffer 0 is an absolute address.
86     *
87     * This is only safe on kernels with context isolation support.
88     */
89    if (GFX_VER >= 8 && device->physical->info.has_context_isolation) {
90 #if GFX_VER == 8
91       anv_batch_write_reg(&batch, GENX(INSTPM), instpm) {
92          instpm.CONSTANT_BUFFERAddressOffsetDisable = true;
93          instpm.CONSTANT_BUFFERAddressOffsetDisableMask = true;
94       }
95 #endif
96    }
97 
98    anv_batch_emit(&batch, GENX(MI_BATCH_BUFFER_END), bbe);
99 
100    assert(batch.next <= batch.end);
101 
102    return anv_queue_submit_simple_batch(queue, &batch);
103 }
104 
105 void
genX(init_physical_device_state)106 genX(init_physical_device_state)(ASSERTED struct anv_physical_device *pdevice)
107 {
108    assert(pdevice->info.verx10 == GFX_VERx10);
109 
110    pdevice->cmd_emit_timestamp = genX(cmd_emit_timestamp);
111    pdevice->cmd_capture_data = genX(cmd_capture_data);
112 }
113 
114 VkResult
genX(init_device_state)115 genX(init_device_state)(struct anv_device *device)
116 {
117    VkResult res;
118 
119    device->slice_hash = (struct anv_state) { 0 };
120    for (uint32_t i = 0; i < device->queue_count; i++) {
121       struct anv_queue *queue = &device->queues[i];
122       switch (queue->family->engine_class) {
123       case INTEL_ENGINE_CLASS_RENDER:
124          res = init_render_queue_state(queue);
125          break;
126       default:
127          res = vk_error(device, VK_ERROR_INITIALIZATION_FAILED);
128          break;
129       }
130       if (res != VK_SUCCESS)
131          return res;
132    }
133 
134    return res;
135 }
136 
137 void
genX(emit_l3_config)138 genX(emit_l3_config)(struct anv_batch *batch,
139                      const struct anv_device *device,
140                      const struct intel_l3_config *cfg)
141 {
142    UNUSED const struct intel_device_info *devinfo = device->info;
143 
144 #if GFX_VER >= 8
145 
146 #define L3_ALLOCATION_REG GENX(L3CNTLREG)
147 #define L3_ALLOCATION_REG_num GENX(L3CNTLREG_num)
148 
149    anv_batch_write_reg(batch, L3_ALLOCATION_REG, l3cr) {
150       if (cfg == NULL) {
151          unreachable("Invalid L3$ config");
152       } else {
153          l3cr.SLMEnable = cfg->n[INTEL_L3P_SLM];
154          assert(cfg->n[INTEL_L3P_IS] == 0);
155          assert(cfg->n[INTEL_L3P_C] == 0);
156          assert(cfg->n[INTEL_L3P_T] == 0);
157          l3cr.URBAllocation = cfg->n[INTEL_L3P_URB];
158          l3cr.ROAllocation = cfg->n[INTEL_L3P_RO];
159          l3cr.DCAllocation = cfg->n[INTEL_L3P_DC];
160          l3cr.AllAllocation = cfg->n[INTEL_L3P_ALL];
161       }
162    }
163 
164 #else /* GFX_VER < 8 */
165 
166    const bool has_dc = cfg->n[INTEL_L3P_DC] || cfg->n[INTEL_L3P_ALL];
167    const bool has_is = cfg->n[INTEL_L3P_IS] || cfg->n[INTEL_L3P_RO] ||
168                        cfg->n[INTEL_L3P_ALL];
169    const bool has_c = cfg->n[INTEL_L3P_C] || cfg->n[INTEL_L3P_RO] ||
170                       cfg->n[INTEL_L3P_ALL];
171    const bool has_t = cfg->n[INTEL_L3P_T] || cfg->n[INTEL_L3P_RO] ||
172                       cfg->n[INTEL_L3P_ALL];
173 
174    assert(!cfg->n[INTEL_L3P_ALL]);
175 
176    /* When enabled SLM only uses a portion of the L3 on half of the banks,
177     * the matching space on the remaining banks has to be allocated to a
178     * client (URB for all validated configurations) set to the
179     * lower-bandwidth 2-bank address hashing mode.
180     */
181    const bool urb_low_bw = cfg->n[INTEL_L3P_SLM] && devinfo->platform != INTEL_PLATFORM_BYT;
182    assert(!urb_low_bw || cfg->n[INTEL_L3P_URB] == cfg->n[INTEL_L3P_SLM]);
183 
184    /* Minimum number of ways that can be allocated to the URB. */
185    const unsigned n0_urb = devinfo->platform == INTEL_PLATFORM_BYT ? 32 : 0;
186    assert(cfg->n[INTEL_L3P_URB] >= n0_urb);
187 
188    anv_batch_write_reg(batch, GENX(L3SQCREG1), l3sqc) {
189       l3sqc.ConvertDC_UC = !has_dc;
190       l3sqc.ConvertIS_UC = !has_is;
191       l3sqc.ConvertC_UC = !has_c;
192       l3sqc.ConvertT_UC = !has_t;
193 #if GFX_VERx10 == 75
194       l3sqc.L3SQGeneralPriorityCreditInitialization = SQGPCI_DEFAULT;
195 #else
196       l3sqc.L3SQGeneralPriorityCreditInitialization =
197          devinfo->platform == INTEL_PLATFORM_BYT ? BYT_SQGPCI_DEFAULT : SQGPCI_DEFAULT;
198 #endif
199       l3sqc.L3SQHighPriorityCreditInitialization = SQHPCI_DEFAULT;
200    }
201 
202    anv_batch_write_reg(batch, GENX(L3CNTLREG2), l3cr2) {
203       l3cr2.SLMEnable = cfg->n[INTEL_L3P_SLM];
204       l3cr2.URBLowBandwidth = urb_low_bw;
205       l3cr2.URBAllocation = cfg->n[INTEL_L3P_URB] - n0_urb;
206 #if !GFX_VERx10 == 75
207       l3cr2.ALLAllocation = cfg->n[INTEL_L3P_ALL];
208 #endif
209       l3cr2.ROAllocation = cfg->n[INTEL_L3P_RO];
210       l3cr2.DCAllocation = cfg->n[INTEL_L3P_DC];
211    }
212 
213    anv_batch_write_reg(batch, GENX(L3CNTLREG3), l3cr3) {
214       l3cr3.ISAllocation = cfg->n[INTEL_L3P_IS];
215       l3cr3.ISLowBandwidth = 0;
216       l3cr3.CAllocation = cfg->n[INTEL_L3P_C];
217       l3cr3.CLowBandwidth = 0;
218       l3cr3.TAllocation = cfg->n[INTEL_L3P_T];
219       l3cr3.TLowBandwidth = 0;
220    }
221 
222 #if GFX_VERx10 == 75
223    if (device->physical->cmd_parser_version >= 4) {
224       /* Enable L3 atomics on HSW if we have a DC partition, otherwise keep
225        * them disabled to avoid crashing the system hard.
226        */
227       anv_batch_write_reg(batch, GENX(SCRATCH1), s1) {
228          s1.L3AtomicDisable = !has_dc;
229       }
230       anv_batch_write_reg(batch, GENX(CHICKEN3), c3) {
231          c3.L3AtomicDisableMask = true;
232          c3.L3AtomicDisable = !has_dc;
233       }
234    }
235 #endif /* GFX_VERx10 == 75 */
236 
237 #endif /* GFX_VER < 8 */
238 }
239 
240 void
genX(emit_multisample)241 genX(emit_multisample)(struct anv_batch *batch, uint32_t samples,
242                        const struct vk_sample_locations_state *sl)
243 {
244    if (sl != NULL) {
245       assert(sl->per_pixel == samples);
246       assert(sl->grid_size.width == 1);
247       assert(sl->grid_size.height == 1);
248    } else {
249       sl = vk_standard_sample_locations_state(samples);
250    }
251 
252    anv_batch_emit(batch, GENX(3DSTATE_MULTISAMPLE), ms) {
253       ms.NumberofMultisamples       = __builtin_ffs(samples) - 1;
254 
255       ms.PixelLocation              = CENTER;
256 #if GFX_VER < 8
257       switch (samples) {
258       case 1:
259          INTEL_SAMPLE_POS_1X_ARRAY(ms.Sample, sl->locations);
260          break;
261       case 2:
262          INTEL_SAMPLE_POS_2X_ARRAY(ms.Sample, sl->locations);
263          break;
264       case 4:
265          INTEL_SAMPLE_POS_4X_ARRAY(ms.Sample, sl->locations);
266          break;
267       case 8:
268          INTEL_SAMPLE_POS_8X_ARRAY(ms.Sample, sl->locations);
269          break;
270       default:
271             break;
272       }
273 #endif
274    }
275 }
276 
277 #if GFX_VER >= 8
278 void
genX(emit_sample_pattern)279 genX(emit_sample_pattern)(struct anv_batch *batch,
280                           const struct vk_sample_locations_state *sl)
281 {
282    assert(sl == NULL || sl->grid_size.width == 1);
283    assert(sl == NULL || sl->grid_size.height == 1);
284 
285    /* See the Vulkan 1.0 spec Table 24.1 "Standard sample locations" and
286     * VkPhysicalDeviceFeatures::standardSampleLocations.
287     */
288    anv_batch_emit(batch, GENX(3DSTATE_SAMPLE_PATTERN), sp) {
289       /* The Skylake PRM Vol. 2a "3DSTATE_SAMPLE_PATTERN" says:
290        *
291        *    "When programming the sample offsets (for NUMSAMPLES_4 or _8
292        *    and MSRASTMODE_xxx_PATTERN), the order of the samples 0 to 3
293        *    (or 7 for 8X, or 15 for 16X) must have monotonically increasing
294        *    distance from the pixel center. This is required to get the
295        *    correct centroid computation in the device."
296        *
297        * However, the Vulkan spec seems to require that the the samples occur
298        * in the order provided through the API. The standard sample patterns
299        * have the above property that they have monotonically increasing
300        * distances from the center but client-provided ones do not. As long as
301        * this only affects centroid calculations as the docs say, we should be
302        * ok because OpenGL and Vulkan only require that the centroid be some
303        * lit sample and that it's the same for all samples in a pixel; they
304        * have no requirement that it be the one closest to center.
305        */
306       for (uint32_t i = 1; i <= 8; i *= 2) {
307          switch (i) {
308          case VK_SAMPLE_COUNT_1_BIT:
309             if (sl && sl->per_pixel == i) {
310                INTEL_SAMPLE_POS_1X_ARRAY(sp._1xSample, sl->locations);
311             } else {
312                INTEL_SAMPLE_POS_1X(sp._1xSample);
313             }
314             break;
315          case VK_SAMPLE_COUNT_2_BIT:
316             if (sl && sl->per_pixel == i) {
317                INTEL_SAMPLE_POS_2X_ARRAY(sp._2xSample, sl->locations);
318             } else {
319                INTEL_SAMPLE_POS_2X(sp._2xSample);
320             }
321             break;
322          case VK_SAMPLE_COUNT_4_BIT:
323             if (sl && sl->per_pixel == i) {
324                INTEL_SAMPLE_POS_4X_ARRAY(sp._4xSample, sl->locations);
325             } else {
326                INTEL_SAMPLE_POS_4X(sp._4xSample);
327             }
328             break;
329          case VK_SAMPLE_COUNT_8_BIT:
330             if (sl && sl->per_pixel == i) {
331                INTEL_SAMPLE_POS_8X_ARRAY(sp._8xSample, sl->locations);
332             } else {
333                INTEL_SAMPLE_POS_8X(sp._8xSample);
334             }
335             break;
336          default:
337             unreachable("Invalid sample count");
338          }
339       }
340    }
341 }
342 #endif
343 
344 static uint32_t
vk_to_intel_tex_filter(VkFilter filter,bool anisotropyEnable)345 vk_to_intel_tex_filter(VkFilter filter, bool anisotropyEnable)
346 {
347    switch (filter) {
348    default:
349       unreachable("Invalid filter");
350    case VK_FILTER_NEAREST:
351       return anisotropyEnable ? MAPFILTER_ANISOTROPIC : MAPFILTER_NEAREST;
352    case VK_FILTER_LINEAR:
353       return anisotropyEnable ? MAPFILTER_ANISOTROPIC : MAPFILTER_LINEAR;
354    }
355 }
356 
357 static uint32_t
vk_to_intel_max_anisotropy(float ratio)358 vk_to_intel_max_anisotropy(float ratio)
359 {
360    return (CLAMP(ratio, 2, 16) - 2) / 2;
361 }
362 
363 static const uint32_t vk_to_intel_mipmap_mode[] = {
364    [VK_SAMPLER_MIPMAP_MODE_NEAREST]          = MIPFILTER_NEAREST,
365    [VK_SAMPLER_MIPMAP_MODE_LINEAR]           = MIPFILTER_LINEAR
366 };
367 
368 static const uint32_t vk_to_intel_tex_address[] = {
369    [VK_SAMPLER_ADDRESS_MODE_REPEAT]          = TCM_WRAP,
370    [VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT] = TCM_MIRROR,
371    [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE]   = TCM_CLAMP,
372    [VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE] = TCM_MIRROR_ONCE,
373    [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER] = TCM_CLAMP_BORDER,
374 };
375 
376 /* Vulkan specifies the result of shadow comparisons as:
377  *     1     if   ref <op> texel,
378  *     0     otherwise.
379  *
380  * The hardware does:
381  *     0     if texel <op> ref,
382  *     1     otherwise.
383  *
384  * So, these look a bit strange because there's both a negation
385  * and swapping of the arguments involved.
386  */
387 static const uint32_t vk_to_intel_shadow_compare_op[] = {
388    [VK_COMPARE_OP_NEVER]                        = PREFILTEROP_ALWAYS,
389    [VK_COMPARE_OP_LESS]                         = PREFILTEROP_LEQUAL,
390    [VK_COMPARE_OP_EQUAL]                        = PREFILTEROP_NOTEQUAL,
391    [VK_COMPARE_OP_LESS_OR_EQUAL]                = PREFILTEROP_LESS,
392    [VK_COMPARE_OP_GREATER]                      = PREFILTEROP_GEQUAL,
393    [VK_COMPARE_OP_NOT_EQUAL]                    = PREFILTEROP_EQUAL,
394    [VK_COMPARE_OP_GREATER_OR_EQUAL]             = PREFILTEROP_GREATER,
395    [VK_COMPARE_OP_ALWAYS]                       = PREFILTEROP_NEVER,
396 };
397 
genX(CreateSampler)398 VkResult genX(CreateSampler)(
399     VkDevice                                    _device,
400     const VkSamplerCreateInfo*                  pCreateInfo,
401     const VkAllocationCallbacks*                pAllocator,
402     VkSampler*                                  pSampler)
403 {
404    ANV_FROM_HANDLE(anv_device, device, _device);
405    struct anv_sampler *sampler;
406 
407    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
408 
409    sampler = vk_object_zalloc(&device->vk, pAllocator, sizeof(*sampler),
410                               VK_OBJECT_TYPE_SAMPLER);
411    if (!sampler)
412       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
413 
414    sampler->n_planes = 1;
415 
416    uint32_t border_color_stride = GFX_VERx10 == 75 ? 512 : 64;
417    uint32_t border_color_offset;
418    ASSERTED bool has_custom_color = false;
419    if (pCreateInfo->borderColor <= VK_BORDER_COLOR_INT_OPAQUE_WHITE) {
420       border_color_offset = device->border_colors.offset +
421                             pCreateInfo->borderColor *
422                             border_color_stride;
423    } else {
424       assert(GFX_VER >= 8);
425       sampler->custom_border_color =
426          anv_state_reserved_pool_alloc(&device->custom_border_colors);
427       border_color_offset = sampler->custom_border_color.offset;
428    }
429 
430    const struct vk_format_ycbcr_info *ycbcr_info = NULL;
431    vk_foreach_struct_const(ext, pCreateInfo->pNext) {
432       switch (ext->sType) {
433       case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO: {
434          VkSamplerYcbcrConversionInfo *pSamplerConversion =
435             (VkSamplerYcbcrConversionInfo *) ext;
436          VK_FROM_HANDLE(vk_ycbcr_conversion, conversion,
437                         pSamplerConversion->conversion);
438 
439          /* Ignore conversion for non-YUV formats. This fulfills a requirement
440           * for clients that want to utilize same code path for images with
441           * external formats (VK_FORMAT_UNDEFINED) and "regular" RGBA images
442           * where format is known.
443           */
444          if (conversion == NULL)
445             break;
446 
447          ycbcr_info = vk_format_get_ycbcr_info(conversion->state.format);
448          if (ycbcr_info == NULL)
449             break;
450 
451          sampler->n_planes = ycbcr_info->n_planes;
452          sampler->conversion = conversion;
453          break;
454       }
455       case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT: {
456          VkSamplerCustomBorderColorCreateInfoEXT *custom_border_color =
457             (VkSamplerCustomBorderColorCreateInfoEXT *) ext;
458          if (sampler->custom_border_color.map == NULL)
459             break;
460 
461          union isl_color_value color = { .u32 = {
462             custom_border_color->customBorderColor.uint32[0],
463             custom_border_color->customBorderColor.uint32[1],
464             custom_border_color->customBorderColor.uint32[2],
465             custom_border_color->customBorderColor.uint32[3],
466          } };
467 
468          const struct anv_format *format_desc =
469             custom_border_color->format != VK_FORMAT_UNDEFINED ?
470             anv_get_format(custom_border_color->format) : NULL;
471 
472          /* For formats with a swizzle, it does not carry over to the sampler
473           * for border colors, so we need to do the swizzle ourselves here.
474           */
475          if (format_desc && format_desc->n_planes == 1 &&
476              !isl_swizzle_is_identity(format_desc->planes[0].swizzle)) {
477             const struct anv_format_plane *fmt_plane = &format_desc->planes[0];
478 
479             assert(!isl_format_has_int_channel(fmt_plane->isl_format));
480             color = isl_color_value_swizzle(color, fmt_plane->swizzle, true);
481          }
482 
483          memcpy(sampler->custom_border_color.map, color.u32, sizeof(color));
484          has_custom_color = true;
485          break;
486       }
487       case VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT:
488          break;
489       default:
490          vk_debug_ignored_stype(ext->sType);
491          break;
492       }
493    }
494 
495    assert((sampler->custom_border_color.map == NULL) || has_custom_color);
496 
497    if (device->physical->has_bindless_samplers) {
498       /* If we have bindless, allocate enough samplers.  We allocate 32 bytes
499        * for each sampler instead of 16 bytes because we want all bindless
500        * samplers to be 32-byte aligned so we don't have to use indirect
501        * sampler messages on them.
502        */
503       sampler->bindless_state =
504          anv_state_pool_alloc(&device->dynamic_state_pool,
505                               sampler->n_planes * 32, 32);
506    }
507 
508    const bool seamless_cube =
509       !(pCreateInfo->flags & VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT);
510 
511    for (unsigned p = 0; p < sampler->n_planes; p++) {
512       const bool plane_has_chroma =
513          ycbcr_info && ycbcr_info->planes[p].has_chroma;
514       const VkFilter min_filter =
515          plane_has_chroma ? sampler->conversion->state.chroma_filter : pCreateInfo->minFilter;
516       const VkFilter mag_filter =
517          plane_has_chroma ? sampler->conversion->state.chroma_filter : pCreateInfo->magFilter;
518       const bool enable_min_filter_addr_rounding = min_filter != VK_FILTER_NEAREST;
519       const bool enable_mag_filter_addr_rounding = mag_filter != VK_FILTER_NEAREST;
520       /* From Broadwell PRM, SAMPLER_STATE:
521        *   "Mip Mode Filter must be set to MIPFILTER_NONE for Planar YUV surfaces."
522        */
523       enum isl_format plane0_isl_format = sampler->conversion ?
524          anv_get_format(sampler->conversion->state.format)->planes[0].isl_format :
525          ISL_FORMAT_UNSUPPORTED;
526       const bool isl_format_is_planar_yuv =
527          plane0_isl_format != ISL_FORMAT_UNSUPPORTED &&
528          isl_format_is_yuv(plane0_isl_format) &&
529          isl_format_is_planar(plane0_isl_format);
530 
531       const uint32_t mip_filter_mode =
532          isl_format_is_planar_yuv ?
533          MIPFILTER_NONE : vk_to_intel_mipmap_mode[pCreateInfo->mipmapMode];
534 
535       struct GENX(SAMPLER_STATE) sampler_state = {
536          .SamplerDisable = false,
537          .TextureBorderColorMode = DX10OGL,
538 
539 #if GFX_VER >= 8
540          .LODPreClampMode = CLAMP_MODE_OGL,
541 #else
542          .LODPreClampEnable = CLAMP_ENABLE_OGL,
543 #endif
544 
545 #if GFX_VER == 8
546          .BaseMipLevel = 0.0,
547 #endif
548          .MipModeFilter = mip_filter_mode,
549          .MagModeFilter = vk_to_intel_tex_filter(mag_filter, pCreateInfo->anisotropyEnable),
550          .MinModeFilter = vk_to_intel_tex_filter(min_filter, pCreateInfo->anisotropyEnable),
551          .TextureLODBias = CLAMP(pCreateInfo->mipLodBias, -16, 15.996),
552          .AnisotropicAlgorithm =
553             pCreateInfo->anisotropyEnable ? EWAApproximation : LEGACY,
554          .MinLOD = CLAMP(pCreateInfo->minLod, 0, 14),
555          .MaxLOD = CLAMP(pCreateInfo->maxLod, 0, 14),
556          .ChromaKeyEnable = 0,
557          .ChromaKeyIndex = 0,
558          .ChromaKeyMode = 0,
559          .ShadowFunction =
560             vk_to_intel_shadow_compare_op[pCreateInfo->compareEnable ?
561                                         pCreateInfo->compareOp : VK_COMPARE_OP_NEVER],
562          .CubeSurfaceControlMode = seamless_cube ? OVERRIDE : PROGRAMMED,
563 
564          .BorderColorPointer = border_color_offset,
565 
566 #if GFX_VER >= 8
567          .LODClampMagnificationMode = MIPNONE,
568 #endif
569 
570          .MaximumAnisotropy = vk_to_intel_max_anisotropy(pCreateInfo->maxAnisotropy),
571          .RAddressMinFilterRoundingEnable = enable_min_filter_addr_rounding,
572          .RAddressMagFilterRoundingEnable = enable_mag_filter_addr_rounding,
573          .VAddressMinFilterRoundingEnable = enable_min_filter_addr_rounding,
574          .VAddressMagFilterRoundingEnable = enable_mag_filter_addr_rounding,
575          .UAddressMinFilterRoundingEnable = enable_min_filter_addr_rounding,
576          .UAddressMagFilterRoundingEnable = enable_mag_filter_addr_rounding,
577          .TrilinearFilterQuality = 0,
578          .NonnormalizedCoordinateEnable = pCreateInfo->unnormalizedCoordinates,
579          .TCXAddressControlMode = vk_to_intel_tex_address[pCreateInfo->addressModeU],
580          .TCYAddressControlMode = vk_to_intel_tex_address[pCreateInfo->addressModeV],
581          .TCZAddressControlMode = vk_to_intel_tex_address[pCreateInfo->addressModeW],
582       };
583 
584       GENX(SAMPLER_STATE_pack)(NULL, sampler->state[p], &sampler_state);
585 
586       if (sampler->bindless_state.map) {
587          memcpy(sampler->bindless_state.map + p * 32,
588                 sampler->state[p], GENX(SAMPLER_STATE_length) * 4);
589       }
590    }
591 
592    *pSampler = anv_sampler_to_handle(sampler);
593 
594    return VK_SUCCESS;
595 }
596