• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2021 Collabora Ltd.
3  *
4  * Derived from tu_device.c which is:
5  * Copyright © 2016 Red Hat.
6  * Copyright © 2016 Bas Nieuwenhuizen
7  * Copyright © 2015 Intel Corporation
8  *
9  * SPDX-License-Identifier: MIT
10  */
11 
12 #include <sys/stat.h>
13 #include <sys/sysinfo.h>
14 #include <sys/sysmacros.h>
15 
16 #include "util/disk_cache.h"
17 #include "git_sha1.h"
18 
19 #include "vk_device.h"
20 #include "vk_drm_syncobj.h"
21 #include "vk_format.h"
22 #include "vk_limits.h"
23 #include "vk_log.h"
24 #include "vk_shader_module.h"
25 #include "vk_util.h"
26 
27 #include "panvk_device.h"
28 #include "panvk_entrypoints.h"
29 #include "panvk_instance.h"
30 #include "panvk_physical_device.h"
31 #include "panvk_wsi.h"
32 
33 #include "pan_format.h"
34 #include "pan_props.h"
35 
36 #include "genxml/gen_macros.h"
37 
38 #define ARM_VENDOR_ID        0x13b5
39 #define MAX_PUSH_DESCRIPTORS 32
40 /* We reserve one ubo for push constant, one for sysvals and one per-set for the
41  * descriptor metadata  */
42 #define RESERVED_UBO_COUNT                   6
43 #define MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS 32 - RESERVED_UBO_COUNT
44 #define MAX_INLINE_UNIFORM_BLOCK_SIZE        (1 << 16)
45 
46 static VkResult
create_kmod_dev(struct panvk_physical_device * device,const struct panvk_instance * instance,drmDevicePtr drm_device)47 create_kmod_dev(struct panvk_physical_device *device,
48                 const struct panvk_instance *instance, drmDevicePtr drm_device)
49 {
50    const char *path = drm_device->nodes[DRM_NODE_RENDER];
51    drmVersionPtr version;
52    int fd;
53 
54    fd = open(path, O_RDWR | O_CLOEXEC);
55    if (fd < 0) {
56       return panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
57                           "failed to open device %s", path);
58    }
59 
60    version = drmGetVersion(fd);
61    if (!version) {
62       close(fd);
63       return panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
64                           "failed to query kernel driver version for device %s",
65                           path);
66    }
67 
68    if (strcmp(version->name, "panfrost") && strcmp(version->name, "panthor")) {
69       drmFreeVersion(version);
70       close(fd);
71       return VK_ERROR_INCOMPATIBLE_DRIVER;
72    }
73 
74    drmFreeVersion(version);
75 
76    if (instance->debug_flags & PANVK_DEBUG_STARTUP)
77       vk_logi(VK_LOG_NO_OBJS(instance), "Found compatible device '%s'.", path);
78 
79    device->kmod.dev = pan_kmod_dev_create(fd, PAN_KMOD_DEV_FLAG_OWNS_FD,
80                                           &instance->kmod.allocator);
81 
82    if (!device->kmod.dev) {
83       close(fd);
84       return panvk_errorf(instance, VK_ERROR_OUT_OF_HOST_MEMORY,
85                           "cannot create device");
86    }
87 
88    return VK_SUCCESS;
89 }
90 
91 static VkResult
get_drm_device_ids(struct panvk_physical_device * device,const struct panvk_instance * instance,drmDevicePtr drm_device)92 get_drm_device_ids(struct panvk_physical_device *device,
93                    const struct panvk_instance *instance,
94                    drmDevicePtr drm_device)
95 {
96    struct stat st;
97 
98    if (stat(drm_device->nodes[DRM_NODE_RENDER], &st)) {
99       return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
100                        "failed to query render node stat");
101    }
102 
103    device->drm.render_rdev = st.st_rdev;
104 
105    if (drm_device->available_nodes & (1 << DRM_NODE_PRIMARY)) {
106       if (stat(drm_device->nodes[DRM_NODE_PRIMARY], &st)) {
107          return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
108                           "failed to query primary node stat");
109       }
110 
111       device->drm.primary_rdev = st.st_rdev;
112    }
113 
114    return VK_SUCCESS;
115 }
116 
117 static int
get_cache_uuid(uint16_t family,void * uuid)118 get_cache_uuid(uint16_t family, void *uuid)
119 {
120    uint32_t mesa_timestamp;
121    uint16_t f = family;
122 
123    if (!disk_cache_get_function_timestamp(get_cache_uuid, &mesa_timestamp))
124       return -1;
125 
126    memset(uuid, 0, VK_UUID_SIZE);
127    memcpy(uuid, &mesa_timestamp, 4);
128    memcpy((char *)uuid + 4, &f, 2);
129    snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "pan");
130    return 0;
131 }
132 
133 static VkResult
get_device_sync_types(struct panvk_physical_device * device,const struct panvk_instance * instance)134 get_device_sync_types(struct panvk_physical_device *device,
135                       const struct panvk_instance *instance)
136 {
137    const unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
138    uint32_t sync_type_count = 0;
139 
140    device->drm_syncobj_type = vk_drm_syncobj_get_type(device->kmod.dev->fd);
141    if (!device->drm_syncobj_type.features) {
142       return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
143                        "failed to query syncobj features");
144    }
145 
146    device->sync_types[sync_type_count++] = &device->drm_syncobj_type;
147 
148    if (arch >= 10) {
149       assert(device->drm_syncobj_type.features & VK_SYNC_FEATURE_TIMELINE);
150    } else {
151       /* We don't support timelines in the uAPI yet and we don't want it getting
152        * suddenly turned on by vk_drm_syncobj_get_type() without us adding panvk
153        * code for it first.
154        */
155       device->drm_syncobj_type.features &= ~VK_SYNC_FEATURE_TIMELINE;
156 
157       /* vk_sync_timeline requires VK_SYNC_FEATURE_GPU_MULTI_WAIT.  Panfrost
158        * waits on the underlying dma-fences and supports the feature.
159        */
160       device->drm_syncobj_type.features |= VK_SYNC_FEATURE_GPU_MULTI_WAIT;
161 
162       device->sync_timeline_type =
163          vk_sync_timeline_get_type(&device->drm_syncobj_type);
164       device->sync_types[sync_type_count++] = &device->sync_timeline_type.sync;
165    }
166 
167    assert(sync_type_count < ARRAY_SIZE(device->sync_types));
168    device->sync_types[sync_type_count] = NULL;
169 
170    return VK_SUCCESS;
171 }
172 
173 static void
get_device_extensions(const struct panvk_physical_device * device,struct vk_device_extension_table * ext)174 get_device_extensions(const struct panvk_physical_device *device,
175                       struct vk_device_extension_table *ext)
176 {
177    const unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
178 
179    *ext = (struct vk_device_extension_table){
180       .KHR_8bit_storage = true,
181       .KHR_16bit_storage = true,
182       .KHR_bind_memory2 = true,
183       .KHR_buffer_device_address = true,
184       .KHR_copy_commands2 = true,
185       .KHR_create_renderpass2 = true,
186       .KHR_dedicated_allocation = true,
187       .KHR_descriptor_update_template = true,
188       .KHR_device_group = true,
189       .KHR_driver_properties = true,
190       .KHR_dynamic_rendering = true,
191       .KHR_external_fence = true,
192       .KHR_external_fence_fd = true,
193       .KHR_external_memory = true,
194       .KHR_external_memory_fd = true,
195       .KHR_external_semaphore = true,
196       .KHR_external_semaphore_fd = true,
197       .KHR_get_memory_requirements2 = true,
198       .KHR_global_priority = true,
199       .KHR_image_format_list = true,
200       .KHR_index_type_uint8 = true,
201       .KHR_maintenance1 = true,
202       .KHR_maintenance2 = true,
203       .KHR_maintenance3 = true,
204       .KHR_map_memory2 = true,
205       .KHR_multiview = arch >= 10,
206       .KHR_pipeline_executable_properties = true,
207       .KHR_pipeline_library = true,
208       .KHR_push_descriptor = true,
209       .KHR_relaxed_block_layout = true,
210       .KHR_sampler_mirror_clamp_to_edge = true,
211       .KHR_shader_draw_parameters = true,
212       .KHR_shader_expect_assume = true,
213       .KHR_shader_float16_int8 = true,
214       .KHR_shader_non_semantic_info = true,
215       .KHR_shader_relaxed_extended_instruction = true,
216       .KHR_storage_buffer_storage_class = true,
217 #ifdef PANVK_USE_WSI_PLATFORM
218       .KHR_swapchain = true,
219 #endif
220       .KHR_synchronization2 = true,
221       .KHR_timeline_semaphore = true,
222       .KHR_variable_pointers = true,
223       .KHR_vertex_attribute_divisor = true,
224       .KHR_zero_initialize_workgroup_memory = true,
225       .EXT_4444_formats = true,
226       .EXT_buffer_device_address = true,
227       .EXT_custom_border_color = true,
228       .EXT_depth_clip_enable = true,
229       .EXT_external_memory_dma_buf = true,
230       .EXT_global_priority = true,
231       .EXT_global_priority_query = true,
232       .EXT_graphics_pipeline_library = true,
233       .EXT_host_query_reset = true,
234       .EXT_image_drm_format_modifier = true,
235       .EXT_image_robustness = true,
236       .EXT_index_type_uint8 = true,
237       .EXT_physical_device_drm = true,
238       .EXT_pipeline_creation_cache_control = true,
239       .EXT_pipeline_creation_feedback = true,
240       .EXT_pipeline_robustness = true,
241       .EXT_private_data = true,
242       .EXT_provoking_vertex = true,
243       .EXT_queue_family_foreign = true,
244       .EXT_sampler_filter_minmax = arch >= 10,
245       .EXT_scalar_block_layout = true,
246       .EXT_shader_module_identifier = true,
247       .EXT_tooling_info = true,
248       .GOOGLE_decorate_string = true,
249       .GOOGLE_hlsl_functionality1 = true,
250       .GOOGLE_user_type = true,
251    };
252 }
253 
254 static void
get_features(const struct panvk_physical_device * device,struct vk_features * features)255 get_features(const struct panvk_physical_device *device,
256              struct vk_features *features)
257 {
258    unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
259 
260    *features = (struct vk_features){
261       /* Vulkan 1.0 */
262       .depthClamp = true,
263       .depthBiasClamp = true,
264       .robustBufferAccess = true,
265       .fullDrawIndexUint32 = true,
266       .imageCubeArray = true,
267       .independentBlend = true,
268       .sampleRateShading = true,
269       .logicOp = true,
270       .wideLines = true,
271       .largePoints = true,
272       .occlusionQueryPrecise = true,
273       .samplerAnisotropy = true,
274       .textureCompressionETC2 = true,
275       .textureCompressionASTC_LDR = true,
276       .fragmentStoresAndAtomics = arch >= 10,
277       .shaderUniformBufferArrayDynamicIndexing = true,
278       .shaderSampledImageArrayDynamicIndexing = true,
279       .shaderStorageBufferArrayDynamicIndexing = true,
280       .shaderStorageImageArrayDynamicIndexing = true,
281       .shaderInt16 = true,
282       .shaderInt64 = true,
283       .drawIndirectFirstInstance = true,
284 
285       /* Vulkan 1.1 */
286       .storageBuffer16BitAccess = true,
287       .uniformAndStorageBuffer16BitAccess = true,
288       .storagePushConstant16 = false,
289       .storageInputOutput16 = false,
290       .multiview = arch >= 10,
291       .multiviewGeometryShader = false,
292       .multiviewTessellationShader = false,
293       .variablePointersStorageBuffer = true,
294       .variablePointers = true,
295       .protectedMemory = false,
296       .samplerYcbcrConversion = false,
297       .shaderDrawParameters = true,
298 
299       /* Vulkan 1.2 */
300       .samplerMirrorClampToEdge = true,
301       .drawIndirectCount = false,
302       .storageBuffer8BitAccess = true,
303       .uniformAndStorageBuffer8BitAccess = false,
304       .storagePushConstant8 = false,
305       .shaderBufferInt64Atomics = false,
306       .shaderSharedInt64Atomics = false,
307       .shaderFloat16 = false,
308       .shaderInt8 = true,
309 
310       .descriptorIndexing = false,
311       .shaderInputAttachmentArrayDynamicIndexing = false,
312       .shaderUniformTexelBufferArrayDynamicIndexing = false,
313       .shaderStorageTexelBufferArrayDynamicIndexing = false,
314       .shaderUniformBufferArrayNonUniformIndexing = false,
315       .shaderSampledImageArrayNonUniformIndexing = false,
316       .shaderStorageBufferArrayNonUniformIndexing = false,
317       .shaderStorageImageArrayNonUniformIndexing = false,
318       .shaderInputAttachmentArrayNonUniformIndexing = false,
319       .shaderUniformTexelBufferArrayNonUniformIndexing = false,
320       .shaderStorageTexelBufferArrayNonUniformIndexing = false,
321       .descriptorBindingUniformBufferUpdateAfterBind = false,
322       .descriptorBindingSampledImageUpdateAfterBind = false,
323       .descriptorBindingStorageImageUpdateAfterBind = false,
324       .descriptorBindingStorageBufferUpdateAfterBind = false,
325       .descriptorBindingUniformTexelBufferUpdateAfterBind = false,
326       .descriptorBindingStorageTexelBufferUpdateAfterBind = false,
327       .descriptorBindingUpdateUnusedWhilePending = false,
328       .descriptorBindingPartiallyBound = false,
329       .descriptorBindingVariableDescriptorCount = false,
330       .runtimeDescriptorArray = false,
331 
332       .samplerFilterMinmax = arch >= 10,
333       .scalarBlockLayout = true,
334       .imagelessFramebuffer = false,
335       .uniformBufferStandardLayout = false,
336       .shaderSubgroupExtendedTypes = false,
337       .separateDepthStencilLayouts = false,
338       .hostQueryReset = true,
339       .timelineSemaphore = true,
340       .bufferDeviceAddress = true,
341       .bufferDeviceAddressCaptureReplay = false,
342       .bufferDeviceAddressMultiDevice = false,
343       .vulkanMemoryModel = false,
344       .vulkanMemoryModelDeviceScope = false,
345       .vulkanMemoryModelAvailabilityVisibilityChains = false,
346       .shaderOutputViewportIndex = false,
347       .shaderOutputLayer = false,
348       .subgroupBroadcastDynamicId = false,
349 
350       /* Vulkan 1.3 */
351       .robustImageAccess = true,
352       .inlineUniformBlock = false,
353       .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
354       .pipelineCreationCacheControl = true,
355       .privateData = true,
356       .shaderDemoteToHelperInvocation = false,
357       .shaderTerminateInvocation = false,
358       .subgroupSizeControl = false,
359       .computeFullSubgroups = false,
360       .synchronization2 = true,
361       .textureCompressionASTC_HDR = false,
362       .shaderZeroInitializeWorkgroupMemory = true,
363       .dynamicRendering = true,
364       .shaderIntegerDotProduct = false,
365       .maintenance4 = false,
366 
367       /* VK_EXT_graphics_pipeline_library */
368       .graphicsPipelineLibrary = true,
369 
370       /* VK_KHR_global_priority */
371       .globalPriorityQuery = true,
372 
373       /* VK_KHR_index_type_uint8 */
374       .indexTypeUint8 = true,
375 
376       /* VK_KHR_vertex_attribute_divisor */
377       .vertexAttributeInstanceRateDivisor = true,
378       .vertexAttributeInstanceRateZeroDivisor = true,
379 
380       /* VK_EXT_depth_clip_enable */
381       .depthClipEnable = true,
382 
383       /* VK_EXT_4444_formats */
384       .formatA4R4G4B4 = true,
385       .formatA4B4G4R4 = true,
386 
387       /* VK_EXT_custom_border_color */
388       .customBorderColors = true,
389 
390       /* VK_EXT_provoking_vertex */
391       .provokingVertexLast = true,
392       .transformFeedbackPreservesProvokingVertex = false,
393 
394       /* v7 doesn't support AFBC(BGR). We need to tweak the texture swizzle to
395        * make it work, which forces us to apply the same swizzle on the border
396        * color, meaning we need to know the format when preparing the border
397        * color.
398        */
399       .customBorderColorWithoutFormat = arch != 7,
400 
401       /* VK_KHR_pipeline_executable_properties */
402       .pipelineExecutableInfo = true,
403 
404       /* VK_EXT_pipeline_robustness */
405       .pipelineRobustness = true,
406 
407       /* VK_KHR_shader_relaxed_extended_instruction */
408       .shaderRelaxedExtendedInstruction = true,
409 
410       /* VK_KHR_shader_expect_assume */
411       .shaderExpectAssume = true,
412 
413       /* VK_EXT_shader_module_identifier */
414       .shaderModuleIdentifier = true,
415    };
416 }
417 
418 static uint32_t
get_vk_version()419 get_vk_version()
420 {
421    const uint32_t version_override = vk_get_version_override();
422    if (version_override)
423       return version_override;
424    return VK_MAKE_API_VERSION(0, 1, 0, VK_HEADER_VERSION);
425 }
426 
427 static void
get_device_properties(const struct panvk_instance * instance,const struct panvk_physical_device * device,struct vk_properties * properties)428 get_device_properties(const struct panvk_instance *instance,
429                       const struct panvk_physical_device *device,
430                       struct vk_properties *properties)
431 {
432    /* HW supports MSAA 4, 8 and 16, but we limit ourselves to MSAA 4 for now. */
433    VkSampleCountFlags sample_counts =
434       VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
435 
436    uint64_t os_page_size = 4096;
437    os_get_page_size(&os_page_size);
438 
439    unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
440 
441    /* Ensure that the max threads count per workgroup is valid for Bifrost */
442    assert(arch > 8 || device->kmod.props.max_threads_per_wg <= 1024);
443 
444    *properties = (struct vk_properties){
445       .apiVersion = get_vk_version(),
446       .driverVersion = vk_get_driver_version(),
447       .vendorID = ARM_VENDOR_ID,
448 
449       /* Collect arch_major, arch_minor, arch_rev and product_major,
450        * as done by the Arm driver.
451        */
452       .deviceID = device->kmod.props.gpu_prod_id << 16,
453       .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
454 
455       /* Vulkan 1.0 limits */
456       /* Maximum texture dimension is 2^16. */
457       .maxImageDimension1D = (1 << 16),
458       .maxImageDimension2D = (1 << 16),
459       .maxImageDimension3D = (1 << 16),
460       .maxImageDimensionCube = (1 << 16),
461       .maxImageArrayLayers = (1 << 16),
462       /* Currently limited by the 1D texture size, which is 2^16.
463        * TODO: If we expose buffer views as 2D textures, we can increase the
464        * limit.
465        */
466       .maxTexelBufferElements = (1 << 16),
467       /* Each uniform entry is 16-byte and the number of entries is encoded in a
468        * 12-bit field, with the minus(1) modifier, which gives 2^20.
469        */
470       .maxUniformBufferRange = 1 << 20,
471       /* Storage buffer access is lowered to globals, so there's no limit here,
472        * except for the SW-descriptor we use to encode storage buffer
473        * descriptors, where the size is a 32-bit field.
474        */
475       .maxStorageBufferRange = UINT32_MAX,
476       /* 128 bytes of push constants, so we're aligned with the minimum Vulkan
477        * requirements.
478        */
479       .maxPushConstantsSize = 128,
480       /* On our kernel drivers we're limited by the available memory rather
481        * than available allocations. This is better expressed through memory
482        * properties and budget queries, and by returning
483        * VK_ERROR_OUT_OF_DEVICE_MEMORY when applicable, rather than
484        * this limit.
485        */
486       .maxMemoryAllocationCount = UINT32_MAX,
487       /* On Mali, VkSampler objects do not use any resources other than host
488        * memory and host address space, availability of which can change
489        * significantly over time.
490        */
491       .maxSamplerAllocationCount = UINT32_MAX,
492       /* A cache line. */
493       .bufferImageGranularity = 64,
494       /* Sparse binding not supported yet. */
495       .sparseAddressSpaceSize = 0,
496       /* On Bifrost, this is a software limit. We pick the minimum required by
497        * Vulkan, because Bifrost GPUs don't have unified descriptor tables,
498        * which forces us to agregatte all descriptors from all sets and dispatch
499        * them to per-type descriptor tables emitted at draw/dispatch time. The
500        * more sets we support the more copies we are likely to have to do at
501        * draw time.
502        *
503        * Valhall has native support for descriptor sets, and allows a maximum
504        * of 16 sets, but we reserve one for our internal use, so we have 15
505        * left.
506        */
507       .maxBoundDescriptorSets = arch <= 7 ? 4 : 15,
508       /* MALI_RENDERER_STATE::sampler_count is 16-bit. */
509       .maxDescriptorSetSamplers = UINT16_MAX,
510       /* MALI_RENDERER_STATE::uniform_buffer_count is 8-bit. We reserve 32 slots
511        * for our internal UBOs.
512        */
513       .maxPerStageDescriptorUniformBuffers = UINT8_MAX - 32,
514       .maxDescriptorSetUniformBuffers = UINT8_MAX - 32,
515       /* SSBOs are limited by the size of a uniform buffer which contains our
516        * panvk_ssbo_desc objects.
517        * panvk_ssbo_desc is 16-byte, and each uniform entry in the Mali UBO is
518        * 16-byte too. The number of entries is encoded in a 12-bit field, with
519        * a minus(1) modifier, which gives a maximum of 2^12 SSBO
520        * descriptors.
521        */
522       .maxDescriptorSetStorageBuffers = 1 << 12,
523       /* MALI_RENDERER_STATE::sampler_count is 16-bit. */
524       .maxDescriptorSetSampledImages = UINT16_MAX,
525       /* MALI_ATTRIBUTE::buffer_index is 9-bit, and each image takes two
526        * MALI_ATTRIBUTE_BUFFER slots, which gives a maximum of (1 << 8) images.
527        */
528       .maxDescriptorSetStorageImages = 1 << 8,
529       /* A maximum of 8 color render targets, and one depth-stencil render
530        * target.
531        */
532       .maxDescriptorSetInputAttachments = 9,
533 
534       /* We could theoretically use the maxDescriptor values here (except for
535        * UBOs where we're really limited to 256 on the shader side), but on
536        * Bifrost we have to copy some tables around, which comes at an extra
537        * memory/processing cost, so let's pick something smaller.
538        */
539       .maxPerStageDescriptorInputAttachments = 9,
540       .maxPerStageDescriptorSampledImages = 256,
541       .maxPerStageDescriptorSamplers = 128,
542       .maxPerStageDescriptorStorageBuffers = 64,
543       .maxPerStageDescriptorStorageImages = 32,
544       .maxPerStageDescriptorUniformBuffers = 64,
545       .maxPerStageResources = 9 + 256 + 128 + 64 + 32 + 64,
546 
547       /* Software limits to keep VkCommandBuffer tracking sane. */
548       .maxDescriptorSetUniformBuffersDynamic = 16,
549       .maxDescriptorSetStorageBuffersDynamic = 8,
550       /* Software limit to keep VkCommandBuffer tracking sane. The HW supports
551        * up to 2^9 vertex attributes.
552        */
553       .maxVertexInputAttributes = 16,
554       .maxVertexInputBindings = 16,
555       /* MALI_ATTRIBUTE::offset is 32-bit. */
556       .maxVertexInputAttributeOffset = UINT32_MAX,
557       /* MALI_ATTRIBUTE_BUFFER::stride is 32-bit. */
558       .maxVertexInputBindingStride = MESA_VK_MAX_VERTEX_BINDING_STRIDE,
559       /* 32 vec4 varyings. */
560       .maxVertexOutputComponents = 128,
561       /* Tesselation shaders not supported. */
562       .maxTessellationGenerationLevel = 0,
563       .maxTessellationPatchSize = 0,
564       .maxTessellationControlPerVertexInputComponents = 0,
565       .maxTessellationControlPerVertexOutputComponents = 0,
566       .maxTessellationControlPerPatchOutputComponents = 0,
567       .maxTessellationControlTotalOutputComponents = 0,
568       .maxTessellationEvaluationInputComponents = 0,
569       .maxTessellationEvaluationOutputComponents = 0,
570       /* Geometry shaders not supported. */
571       .maxGeometryShaderInvocations = 0,
572       .maxGeometryInputComponents = 0,
573       .maxGeometryOutputComponents = 0,
574       .maxGeometryOutputVertices = 0,
575       .maxGeometryTotalOutputComponents = 0,
576       /* 32 vec4 varyings. */
577       .maxFragmentInputComponents = 128,
578       /* 8 render targets. */
579       .maxFragmentOutputAttachments = 8,
580       /* We don't support dual source blending yet. */
581       .maxFragmentDualSrcAttachments = 0,
582       /* 8 render targets, 2^12 storage buffers and 2^8 storage images (see
583        * above).
584        */
585       .maxFragmentCombinedOutputResources = 8 + (1 << 12) + (1 << 8),
586       /* MALI_LOCAL_STORAGE::wls_size_{base,scale} allows us to have up to
587        * (7 << 30) bytes of shared memory, but we cap it to 32K as it doesn't
588        * really make sense to expose this amount of memory, especially since
589        * it's backed by global memory anyway.
590        */
591       .maxComputeSharedMemorySize = 32768,
592       /* Software limit to meet Vulkan 1.0 requirements. We split the
593        * dispatch in several jobs if it's too big.
594        */
595       .maxComputeWorkGroupCount = {65535, 65535, 65535},
596 
597       /* We could also split into serveral jobs but this has many limitations.
598        * As such we limit to the max threads per workgroup supported by the GPU.
599        */
600       .maxComputeWorkGroupInvocations = device->kmod.props.max_threads_per_wg,
601       .maxComputeWorkGroupSize = {device->kmod.props.max_threads_per_wg,
602                                   device->kmod.props.max_threads_per_wg,
603                                   device->kmod.props.max_threads_per_wg},
604       /* 8-bit subpixel precision. */
605       .subPixelPrecisionBits = 8,
606       .subTexelPrecisionBits = 8,
607       .mipmapPrecisionBits = 8,
608       /* Software limit. */
609       .maxDrawIndexedIndexValue = UINT32_MAX,
610       /* Make it one for now. */
611       .maxDrawIndirectCount = 1,
612       .maxSamplerLodBias = (float)INT16_MAX / 256.0f,
613       .maxSamplerAnisotropy = 16,
614       .maxViewports = 1,
615       /* Same as the framebuffer limit. */
616       .maxViewportDimensions = {(1 << 14), (1 << 14)},
617       /* Encoded in a 16-bit signed integer. */
618       .viewportBoundsRange = {INT16_MIN, INT16_MAX},
619       .viewportSubPixelBits = 0,
620       /* Align on a page. */
621       .minMemoryMapAlignment = os_page_size,
622       /* Some compressed texture formats require 128-byte alignment. */
623       .minTexelBufferOffsetAlignment = 64,
624       /* Always aligned on a uniform slot (vec4). */
625       .minUniformBufferOffsetAlignment = 16,
626       /* Lowered to global accesses, which happen at the 32-bit granularity. */
627       .minStorageBufferOffsetAlignment = 4,
628       /* Signed 4-bit value. */
629       .minTexelOffset = -8,
630       .maxTexelOffset = 7,
631       .minTexelGatherOffset = -8,
632       .maxTexelGatherOffset = 7,
633       .minInterpolationOffset = -0.5,
634       .maxInterpolationOffset = 0.5,
635       .subPixelInterpolationOffsetBits = 8,
636       .maxFramebufferWidth = (1 << 14),
637       .maxFramebufferHeight = (1 << 14),
638       .maxFramebufferLayers = 256,
639       .framebufferColorSampleCounts = sample_counts,
640       .framebufferDepthSampleCounts = sample_counts,
641       .framebufferStencilSampleCounts = sample_counts,
642       .framebufferNoAttachmentsSampleCounts = sample_counts,
643       .maxColorAttachments = 8,
644       .sampledImageColorSampleCounts = sample_counts,
645       .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT,
646       .sampledImageDepthSampleCounts = sample_counts,
647       .sampledImageStencilSampleCounts = sample_counts,
648       .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
649       .maxSampleMaskWords = 1,
650       .timestampComputeAndGraphics = false,
651       .timestampPeriod = 0,
652       .maxClipDistances = 0,
653       .maxCullDistances = 0,
654       .maxCombinedClipAndCullDistances = 0,
655       .discreteQueuePriorities = 2,
656       .pointSizeRange = {0.125, 4095.9375},
657       .lineWidthRange = {0.0, 7.9921875},
658       .pointSizeGranularity = (1.0 / 16.0),
659       .lineWidthGranularity = (1.0 / 128.0),
660       .strictLines = false,
661       .standardSampleLocations = true,
662       .optimalBufferCopyOffsetAlignment = 64,
663       .optimalBufferCopyRowPitchAlignment = 64,
664       .nonCoherentAtomSize = 64,
665 
666       /* Vulkan 1.0 sparse properties */
667       .sparseResidencyNonResidentStrict = false,
668       .sparseResidencyAlignedMipSize = false,
669       .sparseResidencyStandard2DBlockShape = false,
670       .sparseResidencyStandard2DMultisampleBlockShape = false,
671       .sparseResidencyStandard3DBlockShape = false,
672 
673       /* Vulkan 1.1 properties */
674       /* XXX: 1.1 support */
675       .subgroupSize = 8,
676       .subgroupSupportedStages = 0,
677       .subgroupSupportedOperations = 0,
678       .subgroupQuadOperationsInAllStages = false,
679       .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
680       .maxMultiviewViewCount = arch >= 10 ? 8 : 0,
681       .maxMultiviewInstanceIndex = arch >= 10 ? UINT32_MAX : 0,
682       .protectedNoFault = false,
683       .maxPerSetDescriptors = UINT16_MAX,
684       /* Our buffer size fields allow only this much */
685       .maxMemoryAllocationSize = UINT32_MAX,
686 
687       /* Vulkan 1.2 properties */
688       /* XXX: 1.2 support */
689       /* XXX: VK_KHR_depth_stencil_resolve */
690       .supportedDepthResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
691       .supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
692       .independentResolveNone = true,
693       .independentResolve = true,
694       /* VK_KHR_driver_properties */
695       .driverID = VK_DRIVER_ID_MESA_PANVK,
696       .conformanceVersion = (VkConformanceVersion){0, 0, 0, 0},
697       /* XXX: VK_KHR_shader_float_controls */
698       .denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
699       .roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
700       .shaderSignedZeroInfNanPreserveFloat16 = true,
701       .shaderSignedZeroInfNanPreserveFloat32 = true,
702       .shaderSignedZeroInfNanPreserveFloat64 = false,
703       .shaderDenormPreserveFloat16 = true,
704       .shaderDenormPreserveFloat32 = true,
705       .shaderDenormPreserveFloat64 = false,
706       .shaderDenormFlushToZeroFloat16 = true,
707       .shaderDenormFlushToZeroFloat32 = true,
708       .shaderDenormFlushToZeroFloat64 = false,
709       .shaderRoundingModeRTEFloat16 = true,
710       .shaderRoundingModeRTEFloat32 = true,
711       .shaderRoundingModeRTEFloat64 = false,
712       .shaderRoundingModeRTZFloat16 = true,
713       .shaderRoundingModeRTZFloat32 = true,
714       .shaderRoundingModeRTZFloat64 = false,
715       /* XXX: VK_EXT_descriptor_indexing */
716       .maxUpdateAfterBindDescriptorsInAllPools = 0,
717       .shaderUniformBufferArrayNonUniformIndexingNative = false,
718       .shaderSampledImageArrayNonUniformIndexingNative = false,
719       .shaderStorageBufferArrayNonUniformIndexingNative = false,
720       .shaderStorageImageArrayNonUniformIndexingNative = false,
721       .shaderInputAttachmentArrayNonUniformIndexingNative = false,
722       .robustBufferAccessUpdateAfterBind = false,
723       .quadDivergentImplicitLod = false,
724       .maxPerStageDescriptorUpdateAfterBindSamplers = 0,
725       .maxPerStageDescriptorUpdateAfterBindUniformBuffers = 0,
726       .maxPerStageDescriptorUpdateAfterBindStorageBuffers = 0,
727       .maxPerStageDescriptorUpdateAfterBindSampledImages = 0,
728       .maxPerStageDescriptorUpdateAfterBindStorageImages = 0,
729       .maxPerStageDescriptorUpdateAfterBindInputAttachments = 0,
730       .maxPerStageUpdateAfterBindResources = 0,
731       .maxDescriptorSetUpdateAfterBindSamplers = 0,
732       .maxDescriptorSetUpdateAfterBindUniformBuffers = 0,
733       .maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = 0,
734       .maxDescriptorSetUpdateAfterBindStorageBuffers = 0,
735       .maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = 0,
736       .maxDescriptorSetUpdateAfterBindSampledImages = 0,
737       .maxDescriptorSetUpdateAfterBindStorageImages = 0,
738       .maxDescriptorSetUpdateAfterBindInputAttachments = 0,
739       .filterMinmaxSingleComponentFormats = arch >= 10,
740       .filterMinmaxImageComponentMapping = arch >= 10,
741       .maxTimelineSemaphoreValueDifference = INT64_MAX,
742       .framebufferIntegerColorSampleCounts = sample_counts,
743 
744       /* Vulkan 1.3 properties */
745       /* XXX: 1.3 support */
746       /* XXX: VK_EXT_subgroup_size_control */
747       .minSubgroupSize = 8,
748       .maxSubgroupSize = 8,
749       .maxComputeWorkgroupSubgroups = 48,
750       .requiredSubgroupSizeStages = VK_SHADER_STAGE_ALL,
751       /* XXX: VK_EXT_inline_uniform_block */
752       .maxInlineUniformBlockSize = MAX_INLINE_UNIFORM_BLOCK_SIZE,
753       .maxPerStageDescriptorInlineUniformBlocks =
754          MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS,
755       .maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks =
756          MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS,
757       .maxDescriptorSetInlineUniformBlocks =
758          MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS,
759       .maxDescriptorSetUpdateAfterBindInlineUniformBlocks =
760          MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS,
761       .maxInlineUniformTotalSize =
762          MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS * MAX_INLINE_UNIFORM_BLOCK_SIZE,
763       /* XXX: VK_KHR_shader_integer_dot_product */
764       .integerDotProduct8BitUnsignedAccelerated = true,
765       .integerDotProduct8BitSignedAccelerated = true,
766       .integerDotProduct4x8BitPackedUnsignedAccelerated = true,
767       .integerDotProduct4x8BitPackedSignedAccelerated = true,
768       /* XXX: VK_EXT_texel_buffer_alignment */
769       .storageTexelBufferOffsetAlignmentBytes = 64,
770       .storageTexelBufferOffsetSingleTexelAlignment = false,
771       .uniformTexelBufferOffsetAlignmentBytes = 4,
772       .uniformTexelBufferOffsetSingleTexelAlignment = true,
773       /* XXX: VK_KHR_maintenance4 */
774       .maxBufferSize = 1 << 30,
775 
776       /* VK_EXT_custom_border_color */
777       .maxCustomBorderColorSamplers = 32768,
778 
779       /* VK_EXT_graphics_pipeline_library */
780       .graphicsPipelineLibraryFastLinking = true,
781       .graphicsPipelineLibraryIndependentInterpolationDecoration = true,
782 
783       /* VK_EXT_pipeline_robustness */
784       .defaultRobustnessStorageBuffers =
785          VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT,
786       .defaultRobustnessUniformBuffers =
787          VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT,
788       .defaultRobustnessVertexInputs =
789          VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT,
790       .defaultRobustnessImages =
791          VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT,
792 
793       /* VK_EXT_provoking_vertex */
794       .provokingVertexModePerPipeline = false,
795       .transformFeedbackPreservesTriangleFanProvokingVertex = false,
796 
797       /* VK_KHR_vertex_attribute_divisor */
798       /* We will have to restrict this a bit for multiview */
799       .maxVertexAttribDivisor = UINT32_MAX,
800       .supportsNonZeroFirstInstance = false,
801 
802       /* VK_KHR_push_descriptor */
803       .maxPushDescriptors = MAX_PUSH_DESCRIPTORS,
804    };
805 
806    snprintf(properties->deviceName, sizeof(properties->deviceName), "%s",
807             device->name);
808 
809    memcpy(properties->pipelineCacheUUID, device->cache_uuid, VK_UUID_SIZE);
810 
811    const struct {
812       uint16_t vendor_id;
813       uint32_t device_id;
814       uint8_t pad[8];
815    } dev_uuid = {
816       .vendor_id = ARM_VENDOR_ID,
817       .device_id = device->model->gpu_id,
818    };
819 
820    STATIC_ASSERT(sizeof(dev_uuid) == VK_UUID_SIZE);
821    memcpy(properties->deviceUUID, &dev_uuid, VK_UUID_SIZE);
822    STATIC_ASSERT(sizeof(instance->driver_build_sha) >= VK_UUID_SIZE);
823    memcpy(properties->driverUUID, instance->driver_build_sha, VK_UUID_SIZE);
824 
825    snprintf(properties->driverName, VK_MAX_DRIVER_NAME_SIZE, "panvk");
826    snprintf(properties->driverInfo, VK_MAX_DRIVER_INFO_SIZE,
827             "Mesa " PACKAGE_VERSION MESA_GIT_SHA1);
828 
829    /* VK_EXT_physical_device_drm */
830    if (device->drm.primary_rdev) {
831       properties->drmHasPrimary = true;
832       properties->drmPrimaryMajor = major(device->drm.primary_rdev);
833       properties->drmPrimaryMinor = minor(device->drm.primary_rdev);
834    }
835    if (device->drm.render_rdev) {
836       properties->drmHasRender = true;
837       properties->drmRenderMajor = major(device->drm.render_rdev);
838       properties->drmRenderMinor = minor(device->drm.render_rdev);
839    }
840 
841    /* VK_EXT_shader_module_identifier */
842    STATIC_ASSERT(sizeof(vk_shaderModuleIdentifierAlgorithmUUID) ==
843                  sizeof(properties->shaderModuleIdentifierAlgorithmUUID));
844    memcpy(properties->shaderModuleIdentifierAlgorithmUUID,
845           vk_shaderModuleIdentifierAlgorithmUUID,
846           sizeof(properties->shaderModuleIdentifierAlgorithmUUID));
847 }
848 
849 void
panvk_physical_device_finish(struct panvk_physical_device * device)850 panvk_physical_device_finish(struct panvk_physical_device *device)
851 {
852    panvk_wsi_finish(device);
853 
854    pan_kmod_dev_destroy(device->kmod.dev);
855 
856    vk_physical_device_finish(&device->vk);
857 }
858 
859 VkResult
panvk_physical_device_init(struct panvk_physical_device * device,struct panvk_instance * instance,drmDevicePtr drm_device)860 panvk_physical_device_init(struct panvk_physical_device *device,
861                            struct panvk_instance *instance,
862                            drmDevicePtr drm_device)
863 {
864    VkResult result;
865 
866    result = create_kmod_dev(device, instance, drm_device);
867    if (result != VK_SUCCESS)
868       return result;
869 
870    pan_kmod_dev_query_props(device->kmod.dev, &device->kmod.props);
871 
872    device->model = panfrost_get_model(device->kmod.props.gpu_prod_id,
873                                       device->kmod.props.gpu_variant);
874 
875    unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
876 
877    switch (arch) {
878    case 6:
879    case 7:
880       if (!getenv("PAN_I_WANT_A_BROKEN_VULKAN_DRIVER")) {
881          result = panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
882                                "WARNING: panvk is not well-tested on v%d, "
883                                "pass PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 "
884                                "if you know what you're doing.", arch);
885          goto fail;
886       }
887       break;
888 
889    case 10:
890       break;
891 
892    default:
893       result = panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
894                             "%s not supported", device->model->name);
895       goto fail;
896    }
897 
898    result = get_drm_device_ids(device, instance, drm_device);
899    if (result != VK_SUCCESS)
900       goto fail;
901 
902    device->formats.all = panfrost_format_table(arch);
903    device->formats.blendable = panfrost_blendable_format_table(arch);
904 
905    memset(device->name, 0, sizeof(device->name));
906    sprintf(device->name, "%s", device->model->name);
907 
908    if (get_cache_uuid(device->kmod.props.gpu_prod_id, device->cache_uuid)) {
909       result = panvk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
910                             "cannot generate UUID");
911       goto fail;
912    }
913 
914    result = get_device_sync_types(device, instance);
915    if (result != VK_SUCCESS)
916       goto fail;
917 
918    vk_warn_non_conformant_implementation("panvk");
919 
920    struct vk_device_extension_table supported_extensions;
921    get_device_extensions(device, &supported_extensions);
922 
923    struct vk_features supported_features;
924    get_features(device, &supported_features);
925 
926    struct vk_properties properties;
927    get_device_properties(instance, device, &properties);
928 
929    struct vk_physical_device_dispatch_table dispatch_table;
930    vk_physical_device_dispatch_table_from_entrypoints(
931       &dispatch_table, &panvk_physical_device_entrypoints, true);
932    vk_physical_device_dispatch_table_from_entrypoints(
933       &dispatch_table, &wsi_physical_device_entrypoints, false);
934 
935    result = vk_physical_device_init(&device->vk, &instance->vk,
936                                     &supported_extensions, &supported_features,
937                                     &properties, &dispatch_table);
938 
939    if (result != VK_SUCCESS)
940       goto fail;
941 
942    device->vk.supported_sync_types = device->sync_types;
943 
944    result = panvk_wsi_init(device);
945    if (result != VK_SUCCESS)
946       goto fail;
947 
948    return VK_SUCCESS;
949 
950 fail:
951    if (device->vk.instance)
952       vk_physical_device_finish(&device->vk);
953 
954    pan_kmod_dev_destroy(device->kmod.dev);
955 
956    return result;
957 }
958 
959 static const VkQueueFamilyProperties panvk_queue_family_properties = {
960    .queueFlags =
961       VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
962    .queueCount = 1,
963    .timestampValidBits = 0,
964    .minImageTransferGranularity = {1, 1, 1},
965 };
966 
967 static void
panvk_fill_global_priority(const struct panvk_physical_device * physical_device,VkQueueFamilyGlobalPriorityPropertiesKHR * prio)968 panvk_fill_global_priority(const struct panvk_physical_device *physical_device,
969                            VkQueueFamilyGlobalPriorityPropertiesKHR *prio)
970 {
971    enum pan_kmod_group_allow_priority_flags prio_mask =
972       physical_device->kmod.props.allowed_group_priorities_mask;
973    uint32_t prio_idx = 0;
974 
975    if (prio_mask & PAN_KMOD_GROUP_ALLOW_PRIORITY_LOW)
976       prio->priorities[prio_idx++] = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR;
977 
978    if (prio_mask & PAN_KMOD_GROUP_ALLOW_PRIORITY_MEDIUM)
979       prio->priorities[prio_idx++] = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
980 
981    if (prio_mask & PAN_KMOD_GROUP_ALLOW_PRIORITY_HIGH)
982       prio->priorities[prio_idx++] = VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR;
983 
984    if (prio_mask & PAN_KMOD_GROUP_ALLOW_PRIORITY_REALTIME)
985       prio->priorities[prio_idx++] = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR;
986 
987    prio->priorityCount = prio_idx;
988 }
989 
990 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)991 panvk_GetPhysicalDeviceQueueFamilyProperties2(
992    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
993    VkQueueFamilyProperties2 *pQueueFamilyProperties)
994 {
995    VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
996    VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out, pQueueFamilyProperties,
997                           pQueueFamilyPropertyCount);
998 
999    vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p)
1000    {
1001       p->queueFamilyProperties = panvk_queue_family_properties;
1002 
1003       VkQueueFamilyGlobalPriorityPropertiesKHR *prio =
1004          vk_find_struct(p->pNext, QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR);
1005       if (prio)
1006          panvk_fill_global_priority(physical_device, prio);
1007    }
1008 }
1009 
1010 static uint64_t
get_system_heap_size()1011 get_system_heap_size()
1012 {
1013    struct sysinfo info;
1014    sysinfo(&info);
1015 
1016    uint64_t total_ram = (uint64_t)info.totalram * info.mem_unit;
1017 
1018    /* We don't want to burn too much ram with the GPU.  If the user has 4GiB
1019     * or less, we use at most half.  If they have more than 4GiB, we use 3/4.
1020     */
1021    uint64_t available_ram;
1022    if (total_ram <= 4ull * 1024 * 1024 * 1024)
1023       available_ram = total_ram / 2;
1024    else
1025       available_ram = total_ram * 3 / 4;
1026 
1027    return available_ram;
1028 }
1029 
1030 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)1031 panvk_GetPhysicalDeviceMemoryProperties2(
1032    VkPhysicalDevice physicalDevice,
1033    VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1034 {
1035    pMemoryProperties->memoryProperties = (VkPhysicalDeviceMemoryProperties){
1036       .memoryHeapCount = 1,
1037       .memoryHeaps[0].size = get_system_heap_size(),
1038       .memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
1039       .memoryTypeCount = 1,
1040       .memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1041                                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1042                                       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
1043       .memoryTypes[0].heapIndex = 0,
1044    };
1045 }
1046 
1047 #define DEVICE_PER_ARCH_FUNCS(_ver)                                            \
1048    VkResult panvk_v##_ver##_create_device(                                     \
1049       struct panvk_physical_device *physical_device,                           \
1050       const VkDeviceCreateInfo *pCreateInfo,                                   \
1051       const VkAllocationCallbacks *pAllocator, VkDevice *pDevice);             \
1052                                                                                \
1053    void panvk_v##_ver##_destroy_device(                                        \
1054       struct panvk_device *device, const VkAllocationCallbacks *pAllocator)
1055 
1056 DEVICE_PER_ARCH_FUNCS(6);
1057 DEVICE_PER_ARCH_FUNCS(7);
1058 DEVICE_PER_ARCH_FUNCS(10);
1059 
1060 VKAPI_ATTR VkResult VKAPI_CALL
panvk_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)1061 panvk_CreateDevice(VkPhysicalDevice physicalDevice,
1062                    const VkDeviceCreateInfo *pCreateInfo,
1063                    const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
1064 {
1065    VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
1066    unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id);
1067    VkResult result = VK_ERROR_INITIALIZATION_FAILED;
1068 
1069    panvk_arch_dispatch_ret(arch, create_device, result, physical_device,
1070                            pCreateInfo, pAllocator, pDevice);
1071 
1072    return result;
1073 }
1074 
1075 VKAPI_ATTR void VKAPI_CALL
panvk_DestroyDevice(VkDevice _device,const VkAllocationCallbacks * pAllocator)1076 panvk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
1077 {
1078    VK_FROM_HANDLE(panvk_device, device, _device);
1079    struct panvk_physical_device *physical_device =
1080       to_panvk_physical_device(device->vk.physical);
1081    unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id);
1082 
1083    panvk_arch_dispatch(arch, destroy_device, device, pAllocator);
1084 }
1085 
1086 static bool
format_is_supported(struct panvk_physical_device * physical_device,const struct panfrost_format fmt,enum pipe_format pfmt)1087 format_is_supported(struct panvk_physical_device *physical_device,
1088                     const struct panfrost_format fmt,
1089                     enum pipe_format pfmt)
1090 {
1091    /* If the format ID is zero, it's not supported. */
1092    if (!fmt.hw)
1093       return false;
1094 
1095    /* Compressed formats (ID < 32) are optional. We need to check against
1096     * the supported formats reported by the GPU. */
1097    if (util_format_is_compressed(pfmt)) {
1098       uint32_t supported_compr_fmts =
1099          panfrost_query_compressed_formats(&physical_device->kmod.props);
1100 
1101       if (!(BITFIELD_BIT(fmt.texfeat_bit) & supported_compr_fmts))
1102          return false;
1103    }
1104 
1105    return true;
1106 }
1107 
1108 static void
get_format_properties(struct panvk_physical_device * physical_device,VkFormat format,VkFormatProperties * out_properties)1109 get_format_properties(struct panvk_physical_device *physical_device,
1110                       VkFormat format, VkFormatProperties *out_properties)
1111 {
1112    VkFormatFeatureFlags tex = 0, buffer = 0;
1113    enum pipe_format pfmt = vk_format_to_pipe_format(format);
1114    unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id);
1115 
1116    if (pfmt == PIPE_FORMAT_NONE)
1117       goto end;
1118 
1119    const struct panfrost_format fmt = physical_device->formats.all[pfmt];
1120 
1121    if (!format_is_supported(physical_device, fmt, pfmt))
1122       goto end;
1123 
1124    /* 3byte formats are not supported by the buffer <-> image copy helpers. */
1125    if (util_format_get_blocksize(pfmt) == 3)
1126       goto end;
1127 
1128    /* Reject sRGB formats (see
1129     * https://github.com/KhronosGroup/Vulkan-Docs/issues/2214).
1130     */
1131    if ((fmt.bind & PAN_BIND_VERTEX_BUFFER) && !util_format_is_srgb(pfmt))
1132       buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
1133 
1134    if (fmt.bind & PAN_BIND_SAMPLER_VIEW) {
1135       tex |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
1136              VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
1137              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
1138              VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
1139              VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
1140 
1141       if (arch >= 10)
1142          tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT;
1143 
1144       /* Integer formats only support nearest filtering */
1145       if (!util_format_is_scaled(pfmt) && !util_format_is_pure_integer(pfmt))
1146          tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
1147 
1148       if (!util_format_is_depth_or_stencil(pfmt))
1149          buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
1150 
1151       tex |= VK_FORMAT_FEATURE_BLIT_SRC_BIT;
1152    }
1153 
1154    if (fmt.bind & PAN_BIND_RENDER_TARGET) {
1155       tex |= VK_FORMAT_FEATURE_BLIT_DST_BIT;
1156       tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
1157 
1158       /* SNORM rendering isn't working yet (nir_lower_blend bugs), disable for
1159        * now.
1160        *
1161        * XXX: Enable once fixed.
1162        */
1163       if (!util_format_is_snorm(pfmt)) {
1164          tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
1165          tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
1166       }
1167 
1168       if (!util_format_is_depth_and_stencil(pfmt))
1169          buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT;
1170    }
1171 
1172    if (pfmt == PIPE_FORMAT_R32_UINT || pfmt == PIPE_FORMAT_R32_SINT) {
1173       buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
1174       tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
1175    }
1176 
1177    if (fmt.bind & PAN_BIND_DEPTH_STENCIL)
1178       tex |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
1179 
1180 end:
1181    out_properties->linearTilingFeatures = tex;
1182    out_properties->optimalTilingFeatures = tex;
1183    out_properties->bufferFeatures = buffer;
1184 }
1185 
1186 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties2 * pFormatProperties)1187 panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
1188                                          VkFormat format,
1189                                          VkFormatProperties2 *pFormatProperties)
1190 {
1191    VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
1192 
1193    get_format_properties(physical_device, format,
1194                          &pFormatProperties->formatProperties);
1195 
1196    VkDrmFormatModifierPropertiesListEXT *list = vk_find_struct(
1197       pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
1198    if (list && pFormatProperties->formatProperties.linearTilingFeatures) {
1199       VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out,
1200                              list->pDrmFormatModifierProperties,
1201                              &list->drmFormatModifierCount);
1202 
1203       vk_outarray_append_typed(VkDrmFormatModifierPropertiesEXT, &out,
1204                                mod_props)
1205       {
1206          mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
1207          mod_props->drmFormatModifierPlaneCount = 1;
1208          mod_props->drmFormatModifierTilingFeatures =
1209             pFormatProperties->formatProperties.linearTilingFeatures;
1210       }
1211    }
1212 }
1213 
1214 static VkResult
get_image_format_properties(struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties * pImageFormatProperties,VkFormatFeatureFlags * p_feature_flags)1215 get_image_format_properties(struct panvk_physical_device *physical_device,
1216                             const VkPhysicalDeviceImageFormatInfo2 *info,
1217                             VkImageFormatProperties *pImageFormatProperties,
1218                             VkFormatFeatureFlags *p_feature_flags)
1219 {
1220    VkFormatProperties format_props;
1221    VkFormatFeatureFlags format_feature_flags;
1222    VkExtent3D maxExtent;
1223    uint32_t maxMipLevels;
1224    uint32_t maxArraySize;
1225    VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT;
1226    enum pipe_format format = vk_format_to_pipe_format(info->format);
1227 
1228    get_format_properties(physical_device, info->format, &format_props);
1229 
1230    switch (info->tiling) {
1231    case VK_IMAGE_TILING_LINEAR:
1232       format_feature_flags = format_props.linearTilingFeatures;
1233       break;
1234    case VK_IMAGE_TILING_OPTIMAL:
1235       format_feature_flags = format_props.optimalTilingFeatures;
1236       break;
1237    case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: {
1238       const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *mod_info =
1239          vk_find_struct_const(
1240             info->pNext, PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
1241       if (mod_info->drmFormatModifier != DRM_FORMAT_MOD_LINEAR)
1242          goto unsupported;
1243 
1244       /* The only difference between optimal and linear is currently whether
1245        * depth/stencil attachments are allowed on depth/stencil formats.
1246        * There's no reason to allow importing depth/stencil textures, so just
1247        * disallow it and then this annoying edge case goes away.
1248        */
1249       if (util_format_is_depth_or_stencil(format))
1250          goto unsupported;
1251 
1252       assert(format_props.optimalTilingFeatures ==
1253              format_props.linearTilingFeatures);
1254 
1255       format_feature_flags = format_props.linearTilingFeatures;
1256       break;
1257    }
1258    default:
1259       unreachable("bad VkPhysicalDeviceImageFormatInfo2");
1260    }
1261 
1262    if (format_feature_flags == 0)
1263       goto unsupported;
1264 
1265    switch (info->type) {
1266    default:
1267       unreachable("bad vkimage type");
1268    case VK_IMAGE_TYPE_1D:
1269       maxExtent.width = 1 << 16;
1270       maxExtent.height = 1;
1271       maxExtent.depth = 1;
1272       maxMipLevels = 17; /* log2(maxWidth) + 1 */
1273       maxArraySize = 1 << 16;
1274       break;
1275    case VK_IMAGE_TYPE_2D:
1276       maxExtent.width = 1 << 16;
1277       maxExtent.height = 1 << 16;
1278       maxExtent.depth = 1;
1279       maxMipLevels = 17; /* log2(maxWidth) + 1 */
1280       maxArraySize = 1 << 16;
1281       break;
1282    case VK_IMAGE_TYPE_3D:
1283       maxExtent.width = 1 << 16;
1284       maxExtent.height = 1 << 16;
1285       maxExtent.depth = 1 << 16;
1286       maxMipLevels = 17; /* log2(maxWidth) + 1 */
1287       maxArraySize = 1;
1288       break;
1289    }
1290 
1291    if (info->tiling == VK_IMAGE_TILING_OPTIMAL &&
1292        info->type == VK_IMAGE_TYPE_2D &&
1293        (format_feature_flags &
1294         (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
1295          VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
1296        !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
1297        !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
1298       sampleCounts |= VK_SAMPLE_COUNT_4_BIT;
1299    }
1300 
1301    /* From the Vulkan 1.2.199 spec:
1302    *
1303    *    "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT specifies that the image can be
1304    *    created with usage flags that are not supported for the format the
1305    *    image is created with but are supported for at least one format a
1306    *    VkImageView created from the image can have."
1307    *
1308    * If VK_IMAGE_CREATE_EXTENDED_USAGE_BIT is set, views can be created with
1309    * different usage than the image so we can't always filter on usage.
1310    * There is one exception to this below for storage.
1311    */
1312    if (!(info->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)) {
1313       if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
1314          if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
1315             goto unsupported;
1316          }
1317       }
1318 
1319       if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) {
1320          if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
1321             goto unsupported;
1322          }
1323       }
1324 
1325       if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
1326           ((info->usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
1327            !vk_format_is_depth_or_stencil(info->format))) {
1328          if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
1329             goto unsupported;
1330          }
1331       }
1332 
1333       if ((info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
1334           ((info->usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
1335            vk_format_is_depth_or_stencil(info->format))) {
1336          if (!(format_feature_flags &
1337                VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
1338             goto unsupported;
1339          }
1340       }
1341    }
1342 
1343    *pImageFormatProperties = (VkImageFormatProperties){
1344       .maxExtent = maxExtent,
1345       .maxMipLevels = maxMipLevels,
1346       .maxArrayLayers = maxArraySize,
1347       .sampleCounts = sampleCounts,
1348 
1349       /* We need to limit images to 32-bit range, because the maximum
1350        * slice-stride is 32-bit wide, meaning that if we allocate an image
1351        * with the maximum width and height, we end up overflowing it.
1352        *
1353        * We get around this by simply limiting the maximum resource size.
1354        */
1355       .maxResourceSize = UINT32_MAX,
1356    };
1357 
1358    if (p_feature_flags)
1359       *p_feature_flags = format_feature_flags;
1360 
1361    return VK_SUCCESS;
1362 unsupported:
1363    *pImageFormatProperties = (VkImageFormatProperties){
1364       .maxExtent = {0, 0, 0},
1365       .maxMipLevels = 0,
1366       .maxArrayLayers = 0,
1367       .sampleCounts = 0,
1368       .maxResourceSize = 0,
1369    };
1370 
1371    return VK_ERROR_FORMAT_NOT_SUPPORTED;
1372 }
1373 
1374 static VkResult
panvk_get_external_image_format_properties(const struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkExternalMemoryHandleTypeFlagBits handleType,VkExternalMemoryProperties * external_properties)1375 panvk_get_external_image_format_properties(
1376    const struct panvk_physical_device *physical_device,
1377    const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
1378    VkExternalMemoryHandleTypeFlagBits handleType,
1379    VkExternalMemoryProperties *external_properties)
1380 {
1381    const VkExternalMemoryHandleTypeFlags supported_handle_types =
1382       VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
1383       VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1384 
1385    if (!(handleType & supported_handle_types)) {
1386       return panvk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
1387                           "VkExternalMemoryTypeFlagBits(0x%x) unsupported",
1388                           handleType);
1389    }
1390 
1391    /* pan_image_layout_init requires 2D for explicit layout */
1392    if (pImageFormatInfo->type != VK_IMAGE_TYPE_2D) {
1393       return panvk_errorf(
1394          physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
1395          "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)",
1396          handleType, pImageFormatInfo->type);
1397    }
1398 
1399    /* There is no restriction on opaque fds.  But for dma-bufs, we want to
1400     * make sure vkGetImageSubresourceLayout can be used to query the image
1401     * layout of an exported dma-buf.  We also want to make sure
1402     * VkImageDrmFormatModifierExplicitCreateInfoEXT can be used to specify the
1403     * image layout of an imported dma-buf.  These add restrictions on the
1404     * image tilings.
1405     */
1406    VkExternalMemoryFeatureFlags features = 0;
1407    if (handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
1408        pImageFormatInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1409       features |= VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
1410                   VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
1411    } else if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR) {
1412       features |= VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
1413    }
1414 
1415    if (!features) {
1416       return panvk_errorf(
1417          physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
1418          "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageTiling(%d)",
1419          handleType, pImageFormatInfo->tiling);
1420    }
1421 
1422    *external_properties = (VkExternalMemoryProperties){
1423       .externalMemoryFeatures = features,
1424       .exportFromImportedHandleTypes = supported_handle_types,
1425       .compatibleHandleTypes = supported_handle_types,
1426    };
1427 
1428    return VK_SUCCESS;
1429 }
1430 
1431 VKAPI_ATTR VkResult VKAPI_CALL
panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * base_info,VkImageFormatProperties2 * base_props)1432 panvk_GetPhysicalDeviceImageFormatProperties2(
1433    VkPhysicalDevice physicalDevice,
1434    const VkPhysicalDeviceImageFormatInfo2 *base_info,
1435    VkImageFormatProperties2 *base_props)
1436 {
1437    VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
1438    const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
1439    const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL;
1440    VkExternalImageFormatProperties *external_props = NULL;
1441    VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL;
1442    VkFormatFeatureFlags format_feature_flags;
1443    VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL;
1444    VkResult result;
1445 
1446    result = get_image_format_properties(physical_device, base_info,
1447                                         &base_props->imageFormatProperties,
1448                                         &format_feature_flags);
1449    if (result != VK_SUCCESS)
1450       return result;
1451 
1452    /* Extract input structs */
1453    vk_foreach_struct_const(s, base_info->pNext) {
1454       switch (s->sType) {
1455       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
1456          external_info = (const void *)s;
1457          break;
1458       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT:
1459          image_view_info = (const void *)s;
1460          break;
1461       default:
1462          break;
1463       }
1464    }
1465 
1466    /* Extract output structs */
1467    vk_foreach_struct(s, base_props->pNext) {
1468       switch (s->sType) {
1469       case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
1470          external_props = (void *)s;
1471          break;
1472       case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT:
1473          cubic_props = (void *)s;
1474          break;
1475       case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES:
1476          ycbcr_props = (void *)s;
1477          break;
1478       default:
1479          break;
1480       }
1481    }
1482 
1483    /* From the Vulkan 1.0.42 spec:
1484     *
1485     *    If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will
1486     *    behave as if VkPhysicalDeviceExternalImageFormatInfo was not
1487     *    present and VkExternalImageFormatProperties will be ignored.
1488     */
1489    if (external_info && external_info->handleType != 0) {
1490       VkExternalImageFormatProperties fallback_external_props;
1491 
1492       if (!external_props) {
1493          memset(&fallback_external_props, 0, sizeof(fallback_external_props));
1494          external_props = &fallback_external_props;
1495       }
1496 
1497       result = panvk_get_external_image_format_properties(
1498          physical_device, base_info, external_info->handleType,
1499          &external_props->externalMemoryProperties);
1500       if (result != VK_SUCCESS)
1501          goto fail;
1502 
1503       /* pan_image_layout_init requirements for explicit layout */
1504       base_props->imageFormatProperties.maxMipLevels = 1;
1505       base_props->imageFormatProperties.maxArrayLayers = 1;
1506       base_props->imageFormatProperties.sampleCounts = 1;
1507    }
1508 
1509    if (cubic_props) {
1510       /* note: blob only allows cubic filtering for 2D and 2D array views
1511        * its likely we can enable it for 1D and CUBE, needs testing however
1512        */
1513       if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D ||
1514            image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) &&
1515           (format_feature_flags &
1516            VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) {
1517          cubic_props->filterCubic = true;
1518          cubic_props->filterCubicMinmax = true;
1519       } else {
1520          cubic_props->filterCubic = false;
1521          cubic_props->filterCubicMinmax = false;
1522       }
1523    }
1524 
1525    if (ycbcr_props)
1526       ycbcr_props->combinedImageSamplerDescriptorCount = 1;
1527 
1528    return VK_SUCCESS;
1529 
1530 fail:
1531    if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) {
1532       /* From the Vulkan 1.0.42 spec:
1533        *
1534        *    If the combination of parameters to
1535        *    vkGetPhysicalDeviceImageFormatProperties2 is not supported by
1536        *    the implementation for use in vkCreateImage, then all members of
1537        *    imageFormatProperties will be filled with zero.
1538        */
1539       base_props->imageFormatProperties = (VkImageFormatProperties){};
1540    }
1541 
1542    return result;
1543 }
1544 
1545 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkSampleCountFlagBits samples,VkImageUsageFlags usage,VkImageTiling tiling,uint32_t * pNumProperties,VkSparseImageFormatProperties * pProperties)1546 panvk_GetPhysicalDeviceSparseImageFormatProperties(
1547    VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
1548    VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling,
1549    uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties)
1550 {
1551    /* Sparse images are not yet supported. */
1552    *pNumProperties = 0;
1553 }
1554 
1555 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)1556 panvk_GetPhysicalDeviceSparseImageFormatProperties2(
1557    VkPhysicalDevice physicalDevice,
1558    const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
1559    uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
1560 {
1561    /* Sparse images are not yet supported. */
1562    *pPropertyCount = 0;
1563 }
1564 
1565 VKAPI_ATTR void VKAPI_CALL
panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo,VkExternalBufferProperties * pExternalBufferProperties)1566 panvk_GetPhysicalDeviceExternalBufferProperties(
1567    VkPhysicalDevice physicalDevice,
1568    const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
1569    VkExternalBufferProperties *pExternalBufferProperties)
1570 {
1571    const VkExternalMemoryHandleTypeFlags supported_handle_types =
1572       VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
1573       VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1574 
1575    /* From the Vulkan 1.3.298 spec:
1576     *
1577     *    compatibleHandleTypes must include at least handleType.
1578     */
1579    VkExternalMemoryHandleTypeFlags handle_types =
1580       pExternalBufferInfo->handleType;
1581    VkExternalMemoryFeatureFlags features = 0;
1582    if (pExternalBufferInfo->handleType & supported_handle_types) {
1583       handle_types |= supported_handle_types;
1584       features |= VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
1585                   VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
1586    }
1587 
1588    pExternalBufferProperties->externalMemoryProperties =
1589       (VkExternalMemoryProperties){
1590          .externalMemoryFeatures = features,
1591          .exportFromImportedHandleTypes = handle_types,
1592          .compatibleHandleTypes = handle_types,
1593       };
1594 }
1595