1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2024 Valve Corporation
3*61046927SAndroid Build Coastguard Worker * Copyright 2024 Alyssa Rosenzweig
4*61046927SAndroid Build Coastguard Worker * Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
5*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
6*61046927SAndroid Build Coastguard Worker */
7*61046927SAndroid Build Coastguard Worker #include "hk_sampler.h"
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Worker #include "hk_device.h"
10*61046927SAndroid Build Coastguard Worker #include "hk_entrypoints.h"
11*61046927SAndroid Build Coastguard Worker #include "hk_physical_device.h"
12*61046927SAndroid Build Coastguard Worker
13*61046927SAndroid Build Coastguard Worker #include "vk_enum_to_str.h"
14*61046927SAndroid Build Coastguard Worker #include "vk_format.h"
15*61046927SAndroid Build Coastguard Worker #include "vk_sampler.h"
16*61046927SAndroid Build Coastguard Worker
17*61046927SAndroid Build Coastguard Worker #include "asahi/genxml/agx_pack.h"
18*61046927SAndroid Build Coastguard Worker
19*61046927SAndroid Build Coastguard Worker static inline uint32_t
translate_address_mode(VkSamplerAddressMode addr_mode)20*61046927SAndroid Build Coastguard Worker translate_address_mode(VkSamplerAddressMode addr_mode)
21*61046927SAndroid Build Coastguard Worker {
22*61046927SAndroid Build Coastguard Worker #define MODE(VK, AGX_) [VK_SAMPLER_ADDRESS_MODE_##VK] = AGX_WRAP_##AGX_
23*61046927SAndroid Build Coastguard Worker static const uint8_t translate[] = {
24*61046927SAndroid Build Coastguard Worker MODE(REPEAT, REPEAT),
25*61046927SAndroid Build Coastguard Worker MODE(MIRRORED_REPEAT, MIRRORED_REPEAT),
26*61046927SAndroid Build Coastguard Worker MODE(CLAMP_TO_EDGE, CLAMP_TO_EDGE),
27*61046927SAndroid Build Coastguard Worker MODE(CLAMP_TO_BORDER, CLAMP_TO_BORDER),
28*61046927SAndroid Build Coastguard Worker MODE(MIRROR_CLAMP_TO_EDGE, MIRRORED_CLAMP_TO_EDGE),
29*61046927SAndroid Build Coastguard Worker };
30*61046927SAndroid Build Coastguard Worker #undef MODE
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker assert(addr_mode < ARRAY_SIZE(translate));
33*61046927SAndroid Build Coastguard Worker return translate[addr_mode];
34*61046927SAndroid Build Coastguard Worker }
35*61046927SAndroid Build Coastguard Worker
36*61046927SAndroid Build Coastguard Worker static uint32_t
translate_texsamp_compare_op(VkCompareOp op)37*61046927SAndroid Build Coastguard Worker translate_texsamp_compare_op(VkCompareOp op)
38*61046927SAndroid Build Coastguard Worker {
39*61046927SAndroid Build Coastguard Worker #define OP(VK, AGX_) [VK_COMPARE_OP_##VK] = AGX_COMPARE_FUNC_##AGX_
40*61046927SAndroid Build Coastguard Worker static const uint8_t translate[] = {
41*61046927SAndroid Build Coastguard Worker OP(NEVER, NEVER),
42*61046927SAndroid Build Coastguard Worker OP(LESS, LESS),
43*61046927SAndroid Build Coastguard Worker OP(EQUAL, EQUAL),
44*61046927SAndroid Build Coastguard Worker OP(LESS_OR_EQUAL, LEQUAL),
45*61046927SAndroid Build Coastguard Worker OP(GREATER, GREATER),
46*61046927SAndroid Build Coastguard Worker OP(NOT_EQUAL, NOT_EQUAL),
47*61046927SAndroid Build Coastguard Worker OP(GREATER_OR_EQUAL, GEQUAL),
48*61046927SAndroid Build Coastguard Worker OP(ALWAYS, ALWAYS),
49*61046927SAndroid Build Coastguard Worker };
50*61046927SAndroid Build Coastguard Worker #undef OP
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker assert(op < ARRAY_SIZE(translate));
53*61046927SAndroid Build Coastguard Worker return translate[op];
54*61046927SAndroid Build Coastguard Worker }
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker static enum agx_filter
translate_filter(VkFilter filter)57*61046927SAndroid Build Coastguard Worker translate_filter(VkFilter filter)
58*61046927SAndroid Build Coastguard Worker {
59*61046927SAndroid Build Coastguard Worker static_assert((enum agx_filter)VK_FILTER_NEAREST == AGX_FILTER_NEAREST);
60*61046927SAndroid Build Coastguard Worker static_assert((enum agx_filter)VK_FILTER_LINEAR == AGX_FILTER_LINEAR);
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker return (enum agx_filter)filter;
63*61046927SAndroid Build Coastguard Worker }
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker static enum agx_mip_filter
translate_mipfilter(VkSamplerMipmapMode mode)66*61046927SAndroid Build Coastguard Worker translate_mipfilter(VkSamplerMipmapMode mode)
67*61046927SAndroid Build Coastguard Worker {
68*61046927SAndroid Build Coastguard Worker switch (mode) {
69*61046927SAndroid Build Coastguard Worker case VK_SAMPLER_MIPMAP_MODE_NEAREST:
70*61046927SAndroid Build Coastguard Worker return AGX_MIP_FILTER_NEAREST;
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker case VK_SAMPLER_MIPMAP_MODE_LINEAR:
73*61046927SAndroid Build Coastguard Worker return AGX_MIP_FILTER_LINEAR;
74*61046927SAndroid Build Coastguard Worker
75*61046927SAndroid Build Coastguard Worker default:
76*61046927SAndroid Build Coastguard Worker unreachable("Invalid filter");
77*61046927SAndroid Build Coastguard Worker }
78*61046927SAndroid Build Coastguard Worker }
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker static bool
uses_border(const VkSamplerCreateInfo * info)81*61046927SAndroid Build Coastguard Worker uses_border(const VkSamplerCreateInfo *info)
82*61046927SAndroid Build Coastguard Worker {
83*61046927SAndroid Build Coastguard Worker return info->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
84*61046927SAndroid Build Coastguard Worker info->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
85*61046927SAndroid Build Coastguard Worker info->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Worker static enum agx_border_colour
is_border_color_custom(VkBorderColor color)89*61046927SAndroid Build Coastguard Worker is_border_color_custom(VkBorderColor color)
90*61046927SAndroid Build Coastguard Worker {
91*61046927SAndroid Build Coastguard Worker /* TODO: for now, opaque black is treated as custom due to rgba4 swizzling
92*61046927SAndroid Build Coastguard Worker * issues, could be optimized though.
93*61046927SAndroid Build Coastguard Worker */
94*61046927SAndroid Build Coastguard Worker switch (color) {
95*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
96*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
97*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_INT_CUSTOM_EXT:
98*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
99*61046927SAndroid Build Coastguard Worker return true;
100*61046927SAndroid Build Coastguard Worker default:
101*61046927SAndroid Build Coastguard Worker return false;
102*61046927SAndroid Build Coastguard Worker }
103*61046927SAndroid Build Coastguard Worker }
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker /* Translate an American VkBorderColor into a Canadian agx_border_colour */
106*61046927SAndroid Build Coastguard Worker static enum agx_border_colour
translate_border_color(VkBorderColor color,bool custom_to_1)107*61046927SAndroid Build Coastguard Worker translate_border_color(VkBorderColor color, bool custom_to_1)
108*61046927SAndroid Build Coastguard Worker {
109*61046927SAndroid Build Coastguard Worker switch (color) {
110*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
111*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
112*61046927SAndroid Build Coastguard Worker return AGX_BORDER_COLOUR_TRANSPARENT_BLACK;
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
115*61046927SAndroid Build Coastguard Worker case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
116*61046927SAndroid Build Coastguard Worker return AGX_BORDER_COLOUR_OPAQUE_WHITE;
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Worker default:
119*61046927SAndroid Build Coastguard Worker assert(is_border_color_custom(color));
120*61046927SAndroid Build Coastguard Worker return custom_to_1 ? AGX_BORDER_COLOUR_OPAQUE_WHITE
121*61046927SAndroid Build Coastguard Worker : AGX_BORDER_COLOUR_TRANSPARENT_BLACK;
122*61046927SAndroid Build Coastguard Worker }
123*61046927SAndroid Build Coastguard Worker }
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker static void
pack_sampler(const struct hk_physical_device * pdev,const struct VkSamplerCreateInfo * info,bool custom_to_1,struct agx_sampler_packed * out)126*61046927SAndroid Build Coastguard Worker pack_sampler(const struct hk_physical_device *pdev,
127*61046927SAndroid Build Coastguard Worker const struct VkSamplerCreateInfo *info, bool custom_to_1,
128*61046927SAndroid Build Coastguard Worker struct agx_sampler_packed *out)
129*61046927SAndroid Build Coastguard Worker {
130*61046927SAndroid Build Coastguard Worker agx_pack(out, SAMPLER, cfg) {
131*61046927SAndroid Build Coastguard Worker cfg.minimum_lod = info->minLod;
132*61046927SAndroid Build Coastguard Worker cfg.maximum_lod = info->maxLod;
133*61046927SAndroid Build Coastguard Worker cfg.magnify = translate_filter(info->magFilter);
134*61046927SAndroid Build Coastguard Worker cfg.minify = translate_filter(info->minFilter);
135*61046927SAndroid Build Coastguard Worker cfg.mip_filter = translate_mipfilter(info->mipmapMode);
136*61046927SAndroid Build Coastguard Worker cfg.wrap_s = translate_address_mode(info->addressModeU);
137*61046927SAndroid Build Coastguard Worker cfg.wrap_t = translate_address_mode(info->addressModeV);
138*61046927SAndroid Build Coastguard Worker cfg.wrap_r = translate_address_mode(info->addressModeW);
139*61046927SAndroid Build Coastguard Worker cfg.pixel_coordinates = info->unnormalizedCoordinates;
140*61046927SAndroid Build Coastguard Worker
141*61046927SAndroid Build Coastguard Worker cfg.seamful_cube_maps =
142*61046927SAndroid Build Coastguard Worker info->flags & VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT;
143*61046927SAndroid Build Coastguard Worker
144*61046927SAndroid Build Coastguard Worker if (info->compareEnable) {
145*61046927SAndroid Build Coastguard Worker cfg.compare_func = translate_texsamp_compare_op(info->compareOp);
146*61046927SAndroid Build Coastguard Worker cfg.compare_enable = true;
147*61046927SAndroid Build Coastguard Worker }
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker if (info->anisotropyEnable) {
150*61046927SAndroid Build Coastguard Worker cfg.maximum_anisotropy =
151*61046927SAndroid Build Coastguard Worker util_next_power_of_two(MAX2(info->maxAnisotropy, 1));
152*61046927SAndroid Build Coastguard Worker } else {
153*61046927SAndroid Build Coastguard Worker cfg.maximum_anisotropy = 1;
154*61046927SAndroid Build Coastguard Worker }
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker if (uses_border(info)) {
157*61046927SAndroid Build Coastguard Worker cfg.border_colour =
158*61046927SAndroid Build Coastguard Worker translate_border_color(info->borderColor, custom_to_1);
159*61046927SAndroid Build Coastguard Worker }
160*61046927SAndroid Build Coastguard Worker }
161*61046927SAndroid Build Coastguard Worker }
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker VKAPI_ATTR VkResult VKAPI_CALL
hk_CreateSampler(VkDevice device,const VkSamplerCreateInfo * info,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler)164*61046927SAndroid Build Coastguard Worker hk_CreateSampler(VkDevice device,
165*61046927SAndroid Build Coastguard Worker const VkSamplerCreateInfo *info /* pCreateInfo */,
166*61046927SAndroid Build Coastguard Worker const VkAllocationCallbacks *pAllocator, VkSampler *pSampler)
167*61046927SAndroid Build Coastguard Worker {
168*61046927SAndroid Build Coastguard Worker VK_FROM_HANDLE(hk_device, dev, device);
169*61046927SAndroid Build Coastguard Worker struct hk_physical_device *pdev = hk_device_physical(dev);
170*61046927SAndroid Build Coastguard Worker struct hk_sampler *sampler;
171*61046927SAndroid Build Coastguard Worker VkResult result;
172*61046927SAndroid Build Coastguard Worker
173*61046927SAndroid Build Coastguard Worker sampler = vk_sampler_create(&dev->vk, info, pAllocator, sizeof(*sampler));
174*61046927SAndroid Build Coastguard Worker if (!sampler)
175*61046927SAndroid Build Coastguard Worker return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker struct agx_sampler_packed samp;
178*61046927SAndroid Build Coastguard Worker pack_sampler(pdev, info, true, &samp);
179*61046927SAndroid Build Coastguard Worker
180*61046927SAndroid Build Coastguard Worker /* LOD bias passed in the descriptor set */
181*61046927SAndroid Build Coastguard Worker sampler->lod_bias_fp16 = _mesa_float_to_half(info->mipLodBias);
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker result =
184*61046927SAndroid Build Coastguard Worker hk_sampler_heap_add(dev, samp, &sampler->planes[sampler->plane_count].hw);
185*61046927SAndroid Build Coastguard Worker if (result != VK_SUCCESS) {
186*61046927SAndroid Build Coastguard Worker hk_DestroySampler(device, hk_sampler_to_handle(sampler), pAllocator);
187*61046927SAndroid Build Coastguard Worker return result;
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker sampler->plane_count++;
191*61046927SAndroid Build Coastguard Worker
192*61046927SAndroid Build Coastguard Worker /* In order to support CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, we
193*61046927SAndroid Build Coastguard Worker * need multiple sampler planes: at minimum we will need one for luminance
194*61046927SAndroid Build Coastguard Worker * (the default), and one for chroma. Each sampler plane needs its own
195*61046927SAndroid Build Coastguard Worker * sampler table entry. However, sampler table entries are very rare on
196*61046927SAndroid Build Coastguard Worker * G13, and each plane would burn one of those. So we make sure to allocate
197*61046927SAndroid Build Coastguard Worker * only the minimum amount that we actually need (i.e., either 1 or 2), and
198*61046927SAndroid Build Coastguard Worker * then just copy the last sampler plane out as far as we need to fill the
199*61046927SAndroid Build Coastguard Worker * number of image planes.
200*61046927SAndroid Build Coastguard Worker */
201*61046927SAndroid Build Coastguard Worker if (sampler->vk.ycbcr_conversion) {
202*61046927SAndroid Build Coastguard Worker assert(!uses_border(info) &&
203*61046927SAndroid Build Coastguard Worker "consequence of VUID-VkSamplerCreateInfo-addressModeU-01646");
204*61046927SAndroid Build Coastguard Worker
205*61046927SAndroid Build Coastguard Worker const VkFilter chroma_filter =
206*61046927SAndroid Build Coastguard Worker sampler->vk.ycbcr_conversion->state.chroma_filter;
207*61046927SAndroid Build Coastguard Worker if (info->magFilter != chroma_filter ||
208*61046927SAndroid Build Coastguard Worker info->minFilter != chroma_filter) {
209*61046927SAndroid Build Coastguard Worker VkSamplerCreateInfo plane2_info = *info;
210*61046927SAndroid Build Coastguard Worker plane2_info.magFilter = chroma_filter;
211*61046927SAndroid Build Coastguard Worker plane2_info.minFilter = chroma_filter;
212*61046927SAndroid Build Coastguard Worker
213*61046927SAndroid Build Coastguard Worker pack_sampler(pdev, &plane2_info, false, &samp);
214*61046927SAndroid Build Coastguard Worker result = hk_sampler_heap_add(
215*61046927SAndroid Build Coastguard Worker dev, samp, &sampler->planes[sampler->plane_count].hw);
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker if (result != VK_SUCCESS) {
218*61046927SAndroid Build Coastguard Worker hk_DestroySampler(device, hk_sampler_to_handle(sampler),
219*61046927SAndroid Build Coastguard Worker pAllocator);
220*61046927SAndroid Build Coastguard Worker return result;
221*61046927SAndroid Build Coastguard Worker }
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker sampler->plane_count++;
224*61046927SAndroid Build Coastguard Worker }
225*61046927SAndroid Build Coastguard Worker } else if (uses_border(info)) {
226*61046927SAndroid Build Coastguard Worker /* If the sampler uses custom border colours, we need both clamp-to-1
227*61046927SAndroid Build Coastguard Worker * and clamp-to-0 variants. We treat these as planes.
228*61046927SAndroid Build Coastguard Worker */
229*61046927SAndroid Build Coastguard Worker pack_sampler(pdev, info, false, &samp);
230*61046927SAndroid Build Coastguard Worker result = hk_sampler_heap_add(dev, samp,
231*61046927SAndroid Build Coastguard Worker &sampler->planes[sampler->plane_count].hw);
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker if (result != VK_SUCCESS) {
234*61046927SAndroid Build Coastguard Worker hk_DestroySampler(device, hk_sampler_to_handle(sampler), pAllocator);
235*61046927SAndroid Build Coastguard Worker return result;
236*61046927SAndroid Build Coastguard Worker }
237*61046927SAndroid Build Coastguard Worker
238*61046927SAndroid Build Coastguard Worker sampler->plane_count++;
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker /* We also need to record the border.
241*61046927SAndroid Build Coastguard Worker *
242*61046927SAndroid Build Coastguard Worker * If there is a border colour component mapping, we need to swizzle with
243*61046927SAndroid Build Coastguard Worker * it. Otherwise, we can assume there's nothing to do.
244*61046927SAndroid Build Coastguard Worker */
245*61046927SAndroid Build Coastguard Worker VkClearColorValue bc = sampler->vk.border_color_value;
246*61046927SAndroid Build Coastguard Worker
247*61046927SAndroid Build Coastguard Worker const VkSamplerBorderColorComponentMappingCreateInfoEXT *swiz_info =
248*61046927SAndroid Build Coastguard Worker vk_find_struct_const(
249*61046927SAndroid Build Coastguard Worker info->pNext,
250*61046927SAndroid Build Coastguard Worker SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT);
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker if (swiz_info) {
253*61046927SAndroid Build Coastguard Worker const bool is_int = vk_border_color_is_int(info->borderColor);
254*61046927SAndroid Build Coastguard Worker bc = vk_swizzle_color_value(bc, swiz_info->components, is_int);
255*61046927SAndroid Build Coastguard Worker }
256*61046927SAndroid Build Coastguard Worker
257*61046927SAndroid Build Coastguard Worker sampler->custom_border = bc;
258*61046927SAndroid Build Coastguard Worker sampler->has_border = true;
259*61046927SAndroid Build Coastguard Worker }
260*61046927SAndroid Build Coastguard Worker
261*61046927SAndroid Build Coastguard Worker *pSampler = hk_sampler_to_handle(sampler);
262*61046927SAndroid Build Coastguard Worker
263*61046927SAndroid Build Coastguard Worker return VK_SUCCESS;
264*61046927SAndroid Build Coastguard Worker }
265*61046927SAndroid Build Coastguard Worker
266*61046927SAndroid Build Coastguard Worker VKAPI_ATTR void VKAPI_CALL
hk_DestroySampler(VkDevice device,VkSampler _sampler,const VkAllocationCallbacks * pAllocator)267*61046927SAndroid Build Coastguard Worker hk_DestroySampler(VkDevice device, VkSampler _sampler,
268*61046927SAndroid Build Coastguard Worker const VkAllocationCallbacks *pAllocator)
269*61046927SAndroid Build Coastguard Worker {
270*61046927SAndroid Build Coastguard Worker VK_FROM_HANDLE(hk_device, dev, device);
271*61046927SAndroid Build Coastguard Worker VK_FROM_HANDLE(hk_sampler, sampler, _sampler);
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker if (!sampler)
274*61046927SAndroid Build Coastguard Worker return;
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker for (uint8_t plane = 0; plane < sampler->plane_count; plane++) {
277*61046927SAndroid Build Coastguard Worker hk_sampler_heap_remove(dev, sampler->planes[plane].hw);
278*61046927SAndroid Build Coastguard Worker }
279*61046927SAndroid Build Coastguard Worker
280*61046927SAndroid Build Coastguard Worker vk_sampler_destroy(&dev->vk, pAllocator, &sampler->vk);
281*61046927SAndroid Build Coastguard Worker }
282