• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2021 Collabora Ltd.
3  *
4  * Derived from:
5  * Copyright © 2016 Red Hat.
6  * Copyright © 2016 Bas Nieuwenhuizen
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  */
27 #include "panvk_private.h"
28 
29 #include <assert.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include "util/mesa-sha1.h"
36 #include "vk_descriptors.h"
37 #include "vk_util.h"
38 
39 #include "pan_bo.h"
40 
41 VkResult
panvk_CreateDescriptorSetLayout(VkDevice _device,const VkDescriptorSetLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorSetLayout * pSetLayout)42 panvk_CreateDescriptorSetLayout(VkDevice _device,
43                                 const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
44                                 const VkAllocationCallbacks *pAllocator,
45                                 VkDescriptorSetLayout *pSetLayout)
46 {
47    VK_FROM_HANDLE(panvk_device, device, _device);
48    struct panvk_descriptor_set_layout *set_layout;
49    VkDescriptorSetLayoutBinding *bindings = NULL;
50    unsigned num_bindings = 0;
51    VkResult result;
52 
53    if (pCreateInfo->bindingCount) {
54       result =
55          vk_create_sorted_bindings(pCreateInfo->pBindings,
56                                    pCreateInfo->bindingCount,
57                                    &bindings);
58       if (result != VK_SUCCESS)
59          return vk_error(device, result);
60 
61       num_bindings = bindings[pCreateInfo->bindingCount - 1].binding + 1;
62    }
63 
64    unsigned num_immutable_samplers = 0;
65    for (unsigned i = 0; i < pCreateInfo->bindingCount; i++) {
66       if (bindings[i].pImmutableSamplers)
67          num_immutable_samplers += bindings[i].descriptorCount;
68    }
69 
70    size_t size = sizeof(*set_layout) +
71                  (sizeof(struct panvk_descriptor_set_binding_layout) *
72                   num_bindings) +
73                  (sizeof(struct panvk_sampler *) * num_immutable_samplers);
74    set_layout = vk_object_zalloc(&device->vk, pAllocator, size,
75                                  VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
76    if (!set_layout) {
77       result = VK_ERROR_OUT_OF_HOST_MEMORY;
78       goto err_free_bindings;
79    }
80 
81    struct panvk_sampler **immutable_samplers =
82       (struct panvk_sampler **)((uint8_t *)set_layout + sizeof(*set_layout) +
83                                 (sizeof(struct panvk_descriptor_set_binding_layout) *
84                                  num_bindings));
85 
86    set_layout->flags = pCreateInfo->flags;
87    set_layout->binding_count = num_bindings;
88 
89    unsigned sampler_idx = 0, tex_idx = 0, ubo_idx = 0, ssbo_idx = 0;
90    unsigned dynoffset_idx = 0, desc_idx = 0;
91 
92    for (unsigned i = 0; i < pCreateInfo->bindingCount; i++) {
93       const VkDescriptorSetLayoutBinding *binding = &bindings[i];
94       struct panvk_descriptor_set_binding_layout *binding_layout =
95          &set_layout->bindings[binding->binding];
96 
97       binding_layout->type = binding->descriptorType;
98       binding_layout->array_size = binding->descriptorCount;
99       binding_layout->shader_stages = binding->stageFlags;
100       if (binding->pImmutableSamplers) {
101          binding_layout->immutable_samplers = immutable_samplers;
102          immutable_samplers += binding_layout->array_size;
103          for (unsigned j = 0; j < binding_layout->array_size; j++) {
104             VK_FROM_HANDLE(panvk_sampler, sampler, binding->pImmutableSamplers[j]);
105             binding_layout->immutable_samplers[j] = sampler;
106          }
107       }
108 
109       binding_layout->desc_idx = desc_idx;
110       desc_idx += binding->descriptorCount;
111       switch (binding_layout->type) {
112       case VK_DESCRIPTOR_TYPE_SAMPLER:
113          binding_layout->sampler_idx = sampler_idx;
114          sampler_idx += binding_layout->array_size;
115          break;
116       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
117          binding_layout->sampler_idx = sampler_idx;
118          binding_layout->tex_idx = tex_idx;
119          sampler_idx += binding_layout->array_size;
120          tex_idx += binding_layout->array_size;
121          break;
122       case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
123       case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
124       case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
125       case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
126       case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
127          binding_layout->tex_idx = tex_idx;
128          tex_idx += binding_layout->array_size;
129          break;
130       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
131          binding_layout->dynoffset_idx = dynoffset_idx;
132          dynoffset_idx += binding_layout->array_size;
133          FALLTHROUGH;
134       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
135          binding_layout->ubo_idx = ubo_idx;
136          ubo_idx += binding_layout->array_size;
137          break;
138       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
139          binding_layout->dynoffset_idx = dynoffset_idx;
140          dynoffset_idx += binding_layout->array_size;
141          FALLTHROUGH;
142       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
143          binding_layout->ssbo_idx = ssbo_idx;
144          ssbo_idx += binding_layout->array_size;
145          break;
146       default:
147          unreachable("Invalid descriptor type");
148       }
149    }
150 
151    set_layout->num_descs = desc_idx;
152    set_layout->num_samplers = sampler_idx;
153    set_layout->num_textures = tex_idx;
154    set_layout->num_ubos = ubo_idx;
155    set_layout->num_ssbos = ssbo_idx;
156    set_layout->num_dynoffsets = dynoffset_idx;
157 
158    free(bindings);
159    *pSetLayout = panvk_descriptor_set_layout_to_handle(set_layout);
160    return VK_SUCCESS;
161 
162 err_free_bindings:
163    free(bindings);
164    return vk_error(device, result);
165 }
166 
167 void
panvk_DestroyDescriptorSetLayout(VkDevice _device,VkDescriptorSetLayout _set_layout,const VkAllocationCallbacks * pAllocator)168 panvk_DestroyDescriptorSetLayout(VkDevice _device,
169                                  VkDescriptorSetLayout _set_layout,
170                                  const VkAllocationCallbacks *pAllocator)
171 {
172    VK_FROM_HANDLE(panvk_device, device, _device);
173    VK_FROM_HANDLE(panvk_descriptor_set_layout, set_layout, _set_layout);
174 
175    if (!set_layout)
176       return;
177 
178    vk_object_free(&device->vk, pAllocator, set_layout);
179 }
180 
181 /* FIXME: make sure those values are correct */
182 #define PANVK_MAX_TEXTURES     (1 << 16)
183 #define PANVK_MAX_SAMPLERS     (1 << 16)
184 #define PANVK_MAX_UBOS         255
185 
186 void
panvk_GetDescriptorSetLayoutSupport(VkDevice _device,const VkDescriptorSetLayoutCreateInfo * pCreateInfo,VkDescriptorSetLayoutSupport * pSupport)187 panvk_GetDescriptorSetLayoutSupport(VkDevice _device,
188                                     const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
189                                     VkDescriptorSetLayoutSupport *pSupport)
190 {
191    VK_FROM_HANDLE(panvk_device, device, _device);
192 
193    pSupport->supported = false;
194 
195    VkDescriptorSetLayoutBinding *bindings;
196    VkResult result =
197       vk_create_sorted_bindings(pCreateInfo->pBindings,
198                                 pCreateInfo->bindingCount,
199                                 &bindings);
200    if (result != VK_SUCCESS) {
201       vk_error(device, result);
202       return;
203    }
204 
205    unsigned sampler_idx = 0, tex_idx = 0, ubo_idx = 0, ssbo_idx = 0, dynoffset_idx = 0;
206    for (unsigned i = 0; i < pCreateInfo->bindingCount; i++) {
207       const VkDescriptorSetLayoutBinding *binding = &bindings[i];
208 
209       switch (binding->descriptorType) {
210       case VK_DESCRIPTOR_TYPE_SAMPLER:
211          sampler_idx += binding->descriptorCount;
212          break;
213       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
214          sampler_idx += binding->descriptorCount;
215          tex_idx += binding->descriptorCount;
216          break;
217       case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
218       case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
219       case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
220       case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
221       case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
222          tex_idx += binding->descriptorCount;
223          break;
224       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
225          dynoffset_idx += binding->descriptorCount;
226          FALLTHROUGH;
227       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
228          ubo_idx += binding->descriptorCount;
229          break;
230       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
231          dynoffset_idx += binding->descriptorCount;
232          FALLTHROUGH;
233       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
234          ssbo_idx += binding->descriptorCount;
235          break;
236       default:
237          unreachable("Invalid descriptor type");
238       }
239    }
240 
241    /* The maximum values apply to all sets attached to a pipeline since all
242     * sets descriptors have to be merged in a single array.
243     */
244    if (tex_idx > PANVK_MAX_TEXTURES / MAX_SETS ||
245        sampler_idx > PANVK_MAX_SAMPLERS / MAX_SETS ||
246        ubo_idx > PANVK_MAX_UBOS / MAX_SETS)
247       return;
248 
249    pSupport->supported = true;
250 }
251 
252 /*
253  * Pipeline layouts.  These have nothing to do with the pipeline.  They are
254  * just multiple descriptor set layouts pasted together.
255  */
256 
257 VkResult
panvk_CreatePipelineLayout(VkDevice _device,const VkPipelineLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineLayout * pPipelineLayout)258 panvk_CreatePipelineLayout(VkDevice _device,
259                            const VkPipelineLayoutCreateInfo *pCreateInfo,
260                            const VkAllocationCallbacks *pAllocator,
261                            VkPipelineLayout *pPipelineLayout)
262 {
263    VK_FROM_HANDLE(panvk_device, device, _device);
264    struct panvk_pipeline_layout *layout;
265    struct mesa_sha1 ctx;
266 
267    layout = vk_object_zalloc(&device->vk, pAllocator, sizeof(*layout),
268                              VK_OBJECT_TYPE_PIPELINE_LAYOUT);
269    if (layout == NULL)
270       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
271 
272    layout->num_sets = pCreateInfo->setLayoutCount;
273    _mesa_sha1_init(&ctx);
274 
275    unsigned sampler_idx = 0, tex_idx = 0, ssbo_idx = 0, ubo_idx = 0, dynoffset_idx = 0;
276    for (unsigned set = 0; set < pCreateInfo->setLayoutCount; set++) {
277       VK_FROM_HANDLE(panvk_descriptor_set_layout, set_layout,
278                      pCreateInfo->pSetLayouts[set]);
279       layout->sets[set].layout = set_layout;
280       layout->sets[set].sampler_offset = sampler_idx;
281       layout->sets[set].tex_offset = tex_idx;
282       layout->sets[set].ubo_offset = ubo_idx;
283       layout->sets[set].ssbo_offset = ssbo_idx;
284       layout->sets[set].dynoffset_offset = dynoffset_idx;
285       sampler_idx += set_layout->num_samplers;
286       tex_idx += set_layout->num_textures;
287       ubo_idx += set_layout->num_ubos + (set_layout->num_dynoffsets != 0);
288       ssbo_idx += set_layout->num_ssbos;
289       dynoffset_idx += set_layout->num_dynoffsets;
290 
291       for (unsigned b = 0; b < set_layout->binding_count; b++) {
292          struct panvk_descriptor_set_binding_layout *binding_layout =
293             &set_layout->bindings[b];
294 
295          if (binding_layout->immutable_samplers) {
296             for (unsigned s = 0; s < binding_layout->array_size; s++) {
297                struct panvk_sampler *sampler = binding_layout->immutable_samplers[s];
298 
299                _mesa_sha1_update(&ctx, &sampler->desc, sizeof(sampler->desc));
300             }
301          }
302          _mesa_sha1_update(&ctx, &binding_layout->type, sizeof(binding_layout->type));
303          _mesa_sha1_update(&ctx, &binding_layout->array_size, sizeof(binding_layout->array_size));
304          _mesa_sha1_update(&ctx, &binding_layout->desc_idx, sizeof(binding_layout->sampler_idx));
305          _mesa_sha1_update(&ctx, &binding_layout->shader_stages, sizeof(binding_layout->shader_stages));
306       }
307    }
308 
309    layout->num_samplers = sampler_idx;
310    layout->num_textures = tex_idx;
311    layout->num_ubos = ubo_idx;
312    layout->num_ssbos = ssbo_idx;
313    layout->num_dynoffsets = dynoffset_idx;
314 
315    _mesa_sha1_final(&ctx, layout->sha1);
316 
317    *pPipelineLayout = panvk_pipeline_layout_to_handle(layout);
318    return VK_SUCCESS;
319 }
320 
321 void
panvk_DestroyPipelineLayout(VkDevice _device,VkPipelineLayout _pipelineLayout,const VkAllocationCallbacks * pAllocator)322 panvk_DestroyPipelineLayout(VkDevice _device,
323                             VkPipelineLayout _pipelineLayout,
324                             const VkAllocationCallbacks *pAllocator)
325 {
326    VK_FROM_HANDLE(panvk_device, device, _device);
327    VK_FROM_HANDLE(panvk_pipeline_layout, pipeline_layout, _pipelineLayout);
328 
329    if (!pipeline_layout)
330       return;
331 
332    vk_object_free(&device->vk, pAllocator, pipeline_layout);
333 }
334 
335 VkResult
panvk_CreateDescriptorPool(VkDevice _device,const VkDescriptorPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorPool * pDescriptorPool)336 panvk_CreateDescriptorPool(VkDevice _device,
337                            const VkDescriptorPoolCreateInfo *pCreateInfo,
338                            const VkAllocationCallbacks *pAllocator,
339                            VkDescriptorPool *pDescriptorPool)
340 {
341    VK_FROM_HANDLE(panvk_device, device, _device);
342    struct panvk_descriptor_pool *pool;
343 
344    pool = vk_object_zalloc(&device->vk, pAllocator,
345                            sizeof(struct panvk_descriptor_pool),
346                            VK_OBJECT_TYPE_DESCRIPTOR_POOL);
347    if (!pool)
348       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
349 
350    pool->max.sets = pCreateInfo->maxSets;
351 
352    for (unsigned i = 0; i < pCreateInfo->poolSizeCount; ++i) {
353       unsigned desc_count = pCreateInfo->pPoolSizes[i].descriptorCount;
354 
355       switch(pCreateInfo->pPoolSizes[i].type) {
356       case VK_DESCRIPTOR_TYPE_SAMPLER:
357          pool->max.samplers += desc_count;
358          break;
359       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
360          pool->max.combined_image_samplers += desc_count;
361          break;
362       case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
363          pool->max.sampled_images += desc_count;
364          break;
365       case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
366          pool->max.storage_images += desc_count;
367          break;
368       case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
369          pool->max.uniform_texel_bufs += desc_count;
370          break;
371       case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
372          pool->max.storage_texel_bufs += desc_count;
373          break;
374       case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
375          pool->max.input_attachments += desc_count;
376          break;
377       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
378          pool->max.uniform_bufs += desc_count;
379          break;
380       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
381          pool->max.storage_bufs += desc_count;
382          break;
383       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
384          pool->max.uniform_dyn_bufs += desc_count;
385          break;
386       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
387          pool->max.storage_dyn_bufs += desc_count;
388          break;
389       default:
390          unreachable("Invalid descriptor type");
391       }
392    }
393 
394    *pDescriptorPool = panvk_descriptor_pool_to_handle(pool);
395    return VK_SUCCESS;
396 }
397 
398 void
panvk_DestroyDescriptorPool(VkDevice _device,VkDescriptorPool _pool,const VkAllocationCallbacks * pAllocator)399 panvk_DestroyDescriptorPool(VkDevice _device,
400                             VkDescriptorPool _pool,
401                             const VkAllocationCallbacks *pAllocator)
402 {
403    VK_FROM_HANDLE(panvk_device, device, _device);
404    VK_FROM_HANDLE(panvk_descriptor_pool, pool, _pool);
405 
406    if (pool)
407       vk_object_free(&device->vk, pAllocator, pool);
408 }
409 
410 VkResult
panvk_ResetDescriptorPool(VkDevice _device,VkDescriptorPool _pool,VkDescriptorPoolResetFlags flags)411 panvk_ResetDescriptorPool(VkDevice _device,
412                           VkDescriptorPool _pool,
413                           VkDescriptorPoolResetFlags flags)
414 {
415    VK_FROM_HANDLE(panvk_descriptor_pool, pool, _pool);
416    memset(&pool->cur, 0, sizeof(pool->cur));
417    return VK_SUCCESS;
418 }
419 
420 static void
panvk_descriptor_set_destroy(struct panvk_device * device,struct panvk_descriptor_pool * pool,struct panvk_descriptor_set * set)421 panvk_descriptor_set_destroy(struct panvk_device *device,
422                              struct panvk_descriptor_pool *pool,
423                              struct panvk_descriptor_set *set)
424 {
425    vk_free(&device->vk.alloc, set->textures);
426    vk_free(&device->vk.alloc, set->samplers);
427    vk_free(&device->vk.alloc, set->ubos);
428    vk_free(&device->vk.alloc, set->descs);
429    vk_object_free(&device->vk, NULL, set);
430 }
431 
432 VkResult
panvk_FreeDescriptorSets(VkDevice _device,VkDescriptorPool descriptorPool,uint32_t count,const VkDescriptorSet * pDescriptorSets)433 panvk_FreeDescriptorSets(VkDevice _device,
434                          VkDescriptorPool descriptorPool,
435                          uint32_t count,
436                          const VkDescriptorSet *pDescriptorSets)
437 {
438    VK_FROM_HANDLE(panvk_device, device, _device);
439    VK_FROM_HANDLE(panvk_descriptor_pool, pool, descriptorPool);
440 
441    for (unsigned i = 0; i < count; i++) {
442       VK_FROM_HANDLE(panvk_descriptor_set, set, pDescriptorSets[i]);
443 
444       if (set)
445          panvk_descriptor_set_destroy(device, pool, set);
446    }
447    return VK_SUCCESS;
448 }
449 
450 VkResult
panvk_CreateDescriptorUpdateTemplate(VkDevice _device,const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate)451 panvk_CreateDescriptorUpdateTemplate(VkDevice _device,
452                                      const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo,
453                                      const VkAllocationCallbacks *pAllocator,
454                                      VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate)
455 {
456    panvk_stub();
457    return VK_SUCCESS;
458 }
459 
460 void
panvk_DestroyDescriptorUpdateTemplate(VkDevice _device,VkDescriptorUpdateTemplate descriptorUpdateTemplate,const VkAllocationCallbacks * pAllocator)461 panvk_DestroyDescriptorUpdateTemplate(VkDevice _device,
462                                       VkDescriptorUpdateTemplate descriptorUpdateTemplate,
463                                       const VkAllocationCallbacks *pAllocator)
464 {
465    panvk_stub();
466 }
467 
468 void
panvk_UpdateDescriptorSetWithTemplate(VkDevice _device,VkDescriptorSet descriptorSet,VkDescriptorUpdateTemplate descriptorUpdateTemplate,const void * pData)469 panvk_UpdateDescriptorSetWithTemplate(VkDevice _device,
470                                       VkDescriptorSet descriptorSet,
471                                       VkDescriptorUpdateTemplate descriptorUpdateTemplate,
472                                       const void *pData)
473 {
474    panvk_stub();
475 }
476 
477 VkResult
panvk_CreateSamplerYcbcrConversion(VkDevice device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion)478 panvk_CreateSamplerYcbcrConversion(VkDevice device,
479                                    const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
480                                    const VkAllocationCallbacks *pAllocator,
481                                    VkSamplerYcbcrConversion *pYcbcrConversion)
482 {
483    panvk_stub();
484    return VK_SUCCESS;
485 }
486 
487 void
panvk_DestroySamplerYcbcrConversion(VkDevice device,VkSamplerYcbcrConversion ycbcrConversion,const VkAllocationCallbacks * pAllocator)488 panvk_DestroySamplerYcbcrConversion(VkDevice device,
489                                     VkSamplerYcbcrConversion ycbcrConversion,
490                                     const VkAllocationCallbacks *pAllocator)
491 {
492    panvk_stub();
493 }
494