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