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