• 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  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  */
28 
29 #include "panvk_private.h"
30 
31 #include "decode.h"
32 
33 #include "pan_encoder.h"
34 #include "pan_util.h"
35 #include "pan_props.h"
36 #include "pan_samples.h"
37 
38 #include "vk_cmd_enqueue_entrypoints.h"
39 #include "vk_common_entrypoints.h"
40 
41 #include <fcntl.h>
42 #include <libsync.h>
43 #include <stdbool.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <xf86drm.h>
47 #include <sys/mman.h>
48 #include <sys/sysinfo.h>
49 
50 #include "drm-uapi/panfrost_drm.h"
51 
52 #include "util/disk_cache.h"
53 #include "util/strtod.h"
54 #include "util/u_debug.h"
55 #include "vk_drm_syncobj.h"
56 #include "vk_format.h"
57 #include "vk_util.h"
58 
59 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
60 #include "wayland-drm-client-protocol.h"
61 #include <wayland-client.h>
62 #endif
63 
64 #include "panvk_cs.h"
65 
66 VkResult
_panvk_device_set_lost(struct panvk_device * device,const char * file,int line,const char * msg,...)67 _panvk_device_set_lost(struct panvk_device *device, const char *file, int line,
68                        const char *msg, ...)
69 {
70    /* Set the flag indicating that waits should return in finite time even
71     * after device loss.
72     */
73    p_atomic_inc(&device->_lost);
74 
75    /* TODO: Report the log message through VkDebugReportCallbackEXT instead */
76    fprintf(stderr, "%s:%d: ", file, line);
77    va_list ap;
78    va_start(ap, msg);
79    vfprintf(stderr, msg, ap);
80    va_end(ap);
81 
82    if (debug_get_bool_option("PANVK_ABORT_ON_DEVICE_LOSS", false))
83       abort();
84 
85    return VK_ERROR_DEVICE_LOST;
86 }
87 
88 static int
panvk_device_get_cache_uuid(uint16_t family,void * uuid)89 panvk_device_get_cache_uuid(uint16_t family, void *uuid)
90 {
91    uint32_t mesa_timestamp;
92    uint16_t f = family;
93 
94    if (!disk_cache_get_function_timestamp(panvk_device_get_cache_uuid,
95                                           &mesa_timestamp))
96       return -1;
97 
98    memset(uuid, 0, VK_UUID_SIZE);
99    memcpy(uuid, &mesa_timestamp, 4);
100    memcpy((char *)uuid + 4, &f, 2);
101    snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "pan");
102    return 0;
103 }
104 
105 static void
panvk_get_driver_uuid(void * uuid)106 panvk_get_driver_uuid(void *uuid)
107 {
108    memset(uuid, 0, VK_UUID_SIZE);
109    snprintf(uuid, VK_UUID_SIZE, "panfrost");
110 }
111 
112 static void
panvk_get_device_uuid(void * uuid)113 panvk_get_device_uuid(void *uuid)
114 {
115    memset(uuid, 0, VK_UUID_SIZE);
116 }
117 
118 static const struct debug_control panvk_debug_options[] = {
119    {"startup", PANVK_DEBUG_STARTUP},
120    {"nir", PANVK_DEBUG_NIR},
121    {"trace", PANVK_DEBUG_TRACE},
122    {"sync", PANVK_DEBUG_SYNC},
123    {"afbc", PANVK_DEBUG_AFBC},
124    {"linear", PANVK_DEBUG_LINEAR},
125    {"dump", PANVK_DEBUG_DUMP},
126    {"no_known_warn", PANVK_DEBUG_NO_KNOWN_WARN},
127    {NULL, 0}};
128 
129 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
130 #define PANVK_USE_WSI_PLATFORM
131 #endif
132 
133 #define PANVK_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
134 
135 VkResult
panvk_EnumerateInstanceVersion(uint32_t * pApiVersion)136 panvk_EnumerateInstanceVersion(uint32_t *pApiVersion)
137 {
138    *pApiVersion = PANVK_API_VERSION;
139    return VK_SUCCESS;
140 }
141 
142 static const struct vk_instance_extension_table panvk_instance_extensions = {
143    .KHR_get_physical_device_properties2 = true,
144    .EXT_debug_report = true,
145    .EXT_debug_utils = true,
146 
147 #ifdef PANVK_USE_WSI_PLATFORM
148    .KHR_surface = true,
149 #endif
150 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
151    .KHR_wayland_surface = true,
152 #endif
153 #ifndef VK_USE_PLATFORM_WIN32_KHR
154    .EXT_headless_surface = true,
155 #endif
156 };
157 
158 static void
panvk_get_device_extensions(const struct panvk_physical_device * device,struct vk_device_extension_table * ext)159 panvk_get_device_extensions(const struct panvk_physical_device *device,
160                             struct vk_device_extension_table *ext)
161 {
162    *ext = (struct vk_device_extension_table){
163       .KHR_copy_commands2 = true,
164       .KHR_shader_expect_assume = true,
165       .KHR_storage_buffer_storage_class = true,
166       .KHR_descriptor_update_template = true,
167 #ifdef PANVK_USE_WSI_PLATFORM
168       .KHR_swapchain = true,
169 #endif
170       .KHR_synchronization2 = true,
171       .KHR_variable_pointers = true,
172       .EXT_custom_border_color = true,
173       .EXT_index_type_uint8 = true,
174       .EXT_vertex_attribute_divisor = true,
175    };
176 }
177 
178 static void
panvk_get_features(const struct panvk_physical_device * device,struct vk_features * features)179 panvk_get_features(const struct panvk_physical_device *device,
180                    struct vk_features *features)
181 {
182    *features = (struct vk_features){
183       /* Vulkan 1.0 */
184       .robustBufferAccess = true,
185       .fullDrawIndexUint32 = true,
186       .independentBlend = true,
187       .logicOp = true,
188       .wideLines = true,
189       .largePoints = true,
190       .textureCompressionETC2 = true,
191       .textureCompressionASTC_LDR = true,
192       .shaderUniformBufferArrayDynamicIndexing = true,
193       .shaderSampledImageArrayDynamicIndexing = true,
194       .shaderStorageBufferArrayDynamicIndexing = true,
195       .shaderStorageImageArrayDynamicIndexing = true,
196 
197       /* Vulkan 1.1 */
198       .storageBuffer16BitAccess = false,
199       .uniformAndStorageBuffer16BitAccess = false,
200       .storagePushConstant16 = false,
201       .storageInputOutput16 = false,
202       .multiview = false,
203       .multiviewGeometryShader = false,
204       .multiviewTessellationShader = false,
205       .variablePointersStorageBuffer = true,
206       .variablePointers = true,
207       .protectedMemory = false,
208       .samplerYcbcrConversion = false,
209       .shaderDrawParameters = false,
210 
211       /* Vulkan 1.2 */
212       .samplerMirrorClampToEdge = false,
213       .drawIndirectCount = false,
214       .storageBuffer8BitAccess = false,
215       .uniformAndStorageBuffer8BitAccess = false,
216       .storagePushConstant8 = false,
217       .shaderBufferInt64Atomics = false,
218       .shaderSharedInt64Atomics = false,
219       .shaderFloat16 = false,
220       .shaderInt8 = false,
221 
222       .descriptorIndexing = false,
223       .shaderInputAttachmentArrayDynamicIndexing = false,
224       .shaderUniformTexelBufferArrayDynamicIndexing = false,
225       .shaderStorageTexelBufferArrayDynamicIndexing = false,
226       .shaderUniformBufferArrayNonUniformIndexing = false,
227       .shaderSampledImageArrayNonUniformIndexing = false,
228       .shaderStorageBufferArrayNonUniformIndexing = false,
229       .shaderStorageImageArrayNonUniformIndexing = false,
230       .shaderInputAttachmentArrayNonUniformIndexing = false,
231       .shaderUniformTexelBufferArrayNonUniformIndexing = false,
232       .shaderStorageTexelBufferArrayNonUniformIndexing = false,
233       .descriptorBindingUniformBufferUpdateAfterBind = false,
234       .descriptorBindingSampledImageUpdateAfterBind = false,
235       .descriptorBindingStorageImageUpdateAfterBind = false,
236       .descriptorBindingStorageBufferUpdateAfterBind = false,
237       .descriptorBindingUniformTexelBufferUpdateAfterBind = false,
238       .descriptorBindingStorageTexelBufferUpdateAfterBind = false,
239       .descriptorBindingUpdateUnusedWhilePending = false,
240       .descriptorBindingPartiallyBound = false,
241       .descriptorBindingVariableDescriptorCount = false,
242       .runtimeDescriptorArray = false,
243 
244       .samplerFilterMinmax = false,
245       .scalarBlockLayout = false,
246       .imagelessFramebuffer = false,
247       .uniformBufferStandardLayout = false,
248       .shaderSubgroupExtendedTypes = false,
249       .separateDepthStencilLayouts = false,
250       .hostQueryReset = false,
251       .timelineSemaphore = false,
252       .bufferDeviceAddress = true,
253       .bufferDeviceAddressCaptureReplay = false,
254       .bufferDeviceAddressMultiDevice = false,
255       .vulkanMemoryModel = false,
256       .vulkanMemoryModelDeviceScope = false,
257       .vulkanMemoryModelAvailabilityVisibilityChains = false,
258       .shaderOutputViewportIndex = false,
259       .shaderOutputLayer = false,
260       .subgroupBroadcastDynamicId = false,
261 
262       /* Vulkan 1.3 */
263       .robustImageAccess = false,
264       .inlineUniformBlock = false,
265       .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
266       .pipelineCreationCacheControl = false,
267       .privateData = true,
268       .shaderDemoteToHelperInvocation = false,
269       .shaderTerminateInvocation = false,
270       .subgroupSizeControl = false,
271       .computeFullSubgroups = false,
272       .synchronization2 = true,
273       .textureCompressionASTC_HDR = false,
274       .shaderZeroInitializeWorkgroupMemory = false,
275       .dynamicRendering = false,
276       .shaderIntegerDotProduct = false,
277       .maintenance4 = false,
278 
279       /* VK_EXT_index_type_uint8 */
280       .indexTypeUint8 = true,
281 
282       /* VK_EXT_vertex_attribute_divisor */
283       .vertexAttributeInstanceRateDivisor = true,
284       .vertexAttributeInstanceRateZeroDivisor = true,
285 
286       /* VK_EXT_depth_clip_enable */
287       .depthClipEnable = true,
288 
289       /* VK_EXT_4444_formats */
290       .formatA4R4G4B4 = true,
291       .formatA4B4G4R4 = true,
292 
293       /* VK_EXT_custom_border_color */
294       .customBorderColors = true,
295       .customBorderColorWithoutFormat = true,
296 
297       /* VK_KHR_shader_expect_assume */
298       .shaderExpectAssume = true,
299    };
300 }
301 
302 VkResult panvk_physical_device_try_create(struct vk_instance *vk_instance,
303                                           struct _drmDevice *drm_device,
304                                           struct vk_physical_device **out);
305 
306 static void
panvk_physical_device_finish(struct panvk_physical_device * device)307 panvk_physical_device_finish(struct panvk_physical_device *device)
308 {
309    panvk_wsi_finish(device);
310 
311    pan_kmod_dev_destroy(device->kmod.dev);
312    if (device->master_fd != -1)
313       close(device->master_fd);
314 
315    vk_physical_device_finish(&device->vk);
316 }
317 
318 static void
panvk_destroy_physical_device(struct vk_physical_device * device)319 panvk_destroy_physical_device(struct vk_physical_device *device)
320 {
321    panvk_physical_device_finish((struct panvk_physical_device *)device);
322    vk_free(&device->instance->alloc, device);
323 }
324 
325 static void *
panvk_kmod_zalloc(const struct pan_kmod_allocator * allocator,size_t size,bool transient)326 panvk_kmod_zalloc(const struct pan_kmod_allocator *allocator,
327                   size_t size, bool transient)
328 {
329    const VkAllocationCallbacks *vkalloc = allocator->priv;
330 
331    return vk_zalloc(vkalloc, size, 8,
332                     transient ? VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
333                               : VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
334 }
335 
336 static void
panvk_kmod_free(const struct pan_kmod_allocator * allocator,void * data)337 panvk_kmod_free(const struct pan_kmod_allocator *allocator, void *data)
338 {
339    const VkAllocationCallbacks *vkalloc = allocator->priv;
340 
341    return vk_free(vkalloc, data);
342 }
343 
344 VkResult
panvk_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)345 panvk_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
346                      const VkAllocationCallbacks *pAllocator,
347                      VkInstance *pInstance)
348 {
349    struct panvk_instance *instance;
350    VkResult result;
351 
352    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
353 
354    pAllocator = pAllocator ?: vk_default_allocator();
355    instance = vk_zalloc(pAllocator, sizeof(*instance), 8,
356                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
357    if (!instance)
358       return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
359 
360    struct vk_instance_dispatch_table dispatch_table;
361 
362    vk_instance_dispatch_table_from_entrypoints(
363       &dispatch_table, &panvk_instance_entrypoints, true);
364    vk_instance_dispatch_table_from_entrypoints(
365       &dispatch_table, &wsi_instance_entrypoints, false);
366    result = vk_instance_init(&instance->vk, &panvk_instance_extensions,
367                              &dispatch_table, pCreateInfo, pAllocator);
368    if (result != VK_SUCCESS) {
369       vk_free(pAllocator, instance);
370       return vk_error(NULL, result);
371    }
372 
373    instance->kmod.allocator = (struct pan_kmod_allocator){
374       .zalloc = panvk_kmod_zalloc,
375       .free = panvk_kmod_free,
376       .priv = &instance->vk.alloc,
377    };
378 
379    instance->vk.physical_devices.try_create_for_drm =
380       panvk_physical_device_try_create;
381    instance->vk.physical_devices.destroy = panvk_destroy_physical_device;
382 
383    instance->debug_flags =
384       parse_debug_string(getenv("PANVK_DEBUG"), panvk_debug_options);
385 
386    if (instance->debug_flags & PANVK_DEBUG_STARTUP)
387       vk_logi(VK_LOG_NO_OBJS(instance), "Created an instance");
388 
389    VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
390 
391    *pInstance = panvk_instance_to_handle(instance);
392 
393    return VK_SUCCESS;
394 }
395 
396 void
panvk_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)397 panvk_DestroyInstance(VkInstance _instance,
398                       const VkAllocationCallbacks *pAllocator)
399 {
400    VK_FROM_HANDLE(panvk_instance, instance, _instance);
401 
402    if (!instance)
403       return;
404 
405    vk_instance_finish(&instance->vk);
406    vk_free(&instance->vk.alloc, instance);
407 }
408 
409 static VkResult
panvk_physical_device_init(struct panvk_physical_device * device,struct panvk_instance * instance,drmDevicePtr drm_device)410 panvk_physical_device_init(struct panvk_physical_device *device,
411                            struct panvk_instance *instance,
412                            drmDevicePtr drm_device)
413 {
414    const char *path = drm_device->nodes[DRM_NODE_RENDER];
415    VkResult result = VK_SUCCESS;
416    drmVersionPtr version;
417    int fd;
418    int master_fd = -1;
419 
420    if (!getenv("PAN_I_WANT_A_BROKEN_VULKAN_DRIVER")) {
421       return vk_errorf(
422          instance, VK_ERROR_INCOMPATIBLE_DRIVER,
423          "WARNING: panvk is not a conformant vulkan implementation, "
424          "pass PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 if you know what you're doing.");
425    }
426 
427    fd = open(path, O_RDWR | O_CLOEXEC);
428    if (fd < 0) {
429       return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
430                        "failed to open device %s", path);
431    }
432 
433    version = drmGetVersion(fd);
434    if (!version) {
435       close(fd);
436       return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
437                        "failed to query kernel driver version for device %s",
438                        path);
439    }
440 
441    if (strcmp(version->name, "panfrost")) {
442       drmFreeVersion(version);
443       close(fd);
444       return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
445                        "device %s does not use the panfrost kernel driver",
446                        path);
447    }
448 
449    drmFreeVersion(version);
450 
451    if (instance->debug_flags & PANVK_DEBUG_STARTUP)
452       vk_logi(VK_LOG_NO_OBJS(instance), "Found compatible device '%s'.", path);
453 
454    struct vk_device_extension_table supported_extensions;
455    panvk_get_device_extensions(device, &supported_extensions);
456 
457    struct vk_features supported_features;
458    panvk_get_features(device, &supported_features);
459 
460    struct vk_physical_device_dispatch_table dispatch_table;
461    vk_physical_device_dispatch_table_from_entrypoints(
462       &dispatch_table, &panvk_physical_device_entrypoints, true);
463    vk_physical_device_dispatch_table_from_entrypoints(
464       &dispatch_table, &wsi_physical_device_entrypoints, false);
465 
466    result =
467       vk_physical_device_init(&device->vk, &instance->vk, &supported_extensions,
468                               &supported_features, NULL, &dispatch_table);
469 
470    if (result != VK_SUCCESS) {
471       vk_error(instance, result);
472       goto fail;
473    }
474 
475    device->instance = instance;
476 
477    if (instance->vk.enabled_extensions.KHR_display) {
478       master_fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
479       if (master_fd >= 0) {
480          /* TODO: free master_fd is accel is not working? */
481       }
482    }
483 
484    device->master_fd = master_fd;
485 
486    device->kmod.dev = pan_kmod_dev_create(fd, PAN_KMOD_DEV_FLAG_OWNS_FD,
487                                           &instance->kmod.allocator);
488    pan_kmod_dev_query_props(device->kmod.dev, &device->kmod.props);
489 
490    unsigned arch = pan_arch(device->kmod.props.gpu_prod_id);
491 
492    device->model = panfrost_get_model(device->kmod.props.gpu_prod_id);
493    device->formats.all = panfrost_format_table(arch);
494    device->formats.blendable = panfrost_blendable_format_table(arch);
495 
496    if (arch <= 5 || arch >= 8) {
497       result = vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
498                          "%s not supported", device->model->name);
499       goto fail;
500    }
501 
502    memset(device->name, 0, sizeof(device->name));
503    sprintf(device->name, "%s", device->model->name);
504 
505    if (panvk_device_get_cache_uuid(device->kmod.props.gpu_prod_id,
506                                    device->cache_uuid)) {
507       result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
508                          "cannot generate UUID");
509       goto fail_close_device;
510    }
511 
512    vk_warn_non_conformant_implementation("panvk");
513 
514    panvk_get_driver_uuid(&device->device_uuid);
515    panvk_get_device_uuid(&device->device_uuid);
516 
517    device->drm_syncobj_type =
518       vk_drm_syncobj_get_type(device->kmod.dev->fd);
519    /* We don't support timelines in the uAPI yet and we don't want it getting
520     * suddenly turned on by vk_drm_syncobj_get_type() without us adding panvk
521     * code for it first.
522     */
523    device->drm_syncobj_type.features &= ~VK_SYNC_FEATURE_TIMELINE;
524 
525    device->sync_types[0] = &device->drm_syncobj_type;
526    device->sync_types[1] = NULL;
527    device->vk.supported_sync_types = device->sync_types;
528 
529    result = panvk_wsi_init(device);
530    if (result != VK_SUCCESS) {
531       vk_error(instance, result);
532       goto fail_close_device;
533    }
534 
535    return VK_SUCCESS;
536 
537 fail_close_device:
538    pan_kmod_dev_destroy(device->kmod.dev);
539 fail:
540    if (fd != -1)
541       close(fd);
542    if (master_fd != -1)
543       close(master_fd);
544    return result;
545 }
546 
547 VkResult
panvk_physical_device_try_create(struct vk_instance * vk_instance,struct _drmDevice * drm_device,struct vk_physical_device ** out)548 panvk_physical_device_try_create(struct vk_instance *vk_instance,
549                                  struct _drmDevice *drm_device,
550                                  struct vk_physical_device **out)
551 {
552    struct panvk_instance *instance =
553       container_of(vk_instance, struct panvk_instance, vk);
554 
555    if (!(drm_device->available_nodes & (1 << DRM_NODE_RENDER)) ||
556        drm_device->bustype != DRM_BUS_PLATFORM)
557       return VK_ERROR_INCOMPATIBLE_DRIVER;
558 
559    struct panvk_physical_device *device =
560       vk_zalloc(&instance->vk.alloc, sizeof(*device), 8,
561                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
562    if (!device)
563       return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
564 
565    VkResult result = panvk_physical_device_init(device, instance, drm_device);
566    if (result != VK_SUCCESS) {
567       vk_free(&instance->vk.alloc, device);
568       return result;
569    }
570 
571    *out = &device->vk;
572    return VK_SUCCESS;
573 }
574 
575 void
panvk_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties2 * pProperties)576 panvk_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
577                                    VkPhysicalDeviceProperties2 *pProperties)
578 {
579    VK_FROM_HANDLE(panvk_physical_device, pdevice, physicalDevice);
580 
581    VkSampleCountFlags sample_counts =
582       VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
583 
584    /* make sure that the entire descriptor set is addressable with a signed
585     * 32-bit int. So the sum of all limits scaled by descriptor size has to
586     * be at most 2 GiB. the combined image & samples object count as one of
587     * both. This limit is for the pipeline layout, not for the set layout, but
588     * there is no set limit, so we just set a pipeline limit. I don't think
589     * any app is going to hit this soon. */
590    size_t max_descriptor_set_size =
591       ((1ull << 31) - 16 * MAX_DYNAMIC_BUFFERS) /
592       (32 /* uniform buffer, 32 due to potential space wasted on alignment */ +
593        32 /* storage buffer, 32 due to potential space wasted on alignment */ +
594        32 /* sampler, largest when combined with image */ +
595        64 /* sampled image */ + 64 /* storage image */);
596 
597    const VkPhysicalDeviceLimits limits = {
598       .maxImageDimension1D = (1 << 14),
599       .maxImageDimension2D = (1 << 14),
600       .maxImageDimension3D = (1 << 11),
601       .maxImageDimensionCube = (1 << 14),
602       .maxImageArrayLayers = (1 << 11),
603       .maxTexelBufferElements = 128 * 1024 * 1024,
604       .maxUniformBufferRange = UINT32_MAX,
605       .maxStorageBufferRange = UINT32_MAX,
606       .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,
607       .maxMemoryAllocationCount = UINT32_MAX,
608       .maxSamplerAllocationCount = 64 * 1024,
609       .bufferImageGranularity = 64,          /* A cache line */
610       .sparseAddressSpaceSize = 0xffffffffu, /* buffer max size */
611       .maxBoundDescriptorSets = MAX_SETS,
612       .maxPerStageDescriptorSamplers = max_descriptor_set_size,
613       .maxPerStageDescriptorUniformBuffers = max_descriptor_set_size,
614       .maxPerStageDescriptorStorageBuffers = max_descriptor_set_size,
615       .maxPerStageDescriptorSampledImages = max_descriptor_set_size,
616       .maxPerStageDescriptorStorageImages = max_descriptor_set_size,
617       .maxPerStageDescriptorInputAttachments = max_descriptor_set_size,
618       .maxPerStageResources = max_descriptor_set_size,
619       .maxDescriptorSetSamplers = max_descriptor_set_size,
620       .maxDescriptorSetUniformBuffers = max_descriptor_set_size,
621       .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,
622       .maxDescriptorSetStorageBuffers = max_descriptor_set_size,
623       .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
624       .maxDescriptorSetSampledImages = max_descriptor_set_size,
625       .maxDescriptorSetStorageImages = max_descriptor_set_size,
626       .maxDescriptorSetInputAttachments = max_descriptor_set_size,
627       .maxVertexInputAttributes = 32,
628       .maxVertexInputBindings = 32,
629       .maxVertexInputAttributeOffset = 2047,
630       .maxVertexInputBindingStride = 2048,
631       .maxVertexOutputComponents = 128,
632       .maxTessellationGenerationLevel = 64,
633       .maxTessellationPatchSize = 32,
634       .maxTessellationControlPerVertexInputComponents = 128,
635       .maxTessellationControlPerVertexOutputComponents = 128,
636       .maxTessellationControlPerPatchOutputComponents = 120,
637       .maxTessellationControlTotalOutputComponents = 4096,
638       .maxTessellationEvaluationInputComponents = 128,
639       .maxTessellationEvaluationOutputComponents = 128,
640       .maxGeometryShaderInvocations = 127,
641       .maxGeometryInputComponents = 64,
642       .maxGeometryOutputComponents = 128,
643       .maxGeometryOutputVertices = 256,
644       .maxGeometryTotalOutputComponents = 1024,
645       .maxFragmentInputComponents = 128,
646       .maxFragmentOutputAttachments = 8,
647       .maxFragmentDualSrcAttachments = 1,
648       .maxFragmentCombinedOutputResources =
649          MAX_RTS + max_descriptor_set_size * 2,
650       .maxComputeSharedMemorySize = 32768,
651       .maxComputeWorkGroupCount = {65535, 65535, 65535},
652       .maxComputeWorkGroupInvocations = 2048,
653       .maxComputeWorkGroupSize = {2048, 2048, 2048},
654       .subPixelPrecisionBits = 4 /* FIXME */,
655       .subTexelPrecisionBits = 4 /* FIXME */,
656       .mipmapPrecisionBits = 4 /* FIXME */,
657       .maxDrawIndexedIndexValue = UINT32_MAX,
658       .maxDrawIndirectCount = UINT32_MAX,
659       .maxSamplerLodBias = 16,
660       .maxSamplerAnisotropy = 16,
661       .maxViewports = MAX_VIEWPORTS,
662       .maxViewportDimensions = {(1 << 14), (1 << 14)},
663       .viewportBoundsRange = {INT16_MIN, INT16_MAX},
664       .viewportSubPixelBits = 8,
665       .minMemoryMapAlignment = 4096, /* A page */
666       .minTexelBufferOffsetAlignment = 64,
667       .minUniformBufferOffsetAlignment = 16,
668       .minStorageBufferOffsetAlignment = 4,
669       .minTexelOffset = -32,
670       .maxTexelOffset = 31,
671       .minTexelGatherOffset = -32,
672       .maxTexelGatherOffset = 31,
673       .minInterpolationOffset = -2,
674       .maxInterpolationOffset = 2,
675       .subPixelInterpolationOffsetBits = 8,
676       .maxFramebufferWidth = (1 << 14),
677       .maxFramebufferHeight = (1 << 14),
678       .maxFramebufferLayers = (1 << 10),
679       .framebufferColorSampleCounts = sample_counts,
680       .framebufferDepthSampleCounts = sample_counts,
681       .framebufferStencilSampleCounts = sample_counts,
682       .framebufferNoAttachmentsSampleCounts = sample_counts,
683       .maxColorAttachments = MAX_RTS,
684       .sampledImageColorSampleCounts = sample_counts,
685       .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT,
686       .sampledImageDepthSampleCounts = sample_counts,
687       .sampledImageStencilSampleCounts = sample_counts,
688       .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
689       .maxSampleMaskWords = 1,
690       .timestampComputeAndGraphics = true,
691       .timestampPeriod = 1,
692       .maxClipDistances = 8,
693       .maxCullDistances = 8,
694       .maxCombinedClipAndCullDistances = 8,
695       .discreteQueuePriorities = 1,
696       .pointSizeRange = {0.125, 4095.9375},
697       .lineWidthRange = {0.0, 7.9921875},
698       .pointSizeGranularity = (1.0 / 16.0),
699       .lineWidthGranularity = (1.0 / 128.0),
700       .strictLines = false, /* FINISHME */
701       .standardSampleLocations = true,
702       .optimalBufferCopyOffsetAlignment = 128,
703       .optimalBufferCopyRowPitchAlignment = 128,
704       .nonCoherentAtomSize = 64,
705    };
706 
707    pProperties->properties = (VkPhysicalDeviceProperties){
708       .apiVersion = PANVK_API_VERSION,
709       .driverVersion = vk_get_driver_version(),
710       .vendorID = 0, /* TODO */
711       .deviceID = 0,
712       .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
713       .limits = limits,
714       .sparseProperties = {0},
715    };
716 
717    strcpy(pProperties->properties.deviceName, pdevice->name);
718    memcpy(pProperties->properties.pipelineCacheUUID, pdevice->cache_uuid,
719           VK_UUID_SIZE);
720 
721    VkPhysicalDeviceVulkan11Properties core_1_1 = {
722       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES,
723       .deviceLUIDValid = false,
724       .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
725       .maxMultiviewViewCount = 0,
726       .maxMultiviewInstanceIndex = 0,
727       .protectedNoFault = false,
728       /* Make sure everything is addressable by a signed 32-bit int, and
729        * our largest descriptors are 96 bytes. */
730       .maxPerSetDescriptors = (1ull << 31) / 96,
731       /* Our buffer size fields allow only this much */
732       .maxMemoryAllocationSize = 0xFFFFFFFFull,
733    };
734    memcpy(core_1_1.driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
735    memcpy(core_1_1.deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
736 
737    const VkPhysicalDeviceVulkan12Properties core_1_2 = {
738       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
739    };
740 
741    const VkPhysicalDeviceVulkan13Properties core_1_3 = {
742       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES,
743    };
744 
745    vk_foreach_struct(ext, pProperties->pNext) {
746       if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1))
747          continue;
748       if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2))
749          continue;
750       if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3))
751          continue;
752 
753       switch (ext->sType) {
754       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
755          VkPhysicalDevicePushDescriptorPropertiesKHR *properties =
756             (VkPhysicalDevicePushDescriptorPropertiesKHR *)ext;
757          properties->maxPushDescriptors = MAX_PUSH_DESCRIPTORS;
758          break;
759       }
760       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
761          VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *properties =
762             (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext;
763          /* We have to restrict this a bit for multiview */
764          properties->maxVertexAttribDivisor = UINT32_MAX / (16 * 2048);
765          break;
766       }
767       default:
768          break;
769       }
770    }
771 }
772 
773 static const VkQueueFamilyProperties panvk_queue_family_properties = {
774    .queueFlags =
775       VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
776    .queueCount = 1,
777    .timestampValidBits = 64,
778    .minImageTransferGranularity = {1, 1, 1},
779 };
780 
781 void
panvk_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)782 panvk_GetPhysicalDeviceQueueFamilyProperties2(
783    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
784    VkQueueFamilyProperties2 *pQueueFamilyProperties)
785 {
786    VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out, pQueueFamilyProperties,
787                           pQueueFamilyPropertyCount);
788 
789    vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p)
790    {
791       p->queueFamilyProperties = panvk_queue_family_properties;
792    }
793 }
794 
795 static uint64_t
panvk_get_system_heap_size()796 panvk_get_system_heap_size()
797 {
798    struct sysinfo info;
799    sysinfo(&info);
800 
801    uint64_t total_ram = (uint64_t)info.totalram * info.mem_unit;
802 
803    /* We don't want to burn too much ram with the GPU.  If the user has 4GiB
804     * or less, we use at most half.  If they have more than 4GiB, we use 3/4.
805     */
806    uint64_t available_ram;
807    if (total_ram <= 4ull * 1024 * 1024 * 1024)
808       available_ram = total_ram / 2;
809    else
810       available_ram = total_ram * 3 / 4;
811 
812    return available_ram;
813 }
814 
815 void
panvk_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)816 panvk_GetPhysicalDeviceMemoryProperties2(
817    VkPhysicalDevice physicalDevice,
818    VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
819 {
820    pMemoryProperties->memoryProperties = (VkPhysicalDeviceMemoryProperties){
821       .memoryHeapCount = 1,
822       .memoryHeaps[0].size = panvk_get_system_heap_size(),
823       .memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
824       .memoryTypeCount = 1,
825       .memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
826                                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
827                                       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
828       .memoryTypes[0].heapIndex = 0,
829    };
830 }
831 
832 static VkResult
panvk_queue_init(struct panvk_device * device,struct panvk_queue * queue,int idx,const VkDeviceQueueCreateInfo * create_info)833 panvk_queue_init(struct panvk_device *device, struct panvk_queue *queue,
834                  int idx, const VkDeviceQueueCreateInfo *create_info)
835 {
836    VkResult result = vk_queue_init(&queue->vk, &device->vk, create_info, idx);
837    if (result != VK_SUCCESS)
838       return result;
839    queue->device = device;
840 
841    struct drm_syncobj_create create = {
842       .flags = DRM_SYNCOBJ_CREATE_SIGNALED,
843    };
844 
845    int ret = drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
846    if (ret) {
847       vk_queue_finish(&queue->vk);
848       return VK_ERROR_OUT_OF_HOST_MEMORY;
849    }
850 
851    unsigned arch = pan_arch(device->physical_device->kmod.props.gpu_prod_id);
852 
853    switch (arch) {
854    case 6:
855       queue->vk.driver_submit = panvk_v6_queue_submit;
856       break;
857    case 7:
858       queue->vk.driver_submit = panvk_v7_queue_submit;
859       break;
860    default:
861       unreachable("Unsupported architecture");
862    }
863 
864    queue->sync = create.handle;
865    return VK_SUCCESS;
866 }
867 
868 static void
panvk_queue_finish(struct panvk_queue * queue)869 panvk_queue_finish(struct panvk_queue *queue)
870 {
871    vk_queue_finish(&queue->vk);
872 }
873 
panvk_priv_bo_create(struct panvk_device * dev,size_t size,uint32_t flags,const struct VkAllocationCallbacks * alloc,VkSystemAllocationScope scope)874 struct panvk_priv_bo *panvk_priv_bo_create(struct panvk_device *dev,
875                                            size_t size, uint32_t flags,
876                                            const struct VkAllocationCallbacks *alloc,
877                                            VkSystemAllocationScope scope)
878 {
879    int ret;
880    struct panvk_priv_bo *priv_bo =
881       vk_zalloc2(&dev->vk.alloc, alloc, sizeof(*priv_bo), 8, scope);
882 
883    if (!priv_bo)
884       return NULL;
885 
886    struct pan_kmod_bo *bo =
887       pan_kmod_bo_alloc(dev->kmod.dev, dev->kmod.vm, size, flags);
888    if (!bo)
889       goto err_free_priv_bo;
890 
891    priv_bo->bo = bo;
892    priv_bo->dev = dev;
893 
894    if (!(flags & PAN_KMOD_BO_FLAG_NO_MMAP)) {
895       priv_bo->addr.host = pan_kmod_bo_mmap(
896          bo, 0, pan_kmod_bo_size(bo), PROT_READ | PROT_WRITE, MAP_SHARED, NULL);
897       if (priv_bo->addr.host == MAP_FAILED)
898          goto err_put_bo;
899    }
900 
901    struct pan_kmod_vm_op op = {
902       .type = PAN_KMOD_VM_OP_TYPE_MAP,
903       .va = {
904          .start = PAN_KMOD_VM_MAP_AUTO_VA,
905          .size = pan_kmod_bo_size(bo),
906       },
907       .map = {
908          .bo = priv_bo->bo,
909          .bo_offset = 0,
910       },
911    };
912 
913    ret = pan_kmod_vm_bind(dev->kmod.vm, PAN_KMOD_VM_OP_MODE_IMMEDIATE, &op, 1);
914    if (ret)
915       goto err_munmap_bo;
916 
917 
918    priv_bo->addr.dev = op.va.start;
919 
920    if (dev->debug.decode_ctx) {
921       pandecode_inject_mmap(dev->debug.decode_ctx, priv_bo->addr.dev,
922                             priv_bo->addr.host, pan_kmod_bo_size(priv_bo->bo),
923                             NULL);
924    }
925 
926    return priv_bo;
927 
928 err_munmap_bo:
929    if (priv_bo->addr.host) {
930       ret = os_munmap(priv_bo->addr.host, pan_kmod_bo_size(bo));
931       assert(!ret);
932    }
933 
934 err_put_bo:
935    pan_kmod_bo_put(bo);
936 
937 err_free_priv_bo:
938    vk_free2(&dev->vk.alloc, alloc, priv_bo);
939    return NULL;
940 }
941 
942 void
panvk_priv_bo_destroy(struct panvk_priv_bo * priv_bo,const VkAllocationCallbacks * alloc)943 panvk_priv_bo_destroy(struct panvk_priv_bo *priv_bo,
944                       const VkAllocationCallbacks *alloc)
945 {
946    if (!priv_bo)
947       return;
948 
949    struct panvk_device *dev = priv_bo->dev;
950 
951    if (dev->debug.decode_ctx) {
952       pandecode_inject_free(dev->debug.decode_ctx, priv_bo->addr.dev,
953                             pan_kmod_bo_size(priv_bo->bo));
954    }
955 
956    struct pan_kmod_vm_op op = {
957       .type = PAN_KMOD_VM_OP_TYPE_UNMAP,
958       .va = {
959          .start = priv_bo->addr.dev,
960          .size = pan_kmod_bo_size(priv_bo->bo),
961       },
962    };
963    ASSERTED int ret =
964       pan_kmod_vm_bind(dev->kmod.vm, PAN_KMOD_VM_OP_MODE_IMMEDIATE, &op, 1);
965    assert(!ret);
966 
967    if (priv_bo->addr.host) {
968       ret = os_munmap(priv_bo->addr.host, pan_kmod_bo_size(priv_bo->bo));
969       assert(!ret);
970    }
971 
972    pan_kmod_bo_put(priv_bo->bo);
973    vk_free2(&dev->vk.alloc, alloc, priv_bo);
974 }
975 
976 /* Always reserve the lower 32MB. */
977 #define PANVK_VA_RESERVE_BOTTOM 0x2000000ull
978 
979 VkResult
panvk_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)980 panvk_CreateDevice(VkPhysicalDevice physicalDevice,
981                    const VkDeviceCreateInfo *pCreateInfo,
982                    const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
983 {
984    VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
985    struct panvk_instance *instance = physical_device->instance;
986    VkResult result;
987    struct panvk_device *device;
988 
989    device = vk_zalloc2(&physical_device->instance->vk.alloc, pAllocator,
990                        sizeof(*device), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
991    if (!device)
992       return vk_error(physical_device, VK_ERROR_OUT_OF_HOST_MEMORY);
993 
994    const struct vk_device_entrypoint_table *dev_entrypoints;
995    const struct vk_command_buffer_ops *cmd_buffer_ops;
996    struct vk_device_dispatch_table dispatch_table;
997    unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id);
998 
999    switch (arch) {
1000    case 6:
1001       dev_entrypoints = &panvk_v6_device_entrypoints;
1002       cmd_buffer_ops = &panvk_v6_cmd_buffer_ops;
1003       break;
1004    case 7:
1005       dev_entrypoints = &panvk_v7_device_entrypoints;
1006       cmd_buffer_ops = &panvk_v7_cmd_buffer_ops;
1007       break;
1008    default:
1009       unreachable("Unsupported architecture");
1010    }
1011 
1012    /* For secondary command buffer support, overwrite any command entrypoints
1013     * in the main device-level dispatch table with
1014     * vk_cmd_enqueue_unless_primary_Cmd*.
1015     */
1016    vk_device_dispatch_table_from_entrypoints(
1017       &dispatch_table, &vk_cmd_enqueue_unless_primary_device_entrypoints, true);
1018 
1019    vk_device_dispatch_table_from_entrypoints(&dispatch_table, dev_entrypoints,
1020                                              false);
1021    vk_device_dispatch_table_from_entrypoints(&dispatch_table,
1022                                              &panvk_device_entrypoints, false);
1023    vk_device_dispatch_table_from_entrypoints(&dispatch_table,
1024                                              &wsi_device_entrypoints, false);
1025 
1026    /* Populate our primary cmd_dispatch table. */
1027    vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
1028                                              dev_entrypoints, true);
1029    vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
1030                                              &panvk_device_entrypoints, false);
1031    vk_device_dispatch_table_from_entrypoints(
1032       &device->cmd_dispatch, &vk_common_device_entrypoints, false);
1033 
1034    result = vk_device_init(&device->vk, &physical_device->vk, &dispatch_table,
1035                            pCreateInfo, pAllocator);
1036    if (result != VK_SUCCESS) {
1037       vk_free(&device->vk.alloc, device);
1038       return result;
1039    }
1040 
1041    /* Must be done after vk_device_init() because this function memset(0) the
1042     * whole struct.
1043     */
1044    device->vk.command_dispatch_table = &device->cmd_dispatch;
1045    device->vk.command_buffer_ops = cmd_buffer_ops;
1046 
1047    device->instance = physical_device->instance;
1048    device->physical_device = physical_device;
1049 
1050    device->kmod.allocator = (struct pan_kmod_allocator){
1051       .zalloc = panvk_kmod_zalloc,
1052       .free = panvk_kmod_free,
1053       .priv = &device->vk.alloc,
1054    };
1055    device->kmod.dev =
1056       pan_kmod_dev_create(dup(physical_device->kmod.dev->fd),
1057                           PAN_KMOD_DEV_FLAG_OWNS_FD, &device->kmod.allocator);
1058 
1059    if (instance->debug_flags & PANVK_DEBUG_TRACE)
1060       device->debug.decode_ctx = pandecode_create_context(false);
1061 
1062    /* 32bit address space, with the lower 32MB reserved. We clamp
1063     * things so it matches kmod VA range limitations.
1064     */
1065    uint64_t user_va_start = panfrost_clamp_to_usable_va_range(
1066       device->kmod.dev, PANVK_VA_RESERVE_BOTTOM);
1067    uint64_t user_va_end =
1068       panfrost_clamp_to_usable_va_range(device->kmod.dev, 1ull << 32);
1069 
1070    device->kmod.vm =
1071       pan_kmod_vm_create(device->kmod.dev, PAN_KMOD_VM_FLAG_AUTO_VA,
1072                          user_va_start, user_va_end - user_va_start);
1073 
1074    device->tiler_heap = panvk_priv_bo_create(
1075       device, 128 * 1024 * 1024,
1076       PAN_KMOD_BO_FLAG_NO_MMAP | PAN_KMOD_BO_FLAG_ALLOC_ON_FAULT,
1077       &device->vk.alloc, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1078 
1079    device->sample_positions = panvk_priv_bo_create(
1080       device, panfrost_sample_positions_buffer_size(), 0,
1081       &device->vk.alloc, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1082    panfrost_upload_sample_positions(device->sample_positions->addr.host);
1083 
1084    vk_device_set_drm_fd(&device->vk, device->kmod.dev->fd);
1085 
1086    panvk_arch_dispatch(arch, meta_init, device);
1087 
1088    for (unsigned i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
1089       const VkDeviceQueueCreateInfo *queue_create =
1090          &pCreateInfo->pQueueCreateInfos[i];
1091       uint32_t qfi = queue_create->queueFamilyIndex;
1092       device->queues[qfi] =
1093          vk_alloc(&device->vk.alloc,
1094                   queue_create->queueCount * sizeof(struct panvk_queue), 8,
1095                   VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1096       if (!device->queues[qfi]) {
1097          result = VK_ERROR_OUT_OF_HOST_MEMORY;
1098          goto fail;
1099       }
1100 
1101       memset(device->queues[qfi], 0,
1102              queue_create->queueCount * sizeof(struct panvk_queue));
1103 
1104       device->queue_count[qfi] = queue_create->queueCount;
1105 
1106       for (unsigned q = 0; q < queue_create->queueCount; q++) {
1107          result =
1108             panvk_queue_init(device, &device->queues[qfi][q], q, queue_create);
1109          if (result != VK_SUCCESS)
1110             goto fail;
1111       }
1112    }
1113 
1114    *pDevice = panvk_device_to_handle(device);
1115    return VK_SUCCESS;
1116 
1117 fail:
1118    for (unsigned i = 0; i < PANVK_MAX_QUEUE_FAMILIES; i++) {
1119       for (unsigned q = 0; q < device->queue_count[i]; q++)
1120          panvk_queue_finish(&device->queues[i][q]);
1121       if (device->queue_count[i])
1122          vk_object_free(&device->vk, NULL, device->queues[i]);
1123    }
1124 
1125    panvk_arch_dispatch(pan_arch(physical_device->kmod.props.gpu_prod_id),
1126                        meta_cleanup, device);
1127    panvk_priv_bo_destroy(device->tiler_heap, &device->vk.alloc);
1128    panvk_priv_bo_destroy(device->sample_positions, &device->vk.alloc);
1129    pan_kmod_vm_destroy(device->kmod.vm);
1130    pan_kmod_dev_destroy(device->kmod.dev);
1131 
1132    vk_free(&device->vk.alloc, device);
1133    return result;
1134 }
1135 
1136 void
panvk_DestroyDevice(VkDevice _device,const VkAllocationCallbacks * pAllocator)1137 panvk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
1138 {
1139    VK_FROM_HANDLE(panvk_device, device, _device);
1140    struct panvk_physical_device *physical_device = device->physical_device;
1141 
1142    if (!device)
1143       return;
1144 
1145    if (device->debug.decode_ctx)
1146       pandecode_destroy_context(device->debug.decode_ctx);
1147 
1148    for (unsigned i = 0; i < PANVK_MAX_QUEUE_FAMILIES; i++) {
1149       for (unsigned q = 0; q < device->queue_count[i]; q++)
1150          panvk_queue_finish(&device->queues[i][q]);
1151       if (device->queue_count[i])
1152          vk_object_free(&device->vk, NULL, device->queues[i]);
1153    }
1154 
1155    panvk_arch_dispatch(pan_arch(physical_device->kmod.props.gpu_prod_id),
1156                        meta_cleanup, device);
1157    panvk_priv_bo_destroy(device->tiler_heap, &device->vk.alloc);
1158    panvk_priv_bo_destroy(device->sample_positions, &device->vk.alloc);
1159    pan_kmod_vm_destroy(device->kmod.vm);
1160    pan_kmod_dev_destroy(device->kmod.dev);
1161    vk_free(&device->vk.alloc, device);
1162 }
1163 
1164 VkResult
panvk_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)1165 panvk_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1166                                        VkLayerProperties *pProperties)
1167 {
1168    *pPropertyCount = 0;
1169    return VK_SUCCESS;
1170 }
1171 
1172 VkResult
panvk_QueueWaitIdle(VkQueue _queue)1173 panvk_QueueWaitIdle(VkQueue _queue)
1174 {
1175    VK_FROM_HANDLE(panvk_queue, queue, _queue);
1176 
1177    if (panvk_device_is_lost(queue->device))
1178       return VK_ERROR_DEVICE_LOST;
1179 
1180    struct drm_syncobj_wait wait = {
1181       .handles = (uint64_t)(uintptr_t)(&queue->sync),
1182       .count_handles = 1,
1183       .timeout_nsec = INT64_MAX,
1184       .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL,
1185    };
1186    int ret;
1187 
1188    ret = drmIoctl(queue->vk.base.device->drm_fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait);
1189    assert(!ret);
1190 
1191    return VK_SUCCESS;
1192 }
1193 
1194 VkResult
panvk_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)1195 panvk_EnumerateInstanceExtensionProperties(const char *pLayerName,
1196                                            uint32_t *pPropertyCount,
1197                                            VkExtensionProperties *pProperties)
1198 {
1199    if (pLayerName)
1200       return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1201 
1202    return vk_enumerate_instance_extension_properties(
1203       &panvk_instance_extensions, pPropertyCount, pProperties);
1204 }
1205 
1206 PFN_vkVoidFunction
panvk_GetInstanceProcAddr(VkInstance _instance,const char * pName)1207 panvk_GetInstanceProcAddr(VkInstance _instance, const char *pName)
1208 {
1209    VK_FROM_HANDLE(panvk_instance, instance, _instance);
1210    return vk_instance_get_proc_addr(&instance->vk, &panvk_instance_entrypoints,
1211                                     pName);
1212 }
1213 
1214 /* The loader wants us to expose a second GetInstanceProcAddr function
1215  * to work around certain LD_PRELOAD issues seen in apps.
1216  */
1217 PUBLIC
1218 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)1219 vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName)
1220 {
1221    return panvk_GetInstanceProcAddr(instance, pName);
1222 }
1223 
1224 VkResult
panvk_AllocateMemory(VkDevice _device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMem)1225 panvk_AllocateMemory(VkDevice _device,
1226                      const VkMemoryAllocateInfo *pAllocateInfo,
1227                      const VkAllocationCallbacks *pAllocator,
1228                      VkDeviceMemory *pMem)
1229 {
1230    VK_FROM_HANDLE(panvk_device, device, _device);
1231    struct panvk_device_memory *mem;
1232    bool can_be_exported = false;
1233 
1234    assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
1235 
1236    if (pAllocateInfo->allocationSize == 0) {
1237       /* Apparently, this is allowed */
1238       *pMem = VK_NULL_HANDLE;
1239       return VK_SUCCESS;
1240    }
1241 
1242    const VkExportMemoryAllocateInfo *export_info =
1243       vk_find_struct_const(pAllocateInfo->pNext, EXPORT_MEMORY_ALLOCATE_INFO);
1244 
1245    if (export_info) {
1246       if (export_info->handleTypes &
1247           ~(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT |
1248             VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT))
1249          return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
1250       else if (export_info->handleTypes)
1251          can_be_exported = true;
1252    }
1253 
1254    mem = vk_object_zalloc(&device->vk, pAllocator, sizeof(*mem),
1255                           VK_OBJECT_TYPE_DEVICE_MEMORY);
1256    if (mem == NULL)
1257       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1258 
1259    const VkImportMemoryFdInfoKHR *fd_info =
1260       vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FD_INFO_KHR);
1261 
1262    if (fd_info && !fd_info->handleType)
1263       fd_info = NULL;
1264 
1265    if (fd_info) {
1266       assert(
1267          fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
1268          fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1269 
1270       /*
1271        * TODO Importing the same fd twice gives us the same handle without
1272        * reference counting.  We need to maintain a per-instance handle-to-bo
1273        * table and add reference count to panvk_bo.
1274        */
1275       mem->bo = pan_kmod_bo_import(device->kmod.dev, fd_info->fd, 0);
1276       /* take ownership and close the fd */
1277       close(fd_info->fd);
1278    } else {
1279       mem->bo = pan_kmod_bo_alloc(device->kmod.dev,
1280                                   can_be_exported ? NULL : device->kmod.vm,
1281                                   pAllocateInfo->allocationSize, 0);
1282    }
1283 
1284    /* Always GPU-map at creation time. */
1285    struct pan_kmod_vm_op op = {
1286       .type = PAN_KMOD_VM_OP_TYPE_MAP,
1287       .va = {
1288          .start = PAN_KMOD_VM_MAP_AUTO_VA,
1289          .size = pan_kmod_bo_size(mem->bo),
1290       },
1291       .map = {
1292          .bo = mem->bo,
1293          .bo_offset = 0,
1294       },
1295    };
1296 
1297    ASSERTED int ret =
1298       pan_kmod_vm_bind(device->kmod.vm, PAN_KMOD_VM_OP_MODE_IMMEDIATE, &op, 1);
1299    assert(!ret);
1300 
1301    mem->addr.dev = op.va.start;
1302 
1303    if (device->debug.decode_ctx) {
1304       pandecode_inject_mmap(device->debug.decode_ctx, mem->addr.dev, NULL,
1305                             pan_kmod_bo_size(mem->bo), NULL);
1306    }
1307 
1308    *pMem = panvk_device_memory_to_handle(mem);
1309 
1310    return VK_SUCCESS;
1311 }
1312 
1313 void
panvk_FreeMemory(VkDevice _device,VkDeviceMemory _mem,const VkAllocationCallbacks * pAllocator)1314 panvk_FreeMemory(VkDevice _device, VkDeviceMemory _mem,
1315                  const VkAllocationCallbacks *pAllocator)
1316 {
1317    VK_FROM_HANDLE(panvk_device, device, _device);
1318    VK_FROM_HANDLE(panvk_device_memory, mem, _mem);
1319 
1320    if (mem == NULL)
1321       return;
1322 
1323    if (device->debug.decode_ctx) {
1324       pandecode_inject_free(device->debug.decode_ctx, mem->addr.dev,
1325                             pan_kmod_bo_size(mem->bo));
1326    }
1327 
1328    struct pan_kmod_vm_op op = {
1329       .type = PAN_KMOD_VM_OP_TYPE_UNMAP,
1330       .va = {
1331          .start = mem->addr.dev,
1332          .size = pan_kmod_bo_size(mem->bo),
1333       },
1334    };
1335 
1336    ASSERTED int ret =
1337       pan_kmod_vm_bind(device->kmod.vm, PAN_KMOD_VM_OP_MODE_IMMEDIATE, &op, 1);
1338    assert(!ret);
1339 
1340    pan_kmod_bo_put(mem->bo);
1341    vk_object_free(&device->vk, pAllocator, mem);
1342 }
1343 
1344 VkResult
panvk_MapMemory(VkDevice _device,VkDeviceMemory _memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags,void ** ppData)1345 panvk_MapMemory(VkDevice _device, VkDeviceMemory _memory, VkDeviceSize offset,
1346                 VkDeviceSize size, VkMemoryMapFlags flags, void **ppData)
1347 {
1348    VK_FROM_HANDLE(panvk_device, device, _device);
1349    VK_FROM_HANDLE(panvk_device_memory, mem, _memory);
1350 
1351    if (mem == NULL) {
1352       *ppData = NULL;
1353       return VK_SUCCESS;
1354    }
1355 
1356    /* Already mapped. */
1357    if (mem->addr.host)
1358       return vk_error(device, VK_ERROR_MEMORY_MAP_FAILED);
1359 
1360    void *addr = pan_kmod_bo_mmap(mem->bo, 0, pan_kmod_bo_size(mem->bo),
1361                                  PROT_READ | PROT_WRITE, MAP_SHARED, NULL);
1362    if (addr == MAP_FAILED)
1363       return vk_error(device, VK_ERROR_MEMORY_MAP_FAILED);
1364 
1365    mem->addr.host = addr;
1366    *ppData = mem->addr.host + offset;
1367    return VK_SUCCESS;
1368 }
1369 
1370 void
panvk_UnmapMemory(VkDevice _device,VkDeviceMemory _memory)1371 panvk_UnmapMemory(VkDevice _device, VkDeviceMemory _memory)
1372 {
1373    VK_FROM_HANDLE(panvk_device_memory, mem, _memory);
1374 
1375    if (mem->addr.host) {
1376       ASSERTED int ret =
1377          os_munmap((void *)mem->addr.host, pan_kmod_bo_size(mem->bo));
1378 
1379       assert(!ret);
1380       mem->addr.host = NULL;
1381    }
1382 }
1383 
1384 VkResult
panvk_FlushMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1385 panvk_FlushMappedMemoryRanges(VkDevice _device, uint32_t memoryRangeCount,
1386                               const VkMappedMemoryRange *pMemoryRanges)
1387 {
1388    return VK_SUCCESS;
1389 }
1390 
1391 VkResult
panvk_InvalidateMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1392 panvk_InvalidateMappedMemoryRanges(VkDevice _device, uint32_t memoryRangeCount,
1393                                    const VkMappedMemoryRange *pMemoryRanges)
1394 {
1395    return VK_SUCCESS;
1396 }
1397 
1398 VkDeviceAddress
panvk_GetBufferDeviceAddress(VkDevice _device,const VkBufferDeviceAddressInfo * pInfo)1399 panvk_GetBufferDeviceAddress(VkDevice _device, const VkBufferDeviceAddressInfo *pInfo)
1400 {
1401    VK_FROM_HANDLE(panvk_buffer, buffer, pInfo->buffer);
1402 
1403    return buffer->dev_addr;
1404 }
1405 
1406 void
panvk_GetBufferMemoryRequirements2(VkDevice device,const VkBufferMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)1407 panvk_GetBufferMemoryRequirements2(VkDevice device,
1408                                    const VkBufferMemoryRequirementsInfo2 *pInfo,
1409                                    VkMemoryRequirements2 *pMemoryRequirements)
1410 {
1411    VK_FROM_HANDLE(panvk_buffer, buffer, pInfo->buffer);
1412 
1413    const uint64_t alignment = 64;
1414    const uint64_t size = align64(buffer->vk.size, alignment);
1415 
1416    pMemoryRequirements->memoryRequirements.memoryTypeBits = 1;
1417    pMemoryRequirements->memoryRequirements.alignment = alignment;
1418    pMemoryRequirements->memoryRequirements.size = size;
1419 }
1420 
1421 void
panvk_GetImageMemoryRequirements2(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)1422 panvk_GetImageMemoryRequirements2(VkDevice device,
1423                                   const VkImageMemoryRequirementsInfo2 *pInfo,
1424                                   VkMemoryRequirements2 *pMemoryRequirements)
1425 {
1426    VK_FROM_HANDLE(panvk_image, image, pInfo->image);
1427 
1428    const uint64_t alignment = 4096;
1429    const uint64_t size = panvk_image_get_total_size(image);
1430 
1431    pMemoryRequirements->memoryRequirements.memoryTypeBits = 1;
1432    pMemoryRequirements->memoryRequirements.alignment = alignment;
1433    pMemoryRequirements->memoryRequirements.size = size;
1434 }
1435 
1436 void
panvk_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)1437 panvk_GetImageSparseMemoryRequirements2(
1438    VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo,
1439    uint32_t *pSparseMemoryRequirementCount,
1440    VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
1441 {
1442    panvk_stub();
1443 }
1444 
1445 void
panvk_GetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory memory,VkDeviceSize * pCommittedMemoryInBytes)1446 panvk_GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory,
1447                                 VkDeviceSize *pCommittedMemoryInBytes)
1448 {
1449    *pCommittedMemoryInBytes = 0;
1450 }
1451 
1452 VkResult
panvk_BindBufferMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos)1453 panvk_BindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
1454                         const VkBindBufferMemoryInfo *pBindInfos)
1455 {
1456    for (uint32_t i = 0; i < bindInfoCount; ++i) {
1457       VK_FROM_HANDLE(panvk_device_memory, mem, pBindInfos[i].memory);
1458       VK_FROM_HANDLE(panvk_buffer, buffer, pBindInfos[i].buffer);
1459       struct pan_kmod_bo *old_bo = buffer->bo;
1460 
1461       if (mem) {
1462          buffer->bo = pan_kmod_bo_get(mem->bo);
1463          buffer->dev_addr = mem->addr.dev + pBindInfos[i].memoryOffset;
1464 
1465          /* FIXME: Only host map for index buffers so we can do the min/max
1466           * index retrieval on the CPU. This is all broken anyway and the
1467           * min/max search should be done with a compute shader that also
1468           * patches the job descriptor accordingly (basically an indirect draw).
1469           *
1470           * Make sure this goes away as soon as we fixed indirect draws.
1471           */
1472          if (buffer->vk.usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
1473             VkDeviceSize offset = pBindInfos[i].memoryOffset;
1474             VkDeviceSize pgsize = getpagesize();
1475             off_t map_start = offset & ~(pgsize - 1);
1476             off_t map_end = offset + buffer->vk.size;
1477             void *map_addr =
1478                pan_kmod_bo_mmap(mem->bo, map_start, map_end - map_start,
1479                                 PROT_WRITE, MAP_SHARED, NULL);
1480 
1481             assert(map_addr != MAP_FAILED);
1482             buffer->host_ptr = map_addr + (offset & pgsize);
1483          }
1484       } else {
1485          buffer->bo = NULL;
1486          buffer->dev_addr = 0;
1487          buffer->host_ptr = NULL;
1488          if (buffer->host_ptr) {
1489             VkDeviceSize pgsize = getpagesize();
1490             uintptr_t map_start = (uintptr_t)buffer->host_ptr & ~(pgsize - 1);
1491             uintptr_t map_end = (uintptr_t)buffer->host_ptr + buffer->vk.size;
1492             ASSERTED int ret =
1493                os_munmap((void *)map_start, map_end - map_start);
1494 
1495             assert(!ret);
1496             buffer->host_ptr = NULL;
1497          }
1498       }
1499 
1500       pan_kmod_bo_put(old_bo);
1501    }
1502    return VK_SUCCESS;
1503 }
1504 
1505 VkResult
panvk_BindImageMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos)1506 panvk_BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
1507                        const VkBindImageMemoryInfo *pBindInfos)
1508 {
1509    for (uint32_t i = 0; i < bindInfoCount; ++i) {
1510       VK_FROM_HANDLE(panvk_image, image, pBindInfos[i].image);
1511       VK_FROM_HANDLE(panvk_device_memory, mem, pBindInfos[i].memory);
1512       struct pan_kmod_bo *old_bo = image->bo;
1513 
1514       if (mem) {
1515          image->bo = pan_kmod_bo_get(mem->bo);
1516          image->pimage.data.base = mem->addr.dev;
1517          image->pimage.data.offset = pBindInfos[i].memoryOffset;
1518          /* Reset the AFBC headers */
1519          if (drm_is_afbc(image->pimage.layout.modifier)) {
1520             /* Transient CPU mapping */
1521             void *base = pan_kmod_bo_mmap(mem->bo, 0, pan_kmod_bo_size(mem->bo),
1522                                           PROT_WRITE, MAP_SHARED, NULL);
1523 
1524             assert(base != MAP_FAILED);
1525 
1526             for (unsigned layer = 0; layer < image->pimage.layout.array_size;
1527                  layer++) {
1528                for (unsigned level = 0; level < image->pimage.layout.nr_slices;
1529                     level++) {
1530                   void *header = base + image->pimage.data.offset +
1531                                  (layer * image->pimage.layout.array_stride) +
1532                                  image->pimage.layout.slices[level].offset;
1533                   memset(header, 0,
1534                          image->pimage.layout.slices[level].afbc.header_size);
1535                }
1536             }
1537 
1538             ASSERTED int ret = os_munmap(base, pan_kmod_bo_size(mem->bo));
1539             assert(!ret);
1540          }
1541       } else {
1542          image->bo = NULL;
1543          image->pimage.data.offset = pBindInfos[i].memoryOffset;
1544       }
1545 
1546       pan_kmod_bo_put(old_bo);
1547    }
1548 
1549    return VK_SUCCESS;
1550 }
1551 
1552 VkResult
panvk_CreateEvent(VkDevice _device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)1553 panvk_CreateEvent(VkDevice _device, const VkEventCreateInfo *pCreateInfo,
1554                   const VkAllocationCallbacks *pAllocator, VkEvent *pEvent)
1555 {
1556    VK_FROM_HANDLE(panvk_device, device, _device);
1557    struct panvk_event *event = vk_object_zalloc(
1558       &device->vk, pAllocator, sizeof(*event), VK_OBJECT_TYPE_EVENT);
1559    if (!event)
1560       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1561 
1562    struct drm_syncobj_create create = {
1563       .flags = 0,
1564    };
1565 
1566    int ret = drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
1567    if (ret)
1568       return VK_ERROR_OUT_OF_HOST_MEMORY;
1569 
1570    event->syncobj = create.handle;
1571    *pEvent = panvk_event_to_handle(event);
1572 
1573    return VK_SUCCESS;
1574 }
1575 
1576 void
panvk_DestroyEvent(VkDevice _device,VkEvent _event,const VkAllocationCallbacks * pAllocator)1577 panvk_DestroyEvent(VkDevice _device, VkEvent _event,
1578                    const VkAllocationCallbacks *pAllocator)
1579 {
1580    VK_FROM_HANDLE(panvk_device, device, _device);
1581    VK_FROM_HANDLE(panvk_event, event, _event);
1582 
1583    if (!event)
1584       return;
1585 
1586    struct drm_syncobj_destroy destroy = {.handle = event->syncobj};
1587    drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);
1588 
1589    vk_object_free(&device->vk, pAllocator, event);
1590 }
1591 
1592 VkResult
panvk_GetEventStatus(VkDevice _device,VkEvent _event)1593 panvk_GetEventStatus(VkDevice _device, VkEvent _event)
1594 {
1595    VK_FROM_HANDLE(panvk_device, device, _device);
1596    VK_FROM_HANDLE(panvk_event, event, _event);
1597    bool signaled;
1598 
1599    struct drm_syncobj_wait wait = {
1600       .handles = (uintptr_t)&event->syncobj,
1601       .count_handles = 1,
1602       .timeout_nsec = 0,
1603       .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
1604    };
1605 
1606    int ret = drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait);
1607    if (ret) {
1608       if (errno == ETIME)
1609          signaled = false;
1610       else {
1611          assert(0);
1612          return VK_ERROR_DEVICE_LOST; /* TODO */
1613       }
1614    } else
1615       signaled = true;
1616 
1617    return signaled ? VK_EVENT_SET : VK_EVENT_RESET;
1618 }
1619 
1620 VkResult
panvk_SetEvent(VkDevice _device,VkEvent _event)1621 panvk_SetEvent(VkDevice _device, VkEvent _event)
1622 {
1623    VK_FROM_HANDLE(panvk_device, device, _device);
1624    VK_FROM_HANDLE(panvk_event, event, _event);
1625 
1626    struct drm_syncobj_array objs = {
1627       .handles = (uint64_t)(uintptr_t)&event->syncobj,
1628       .count_handles = 1};
1629 
1630    /* This is going to just replace the fence for this syncobj with one that
1631     * is already in signaled state. This won't be a problem because the spec
1632     * mandates that the event will have been set before the vkCmdWaitEvents
1633     * command executes.
1634     * https://www.khronos.org/registry/vulkan/specs/1.2/html/chap6.html#commandbuffers-submission-progress
1635     */
1636    if (drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &objs))
1637       return VK_ERROR_DEVICE_LOST;
1638 
1639    return VK_SUCCESS;
1640 }
1641 
1642 VkResult
panvk_ResetEvent(VkDevice _device,VkEvent _event)1643 panvk_ResetEvent(VkDevice _device, VkEvent _event)
1644 {
1645    VK_FROM_HANDLE(panvk_device, device, _device);
1646    VK_FROM_HANDLE(panvk_event, event, _event);
1647 
1648    struct drm_syncobj_array objs = {
1649       .handles = (uint64_t)(uintptr_t)&event->syncobj,
1650       .count_handles = 1};
1651 
1652    if (drmIoctl(device->vk.drm_fd, DRM_IOCTL_SYNCOBJ_RESET, &objs))
1653       return VK_ERROR_DEVICE_LOST;
1654 
1655    return VK_SUCCESS;
1656 }
1657 
1658 VkResult
panvk_CreateBuffer(VkDevice _device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)1659 panvk_CreateBuffer(VkDevice _device, const VkBufferCreateInfo *pCreateInfo,
1660                    const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
1661 {
1662    VK_FROM_HANDLE(panvk_device, device, _device);
1663    struct panvk_buffer *buffer;
1664 
1665    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
1666 
1667    buffer =
1668       vk_buffer_create(&device->vk, pCreateInfo, pAllocator, sizeof(*buffer));
1669    if (buffer == NULL)
1670       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1671 
1672    *pBuffer = panvk_buffer_to_handle(buffer);
1673 
1674    return VK_SUCCESS;
1675 }
1676 
1677 void
panvk_DestroyBuffer(VkDevice _device,VkBuffer _buffer,const VkAllocationCallbacks * pAllocator)1678 panvk_DestroyBuffer(VkDevice _device, VkBuffer _buffer,
1679                     const VkAllocationCallbacks *pAllocator)
1680 {
1681    VK_FROM_HANDLE(panvk_device, device, _device);
1682    VK_FROM_HANDLE(panvk_buffer, buffer, _buffer);
1683 
1684    if (!buffer)
1685       return;
1686 
1687    if (buffer->host_ptr) {
1688       VkDeviceSize pgsize = getpagesize();
1689       uintptr_t map_start = (uintptr_t)buffer->host_ptr & ~(pgsize - 1);
1690       uintptr_t map_end =
1691          ALIGN_POT((uintptr_t)buffer->host_ptr + buffer->vk.size, pgsize);
1692       ASSERTED int ret = os_munmap((void *)map_start, map_end - map_start);
1693 
1694       assert(!ret);
1695       buffer->host_ptr = NULL;
1696    }
1697 
1698    pan_kmod_bo_put(buffer->bo);
1699    vk_buffer_destroy(&device->vk, pAllocator, &buffer->vk);
1700 }
1701 
1702 VkResult
panvk_CreateFramebuffer(VkDevice _device,const VkFramebufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFramebuffer * pFramebuffer)1703 panvk_CreateFramebuffer(VkDevice _device,
1704                         const VkFramebufferCreateInfo *pCreateInfo,
1705                         const VkAllocationCallbacks *pAllocator,
1706                         VkFramebuffer *pFramebuffer)
1707 {
1708    VK_FROM_HANDLE(panvk_device, device, _device);
1709    struct panvk_framebuffer *framebuffer;
1710 
1711    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
1712 
1713    size_t size = sizeof(*framebuffer) + sizeof(struct panvk_attachment_info) *
1714                                            pCreateInfo->attachmentCount;
1715    framebuffer = vk_object_alloc(&device->vk, pAllocator, size,
1716                                  VK_OBJECT_TYPE_FRAMEBUFFER);
1717    if (framebuffer == NULL)
1718       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1719 
1720    framebuffer->attachment_count = pCreateInfo->attachmentCount;
1721    framebuffer->width = pCreateInfo->width;
1722    framebuffer->height = pCreateInfo->height;
1723    framebuffer->layers = pCreateInfo->layers;
1724    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
1725       VkImageView _iview = pCreateInfo->pAttachments[i];
1726       struct panvk_image_view *iview = panvk_image_view_from_handle(_iview);
1727       framebuffer->attachments[i].iview = iview;
1728    }
1729 
1730    *pFramebuffer = panvk_framebuffer_to_handle(framebuffer);
1731    return VK_SUCCESS;
1732 }
1733 
1734 void
panvk_DestroyFramebuffer(VkDevice _device,VkFramebuffer _fb,const VkAllocationCallbacks * pAllocator)1735 panvk_DestroyFramebuffer(VkDevice _device, VkFramebuffer _fb,
1736                          const VkAllocationCallbacks *pAllocator)
1737 {
1738    VK_FROM_HANDLE(panvk_device, device, _device);
1739    VK_FROM_HANDLE(panvk_framebuffer, fb, _fb);
1740 
1741    if (fb)
1742       vk_object_free(&device->vk, pAllocator, fb);
1743 }
1744 
1745 void
panvk_DestroySampler(VkDevice _device,VkSampler _sampler,const VkAllocationCallbacks * pAllocator)1746 panvk_DestroySampler(VkDevice _device, VkSampler _sampler,
1747                      const VkAllocationCallbacks *pAllocator)
1748 {
1749    VK_FROM_HANDLE(panvk_device, device, _device);
1750    VK_FROM_HANDLE(panvk_sampler, sampler, _sampler);
1751 
1752    if (!sampler)
1753       return;
1754 
1755    vk_object_free(&device->vk, pAllocator, sampler);
1756 }
1757 
1758 VkResult
panvk_GetMemoryFdKHR(VkDevice _device,const VkMemoryGetFdInfoKHR * pGetFdInfo,int * pFd)1759 panvk_GetMemoryFdKHR(VkDevice _device, const VkMemoryGetFdInfoKHR *pGetFdInfo,
1760                      int *pFd)
1761 {
1762    VK_FROM_HANDLE(panvk_device, device, _device);
1763    VK_FROM_HANDLE(panvk_device_memory, memory, pGetFdInfo->memory);
1764 
1765    assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
1766 
1767    /* At the moment, we support only the below handle types. */
1768    assert(
1769       pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
1770       pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1771 
1772    int prime_fd = pan_kmod_bo_export(memory->bo);
1773    if (prime_fd < 0)
1774       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
1775 
1776    *pFd = prime_fd;
1777    return VK_SUCCESS;
1778 }
1779 
1780 VkResult
panvk_GetMemoryFdPropertiesKHR(VkDevice _device,VkExternalMemoryHandleTypeFlagBits handleType,int fd,VkMemoryFdPropertiesKHR * pMemoryFdProperties)1781 panvk_GetMemoryFdPropertiesKHR(VkDevice _device,
1782                                VkExternalMemoryHandleTypeFlagBits handleType,
1783                                int fd,
1784                                VkMemoryFdPropertiesKHR *pMemoryFdProperties)
1785 {
1786    assert(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1787    pMemoryFdProperties->memoryTypeBits = 1;
1788    return VK_SUCCESS;
1789 }
1790 
1791 void
panvk_GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalSemaphoreInfo * pExternalSemaphoreInfo,VkExternalSemaphoreProperties * pExternalSemaphoreProperties)1792 panvk_GetPhysicalDeviceExternalSemaphoreProperties(
1793    VkPhysicalDevice physicalDevice,
1794    const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
1795    VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
1796 {
1797    if ((pExternalSemaphoreInfo->handleType ==
1798            VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT ||
1799         pExternalSemaphoreInfo->handleType ==
1800            VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) {
1801       pExternalSemaphoreProperties->exportFromImportedHandleTypes =
1802          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT |
1803          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1804       pExternalSemaphoreProperties->compatibleHandleTypes =
1805          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT |
1806          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1807       pExternalSemaphoreProperties->externalSemaphoreFeatures =
1808          VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
1809          VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
1810    } else {
1811       pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
1812       pExternalSemaphoreProperties->compatibleHandleTypes = 0;
1813       pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
1814    }
1815 }
1816 
1817 void
panvk_GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalFenceInfo * pExternalFenceInfo,VkExternalFenceProperties * pExternalFenceProperties)1818 panvk_GetPhysicalDeviceExternalFenceProperties(
1819    VkPhysicalDevice physicalDevice,
1820    const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo,
1821    VkExternalFenceProperties *pExternalFenceProperties)
1822 {
1823    pExternalFenceProperties->exportFromImportedHandleTypes = 0;
1824    pExternalFenceProperties->compatibleHandleTypes = 0;
1825    pExternalFenceProperties->externalFenceFeatures = 0;
1826 }
1827