1 /*
2 * Copyright © 2021 Collabora Ltd.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "genxml/gen_macros.h"
7
8 #include "panvk_device.h"
9 #include "panvk_entrypoints.h"
10 #include "panvk_sampler.h"
11
12 #include "pan_encoder.h"
13 #include "pan_format.h"
14
15 #include "vk_format.h"
16 #include "vk_log.h"
17
18 static enum mali_mipmap_mode
panvk_translate_sampler_mipmap_mode(VkSamplerMipmapMode mode)19 panvk_translate_sampler_mipmap_mode(VkSamplerMipmapMode mode)
20 {
21 switch (mode) {
22 case VK_SAMPLER_MIPMAP_MODE_NEAREST:
23 return MALI_MIPMAP_MODE_NEAREST;
24 case VK_SAMPLER_MIPMAP_MODE_LINEAR:
25 return MALI_MIPMAP_MODE_TRILINEAR;
26 default:
27 unreachable("Invalid mipmap mode");
28 }
29 }
30
31 static unsigned
panvk_translate_sampler_address_mode(VkSamplerAddressMode mode)32 panvk_translate_sampler_address_mode(VkSamplerAddressMode mode)
33 {
34 switch (mode) {
35 case VK_SAMPLER_ADDRESS_MODE_REPEAT:
36 return MALI_WRAP_MODE_REPEAT;
37 case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
38 return MALI_WRAP_MODE_MIRRORED_REPEAT;
39 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
40 return MALI_WRAP_MODE_CLAMP_TO_EDGE;
41 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:
42 return MALI_WRAP_MODE_CLAMP_TO_BORDER;
43 case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
44 return MALI_WRAP_MODE_MIRRORED_CLAMP_TO_EDGE;
45 default:
46 unreachable("Invalid wrap");
47 }
48 }
49
50 static enum mali_func
panvk_translate_sampler_compare_func(const VkSamplerCreateInfo * pCreateInfo)51 panvk_translate_sampler_compare_func(const VkSamplerCreateInfo *pCreateInfo)
52 {
53 if (!pCreateInfo->compareEnable)
54 return MALI_FUNC_NEVER;
55
56 return panfrost_flip_compare_func((enum mali_func)pCreateInfo->compareOp);
57 }
58
59 #if PAN_ARCH == 7
60 static void
panvk_afbc_reswizzle_border_color(VkClearColorValue * border_color,VkFormat fmt)61 panvk_afbc_reswizzle_border_color(VkClearColorValue *border_color, VkFormat fmt)
62 {
63 /* Doing border color reswizzle implies disabling support for
64 * customBorderColorWithoutFormat. */
65
66 enum pipe_format pfmt = vk_format_to_pipe_format(fmt);
67 if (panfrost_format_is_yuv(pfmt) || util_format_is_depth_or_stencil(pfmt) ||
68 !panfrost_format_supports_afbc(PAN_ARCH, pfmt))
69 return;
70
71 const struct util_format_description *fdesc = util_format_description(pfmt);
72 if (fdesc->swizzle[0] == PIPE_SWIZZLE_Z &&
73 fdesc->swizzle[2] == PIPE_SWIZZLE_X) {
74 uint32_t red = border_color->uint32[0];
75
76 border_color->uint32[0] = border_color->uint32[2];
77 border_color->uint32[2] = red;
78 }
79 }
80 #endif
81
82 VKAPI_ATTR VkResult VKAPI_CALL
panvk_per_arch(CreateSampler)83 panvk_per_arch(CreateSampler)(VkDevice _device,
84 const VkSamplerCreateInfo *pCreateInfo,
85 const VkAllocationCallbacks *pAllocator,
86 VkSampler *pSampler)
87 {
88 VK_FROM_HANDLE(panvk_device, device, _device);
89 struct panvk_sampler *sampler;
90
91 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
92
93 sampler =
94 vk_sampler_create(&device->vk, pCreateInfo, pAllocator, sizeof(*sampler));
95 if (!sampler)
96 return panvk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
97
98 STATIC_ASSERT(sizeof(sampler->desc) >= pan_size(SAMPLER));
99
100 VkFormat fmt;
101 VkClearColorValue border_color =
102 vk_sampler_border_color_value(pCreateInfo, &fmt);
103
104 #if PAN_ARCH == 7
105 panvk_afbc_reswizzle_border_color(&border_color, fmt);
106 #endif
107
108 pan_pack(&sampler->desc, SAMPLER, cfg) {
109 cfg.magnify_nearest = pCreateInfo->magFilter == VK_FILTER_NEAREST;
110 cfg.minify_nearest = pCreateInfo->minFilter == VK_FILTER_NEAREST;
111 cfg.mipmap_mode =
112 panvk_translate_sampler_mipmap_mode(pCreateInfo->mipmapMode);
113 cfg.normalized_coordinates = !pCreateInfo->unnormalizedCoordinates;
114 cfg.clamp_integer_array_indices = false;
115
116 /* Normalized float texture coordinates are rounded to fixed-point
117 * before rounding to integer coordinates. When round_to_nearest_even is
118 * enabled with VK_FILTER_NEAREST, the upper 2^-9 float coordinates in
119 * each texel are rounded up to the next texel.
120 *
121 * The Vulkan 1.4.304 spec seems to allow both rounding modes for all
122 * filters, but a CTS bug[1] causes test failures when round-to-nearest
123 * is used with VK_FILTER_NEAREST.
124 *
125 * Regardless, disabling round_to_nearest_even for NEAREST filters
126 * is a desirable precision improvement.
127 *
128 * [1]: https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/5547
129 */
130 if (pCreateInfo->minFilter == VK_FILTER_NEAREST &&
131 pCreateInfo->magFilter == VK_FILTER_NEAREST)
132 cfg.round_to_nearest_even = false;
133
134 cfg.lod_bias = pCreateInfo->mipLodBias;
135 cfg.minimum_lod = pCreateInfo->minLod;
136 cfg.maximum_lod = pCreateInfo->maxLod;
137 cfg.wrap_mode_s =
138 panvk_translate_sampler_address_mode(pCreateInfo->addressModeU);
139 cfg.wrap_mode_t =
140 panvk_translate_sampler_address_mode(pCreateInfo->addressModeV);
141
142 /* "
143 * When unnormalizedCoordinates is VK_TRUE, images the sampler is used
144 * with in the shader have the following requirements:
145 * - The viewType must be either VK_IMAGE_VIEW_TYPE_1D or
146 * VK_IMAGE_VIEW_TYPE_2D.
147 * - The image view must have a single layer and a single mip level.
148 * "
149 *
150 * This means addressModeW should be ignored. We pick a default value
151 * that works for normalized_coordinates=false.
152 */
153 cfg.wrap_mode_r =
154 pCreateInfo->unnormalizedCoordinates
155 ? MALI_WRAP_MODE_CLAMP_TO_EDGE
156 : panvk_translate_sampler_address_mode(pCreateInfo->addressModeW);
157 cfg.compare_function = panvk_translate_sampler_compare_func(pCreateInfo);
158 cfg.border_color_r = border_color.uint32[0];
159 cfg.border_color_g = border_color.uint32[1];
160 cfg.border_color_b = border_color.uint32[2];
161 cfg.border_color_a = border_color.uint32[3];
162
163 if (pCreateInfo->anisotropyEnable && pCreateInfo->maxAnisotropy > 1) {
164 cfg.maximum_anisotropy = pCreateInfo->maxAnisotropy;
165 cfg.lod_algorithm = MALI_LOD_ALGORITHM_ANISOTROPIC;
166 }
167
168 #if PAN_ARCH >= 10
169 switch (sampler->vk.reduction_mode) {
170 case VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE:
171 cfg.reduction_mode = MALI_REDUCTION_MODE_AVERAGE;
172 break;
173 case VK_SAMPLER_REDUCTION_MODE_MIN:
174 cfg.reduction_mode = MALI_REDUCTION_MODE_MINIMUM;
175 break;
176 case VK_SAMPLER_REDUCTION_MODE_MAX:
177 cfg.reduction_mode = MALI_REDUCTION_MODE_MAXIMUM;
178 break;
179 default:
180 unreachable("Invalid reduction mode");
181 }
182 #endif
183 }
184
185 *pSampler = panvk_sampler_to_handle(sampler);
186 return VK_SUCCESS;
187 }
188
189 VKAPI_ATTR void VKAPI_CALL
panvk_per_arch(DestroySampler)190 panvk_per_arch(DestroySampler)(VkDevice _device, VkSampler _sampler,
191 const VkAllocationCallbacks *pAllocator)
192 {
193 VK_FROM_HANDLE(panvk_device, device, _device);
194 VK_FROM_HANDLE(panvk_sampler, sampler, _sampler);
195
196 if (!sampler)
197 return;
198
199 vk_sampler_destroy(&device->vk, pAllocator, &sampler->vk);
200 }
201