• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2019 Raspberry Pi
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <sys/mman.h>
29 #include <sys/sysinfo.h>
30 #include <unistd.h>
31 #include <xf86drm.h>
32 
33 #include "v3dv_private.h"
34 
35 #include "common/v3d_debug.h"
36 
37 #include "broadcom/cle/v3dx_pack.h"
38 
39 #include "compiler/v3d_compiler.h"
40 #include "compiler/glsl_types.h"
41 
42 #include "drm-uapi/v3d_drm.h"
43 #include "format/u_format.h"
44 #include "vk_util.h"
45 
46 #include "util/build_id.h"
47 #include "util/debug.h"
48 
49 #ifdef VK_USE_PLATFORM_XCB_KHR
50 #include <xcb/xcb.h>
51 #include <xcb/dri3.h>
52 #endif
53 
54 #ifdef USE_V3D_SIMULATOR
55 #include "drm-uapi/i915_drm.h"
56 #endif
57 
58 static void *
default_alloc_func(void * pUserData,size_t size,size_t align,VkSystemAllocationScope allocationScope)59 default_alloc_func(void *pUserData, size_t size, size_t align,
60                    VkSystemAllocationScope allocationScope)
61 {
62    return malloc(size);
63 }
64 
65 static void *
default_realloc_func(void * pUserData,void * pOriginal,size_t size,size_t align,VkSystemAllocationScope allocationScope)66 default_realloc_func(void *pUserData, void *pOriginal, size_t size,
67                      size_t align, VkSystemAllocationScope allocationScope)
68 {
69    return realloc(pOriginal, size);
70 }
71 
72 static void
default_free_func(void * pUserData,void * pMemory)73 default_free_func(void *pUserData, void *pMemory)
74 {
75    free(pMemory);
76 }
77 
78 static const VkAllocationCallbacks default_alloc = {
79    .pUserData = NULL,
80    .pfnAllocation = default_alloc_func,
81    .pfnReallocation = default_realloc_func,
82    .pfnFree = default_free_func,
83 };
84 
85 VkResult
v3dv_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)86 v3dv_EnumerateInstanceExtensionProperties(const char *pLayerName,
87                                           uint32_t *pPropertyCount,
88                                           VkExtensionProperties *pProperties)
89 {
90    /* We don't support any layers  */
91    if (pLayerName)
92       return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
93 
94    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
95 
96    for (int i = 0; i < V3DV_INSTANCE_EXTENSION_COUNT; i++) {
97       if (v3dv_instance_extensions_supported.extensions[i]) {
98          vk_outarray_append(&out, prop) {
99             *prop = v3dv_instance_extensions[i];
100          }
101       }
102    }
103 
104    return vk_outarray_status(&out);
105 }
106 
107 VkResult
v3dv_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)108 v3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
109                     const VkAllocationCallbacks *pAllocator,
110                     VkInstance *pInstance)
111 {
112    struct v3dv_instance *instance;
113    VkResult result;
114 
115    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
116 
117    struct v3dv_instance_extension_table enabled_extensions = {};
118    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
119       int idx;
120       for (idx = 0; idx < V3DV_INSTANCE_EXTENSION_COUNT; idx++) {
121          if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
122                     v3dv_instance_extensions[idx].extensionName) == 0)
123             break;
124       }
125 
126       if (idx >= V3DV_INSTANCE_EXTENSION_COUNT)
127          return vk_error(NULL, VK_ERROR_EXTENSION_NOT_PRESENT);
128 
129       if (!v3dv_instance_extensions_supported.extensions[idx])
130          return vk_error(NULL, VK_ERROR_EXTENSION_NOT_PRESENT);
131 
132       enabled_extensions.extensions[idx] = true;
133    }
134 
135    instance = vk_alloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
136                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
137    if (!instance)
138       return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
139 
140    instance->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
141 
142    if (pAllocator)
143       instance->alloc = *pAllocator;
144    else
145       instance->alloc = default_alloc;
146 
147    v3d_process_debug_variable();
148 
149    instance->app_info = (struct v3dv_app_info) { .api_version = 0 };
150    if (pCreateInfo->pApplicationInfo) {
151       const VkApplicationInfo *app = pCreateInfo->pApplicationInfo;
152 
153       instance->app_info.app_name =
154          vk_strdup(&instance->alloc, app->pApplicationName,
155                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
156       instance->app_info.app_version = app->applicationVersion;
157 
158       instance->app_info.engine_name =
159          vk_strdup(&instance->alloc, app->pEngineName,
160                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
161       instance->app_info.engine_version = app->engineVersion;
162 
163       instance->app_info.api_version = app->apiVersion;
164    }
165 
166    if (instance->app_info.api_version == 0)
167       instance->app_info.api_version = VK_API_VERSION_1_0;
168 
169    instance->enabled_extensions = enabled_extensions;
170 
171    for (unsigned i = 0; i < ARRAY_SIZE(instance->dispatch.entrypoints); i++) {
172       /* Vulkan requires that entrypoints for extensions which have not been
173        * enabled must not be advertised.
174        */
175       if (!v3dv_instance_entrypoint_is_enabled(i,
176                                               instance->app_info.api_version,
177                                               &instance->enabled_extensions)) {
178          instance->dispatch.entrypoints[i] = NULL;
179       } else {
180          instance->dispatch.entrypoints[i] =
181             v3dv_instance_dispatch_table.entrypoints[i];
182       }
183    }
184 
185    struct v3dv_physical_device *pdevice = &instance->physicalDevice;
186    for (unsigned i = 0; i < ARRAY_SIZE(pdevice->dispatch.entrypoints); i++) {
187       /* Vulkan requires that entrypoints for extensions which have not been
188        * enabled must not be advertised.
189        */
190       if (!v3dv_physical_device_entrypoint_is_enabled(i,
191                                                      instance->app_info.api_version,
192                                                      &instance->enabled_extensions)) {
193          pdevice->dispatch.entrypoints[i] = NULL;
194       } else {
195          pdevice->dispatch.entrypoints[i] =
196             v3dv_physical_device_dispatch_table.entrypoints[i];
197       }
198    }
199 
200    for (unsigned i = 0; i < ARRAY_SIZE(instance->device_dispatch.entrypoints); i++) {
201       /* Vulkan requires that entrypoints for extensions which have not been
202        * enabled must not be advertised.
203        */
204       if (!v3dv_device_entrypoint_is_enabled(i,
205                                             instance->app_info.api_version,
206                                             &instance->enabled_extensions,
207                                             NULL)) {
208          instance->device_dispatch.entrypoints[i] = NULL;
209       } else {
210          instance->device_dispatch.entrypoints[i] =
211             v3dv_device_dispatch_table.entrypoints[i];
212       }
213    }
214 
215    instance->physicalDeviceCount = -1;
216 
217    result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
218    if (result != VK_SUCCESS) {
219       vk_free2(&default_alloc, pAllocator, instance);
220       return vk_error(NULL, result);
221    }
222 
223 
224    /* We start with the default values for the pipeline_cache envvars */
225    instance->pipeline_cache_enabled = true;
226    instance->default_pipeline_cache_enabled = true;
227    const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE");
228    if (pipeline_cache_str != NULL) {
229       if (strncmp(pipeline_cache_str, "full", 4) == 0) {
230          /* nothing to do, just to filter correct values */
231       } else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) {
232          instance->default_pipeline_cache_enabled = false;
233       } else if (strncmp(pipeline_cache_str, "off", 3) == 0) {
234          instance->pipeline_cache_enabled = false;
235          instance->default_pipeline_cache_enabled = false;
236       } else {
237          fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. "
238                  "Allowed values are: full, no-default-cache, off\n");
239       }
240    }
241 
242    if (instance->pipeline_cache_enabled == false) {
243       fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance "
244               "can be affected negatively\n");
245    } else {
246       if (instance->default_pipeline_cache_enabled == false) {
247         fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. "
248                 "Performance can be affected negatively\n");
249       }
250    }
251 
252    glsl_type_singleton_init_or_ref();
253 
254    VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
255 
256    *pInstance = v3dv_instance_to_handle(instance);
257 
258    return VK_SUCCESS;
259 }
260 
261 static void
physical_device_finish(struct v3dv_physical_device * device)262 physical_device_finish(struct v3dv_physical_device *device)
263 {
264    v3dv_wsi_finish(device);
265 
266    v3d_compiler_free(device->compiler);
267 
268    close(device->render_fd);
269    if (device->display_fd >= 0)
270       close(device->display_fd);
271 
272    free(device->name);
273 
274 #if using_v3d_simulator
275    v3d_simulator_destroy(device->sim_file);
276 #endif
277 }
278 
279 void
v3dv_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)280 v3dv_DestroyInstance(VkInstance _instance,
281                      const VkAllocationCallbacks *pAllocator)
282 {
283    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
284 
285    if (!instance)
286       return;
287 
288    if (instance->physicalDeviceCount > 0) {
289       /* We support at most one physical device. */
290       assert(instance->physicalDeviceCount == 1);
291       physical_device_finish(&instance->physicalDevice);
292    }
293 
294    vk_free(&instance->alloc, (char *)instance->app_info.app_name);
295    vk_free(&instance->alloc, (char *)instance->app_info.engine_name);
296 
297    VG(VALGRIND_DESTROY_MEMPOOL(instance));
298 
299    vk_debug_report_instance_destroy(&instance->debug_report_callbacks);
300 
301    glsl_type_singleton_decref();
302 
303    vk_free(&instance->alloc, instance);
304 }
305 
306 static uint64_t
compute_heap_size()307 compute_heap_size()
308 {
309 #if !using_v3d_simulator
310    /* Query the total ram from the system */
311    struct sysinfo info;
312    sysinfo(&info);
313 
314    uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;
315 #else
316    uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size();
317 #endif
318 
319    /* We don't want to burn too much ram with the GPU.  If the user has 4GiB
320     * or less, we use at most half.  If they have more than 4GiB, we use 3/4.
321     */
322    uint64_t available_ram;
323    if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull)
324       available_ram = total_ram / 2;
325    else
326       available_ram = total_ram * 3 / 4;
327 
328    return available_ram;
329 }
330 
331 /* When running on the simulator we do everything on a single render node so
332  * we don't need to get an authenticated display fd from the display server.
333  */
334 #if !using_v3d_simulator
335 #ifdef VK_USE_PLATFORM_XCB_KHR
336 static int
create_display_fd_xcb()337 create_display_fd_xcb()
338 {
339    int fd = -1;
340 
341    xcb_connection_t *conn = xcb_connect(NULL, NULL);
342    if (xcb_connection_has_error(conn))
343       goto finish;
344 
345    const xcb_setup_t *setup = xcb_get_setup(conn);
346    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
347    xcb_screen_t *screen = iter.data;
348 
349    xcb_dri3_open_cookie_t cookie;
350    xcb_dri3_open_reply_t *reply;
351    cookie = xcb_dri3_open(conn, screen->root, None);
352    reply = xcb_dri3_open_reply(conn, cookie, NULL);
353    if (!reply)
354       goto finish;
355 
356    if (reply->nfd != 1)
357       goto finish;
358 
359    fd = xcb_dri3_open_reply_fds(conn, reply)[0];
360    fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
361 
362 finish:
363    xcb_disconnect(conn);
364    if (reply)
365       free(reply);
366 
367    return fd;
368 }
369 #endif
370 #endif
371 
372 static bool
v3d_has_feature(struct v3dv_physical_device * device,enum drm_v3d_param feature)373 v3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature)
374 {
375    struct drm_v3d_get_param p = {
376       .param = feature,
377    };
378    if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0)
379       return false;
380    return p.value;
381 }
382 
383 static bool
device_has_expected_features(struct v3dv_physical_device * device)384 device_has_expected_features(struct v3dv_physical_device *device)
385 {
386    return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) &&
387           v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) &&
388           v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);
389 }
390 
391 
392 static VkResult
init_uuids(struct v3dv_physical_device * device)393 init_uuids(struct v3dv_physical_device *device)
394 {
395    const struct build_id_note *note =
396       build_id_find_nhdr_for_addr(init_uuids);
397    if (!note) {
398       return vk_errorf(device->instance,
399                        VK_ERROR_INITIALIZATION_FAILED,
400                        "Failed to find build-id");
401    }
402 
403    unsigned build_id_len = build_id_length(note);
404    if (build_id_len < 20) {
405       return vk_errorf(device->instance,
406                        VK_ERROR_INITIALIZATION_FAILED,
407                        "build-id too short.  It needs to be a SHA");
408    }
409 
410    uint32_t vendor_id = v3dv_physical_device_vendor_id(device);
411    uint32_t device_id = v3dv_physical_device_device_id(device);
412 
413    struct mesa_sha1 sha1_ctx;
414    uint8_t sha1[20];
415    STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
416 
417    /* The pipeline cache UUID is used for determining when a pipeline cache is
418     * invalid.  It needs both a driver build and the PCI ID of the device.
419     */
420    _mesa_sha1_init(&sha1_ctx);
421    _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
422    _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
423    _mesa_sha1_final(&sha1_ctx, sha1);
424    memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
425 
426    /* The driver UUID is used for determining sharability of images and memory
427     * between two Vulkan instances in separate processes.  People who want to
428     * share memory need to also check the device UUID (below) so all this
429     * needs to be is the build-id.
430     */
431    memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE);
432 
433    /* The device UUID uniquely identifies the given device within the machine.
434     * Since we never have more than one device, this doesn't need to be a real
435     * UUID.
436     */
437    _mesa_sha1_init(&sha1_ctx);
438    _mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id));
439    _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
440    _mesa_sha1_final(&sha1_ctx, sha1);
441    memcpy(device->device_uuid, sha1, VK_UUID_SIZE);
442 
443    return VK_SUCCESS;
444 }
445 
446 static VkResult
physical_device_init(struct v3dv_physical_device * device,struct v3dv_instance * instance,drmDevicePtr drm_device)447 physical_device_init(struct v3dv_physical_device *device,
448                      struct v3dv_instance *instance,
449                      drmDevicePtr drm_device)
450 {
451    VkResult result = VK_SUCCESS;
452    int32_t display_fd = -1;
453 
454    device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
455    device->instance = instance;
456 
457    const char *path = drm_device->nodes[DRM_NODE_RENDER];
458    int32_t render_fd = open(path, O_RDWR | O_CLOEXEC);
459    if (render_fd < 0)
460       return vk_error(instance, VK_ERROR_INCOMPATIBLE_DRIVER);
461 
462    /* If we are running on real hardware we need to open the vc4 display
463     * device so we can allocate winsys BOs for the v3d core to render into.
464     */
465 #if !using_v3d_simulator
466 #ifdef VK_USE_PLATFORM_XCB_KHR
467    display_fd = create_display_fd_xcb();
468 #endif
469 
470    if (display_fd == -1) {
471       result = VK_ERROR_INCOMPATIBLE_DRIVER;
472       goto fail;
473    }
474 #endif
475 
476    device->render_fd = render_fd;       /* The v3d render node  */
477    device->display_fd = display_fd;    /* The vc4 primary node */
478 
479 #if using_v3d_simulator
480    device->sim_file = v3d_simulator_init(device->render_fd);
481 #endif
482 
483    if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
484       result = VK_ERROR_INCOMPATIBLE_DRIVER;
485       goto fail;
486    }
487 
488    if (device->devinfo.ver < 42) {
489       result = VK_ERROR_INCOMPATIBLE_DRIVER;
490       goto fail;
491    }
492 
493    if (!device_has_expected_features(device)) {
494       result = VK_ERROR_INCOMPATIBLE_DRIVER;
495       goto fail;
496    }
497 
498    result = init_uuids(device);
499    if (result != VK_SUCCESS)
500       goto fail;
501 
502    device->compiler = v3d_compiler_init(&device->devinfo);
503    device->next_program_id = 0;
504 
505    asprintf(&device->name, "V3D %d.%d",
506             device->devinfo.ver / 10, device->devinfo.ver % 10);
507 
508    /* Setup available memory heaps and types */
509    VkPhysicalDeviceMemoryProperties *mem = &device->memory;
510    mem->memoryHeapCount = 1;
511    mem->memoryHeaps[0].size = compute_heap_size();
512    mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
513 
514    /* This is the only combination required by the spec */
515    mem->memoryTypeCount = 1;
516    mem->memoryTypes[0].propertyFlags =
517       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
518       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
519       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
520    mem->memoryTypes[0].heapIndex = 0;
521 
522    device->options.merge_jobs = getenv("V3DV_NO_MERGE_JOBS") == NULL;
523 
524    result = v3dv_wsi_init(device);
525    if (result != VK_SUCCESS) {
526       vk_error(instance, result);
527       goto fail;
528    }
529 
530    v3dv_physical_device_get_supported_extensions(device,
531                                                  &device->supported_extensions);
532 
533    fprintf(stderr, "WARNING: v3dv is neither a complete nor a conformant "
534                    "Vulkan implementation. Testing use only.\n");
535 
536    return VK_SUCCESS;
537 
538 fail:
539    if (render_fd >= 0)
540       close(render_fd);
541    if (display_fd >= 0)
542       close(display_fd);
543 
544    return result;
545 }
546 
547 static VkResult
enumerate_devices(struct v3dv_instance * instance)548 enumerate_devices(struct v3dv_instance *instance)
549 {
550    /* TODO: Check for more devices? */
551    drmDevicePtr devices[8];
552    VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
553    int max_devices;
554 
555    instance->physicalDeviceCount = 0;
556 
557    max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
558    if (max_devices < 1)
559       return VK_ERROR_INCOMPATIBLE_DRIVER;
560 
561 #if !using_v3d_simulator
562    int32_t v3d_idx = -1;
563    int32_t vc4_idx = -1;
564 #endif
565    for (unsigned i = 0; i < (unsigned)max_devices; i++) {
566 #if using_v3d_simulator
567       /* In the simulator, we look for an Intel render node */
568       if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
569           devices[i]->bustype == DRM_BUS_PCI &&
570           devices[i]->deviceinfo.pci->vendor_id == 0x8086) {
571          result = physical_device_init(&instance->physicalDevice, instance,
572                                        devices[i]);
573          if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
574             break;
575       }
576 #else
577       /* On actual hardware, we should have a render node (v3d)
578        * and a primary node (vc4). We will need to use the primary
579        * to allocate WSI buffers and share them with the render node
580        * via prime, but that is a privileged operation so we need the
581        * primary node to be authenticated, and for that we need the
582        * display server to provide the device fd (with DRI3), so we
583        * here we only check that the device is present but we don't
584        * try to open it.
585        */
586       if (devices[i]->bustype != DRM_BUS_PLATFORM)
587          continue;
588 
589       if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) {
590          char **compat = devices[i]->deviceinfo.platform->compatible;
591          while (*compat) {
592             if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) {
593                v3d_idx = i;
594                break;
595             }
596             compat++;
597          }
598       } else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) {
599          char **compat = devices[i]->deviceinfo.platform->compatible;
600          while (*compat) {
601             if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 ||
602                 strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) {
603                vc4_idx = i;
604                break;
605             }
606             compat++;
607          }
608       }
609 #endif
610    }
611 
612 #if !using_v3d_simulator
613    if (v3d_idx == -1 || vc4_idx == -1)
614       result = VK_ERROR_INCOMPATIBLE_DRIVER;
615    else
616       result = physical_device_init(&instance->physicalDevice, instance,
617                                     devices[v3d_idx]);
618 #endif
619 
620    drmFreeDevices(devices, max_devices);
621 
622    if (result == VK_SUCCESS)
623       instance->physicalDeviceCount = 1;
624 
625    return result;
626 }
627 
628 static VkResult
instance_ensure_physical_device(struct v3dv_instance * instance)629 instance_ensure_physical_device(struct v3dv_instance *instance)
630 {
631    if (instance->physicalDeviceCount < 0) {
632       VkResult result = enumerate_devices(instance);
633       if (result != VK_SUCCESS &&
634           result != VK_ERROR_INCOMPATIBLE_DRIVER)
635          return result;
636    }
637 
638    return VK_SUCCESS;
639 }
640 
641 VkResult
v3dv_EnumeratePhysicalDevices(VkInstance _instance,uint32_t * pPhysicalDeviceCount,VkPhysicalDevice * pPhysicalDevices)642 v3dv_EnumeratePhysicalDevices(VkInstance _instance,
643                               uint32_t *pPhysicalDeviceCount,
644                               VkPhysicalDevice *pPhysicalDevices)
645 {
646    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
647    VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);
648 
649    VkResult result = instance_ensure_physical_device(instance);
650    if (result != VK_SUCCESS)
651       return result;
652 
653    if (instance->physicalDeviceCount == 0)
654       return VK_SUCCESS;
655 
656    assert(instance->physicalDeviceCount == 1);
657    vk_outarray_append(&out, i) {
658       *i = v3dv_physical_device_to_handle(&instance->physicalDevice);
659    }
660 
661    return vk_outarray_status(&out);
662 }
663 
664 void
v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures * pFeatures)665 v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
666                                VkPhysicalDeviceFeatures *pFeatures)
667 {
668    memset(pFeatures, 0, sizeof(*pFeatures));
669 
670    *pFeatures = (VkPhysicalDeviceFeatures) {
671       .robustBufferAccess = true, /* This feature is mandatory */
672       .fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */
673       .imageCubeArray = true,
674       .independentBlend = true,
675       .geometryShader = false,
676       .tessellationShader = false,
677       .sampleRateShading = true,
678       .dualSrcBlend = false,
679       .logicOp = true,
680       .multiDrawIndirect = false,
681       .drawIndirectFirstInstance = true,
682       .depthClamp = false,
683       .depthBiasClamp = false,
684       .fillModeNonSolid = true,
685       .depthBounds = false, /* Only available since V3D 4.3.16.2 */
686       .wideLines = true,
687       .largePoints = true,
688       .alphaToOne = true,
689       .multiViewport = false,
690       .samplerAnisotropy = true,
691       .textureCompressionETC2 = true,
692       .textureCompressionASTC_LDR = false,
693       .textureCompressionBC = false,
694       .occlusionQueryPrecise = true,
695       .pipelineStatisticsQuery = false,
696       .vertexPipelineStoresAndAtomics = true,
697       .fragmentStoresAndAtomics = true,
698       .shaderTessellationAndGeometryPointSize = false,
699       .shaderImageGatherExtended = false,
700       .shaderStorageImageExtendedFormats = true,
701       .shaderStorageImageMultisample = false,
702       .shaderStorageImageReadWithoutFormat = false,
703       .shaderStorageImageWriteWithoutFormat = false,
704       .shaderUniformBufferArrayDynamicIndexing = false,
705       .shaderSampledImageArrayDynamicIndexing = false,
706       .shaderStorageBufferArrayDynamicIndexing = false,
707       .shaderStorageImageArrayDynamicIndexing = false,
708       .shaderClipDistance = true,
709       .shaderCullDistance = false,
710       .shaderFloat64 = false,
711       .shaderInt64 = false,
712       .shaderInt16 = false,
713       .shaderResourceResidency = false,
714       .shaderResourceMinLod = false,
715       .sparseBinding = false,
716       .sparseResidencyBuffer = false,
717       .sparseResidencyImage2D = false,
718       .sparseResidencyImage3D = false,
719       .sparseResidency2Samples = false,
720       .sparseResidency4Samples = false,
721       .sparseResidency8Samples = false,
722       .sparseResidency16Samples = false,
723       .sparseResidencyAliased = false,
724       .variableMultisampleRate = false,
725       .inheritedQueries = true,
726    };
727 }
728 
729 void
v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures2 * pFeatures)730 v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
731                                 VkPhysicalDeviceFeatures2 *pFeatures)
732 {
733    v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
734 
735    vk_foreach_struct(ext, pFeatures->pNext) {
736       switch (ext->sType) {
737       default:
738          v3dv_debug_ignored_stype(ext->sType);
739          break;
740       }
741    }
742 }
743 
744 uint32_t
v3dv_physical_device_vendor_id(struct v3dv_physical_device * dev)745 v3dv_physical_device_vendor_id(struct v3dv_physical_device *dev)
746 {
747    return 0x14E4; /* Broadcom */
748 }
749 
750 
751 #if using_v3d_simulator
752 static bool
get_i915_param(int fd,uint32_t param,int * value)753 get_i915_param(int fd, uint32_t param, int *value)
754 {
755    int tmp;
756 
757    struct drm_i915_getparam gp = {
758       .param = param,
759       .value = &tmp,
760    };
761 
762    int ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
763    if (ret != 0)
764       return false;
765 
766    *value = tmp;
767    return true;
768 }
769 #endif
770 
771 uint32_t
v3dv_physical_device_device_id(struct v3dv_physical_device * dev)772 v3dv_physical_device_device_id(struct v3dv_physical_device *dev)
773 {
774 #if using_v3d_simulator
775    int devid = 0;
776 
777    if (!get_i915_param(dev->render_fd, I915_PARAM_CHIPSET_ID, &devid))
778       fprintf(stderr, "Error getting device_id\n");
779 
780    return devid;
781 #else
782    return dev->devinfo.ver;
783 #endif
784 }
785 
786 void
v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties * pProperties)787 v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
788                                  VkPhysicalDeviceProperties *pProperties)
789 {
790    V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
791 
792    const uint32_t page_size = 4096;
793    const uint32_t mem_size = compute_heap_size();
794 
795    /* Per-stage limits */
796    const uint32_t max_samplers = 16;
797    const uint32_t max_uniform_buffers = 12;
798    const uint32_t max_storage_buffers = 12;
799    const uint32_t max_dynamic_storage_buffers = 6;
800    const uint32_t max_sampled_images = 16;
801    const uint32_t max_storage_images = 4;
802    const uint32_t max_input_attachments = 4;
803    assert(max_sampled_images + max_storage_images + max_input_attachments
804           <= V3D_MAX_TEXTURE_SAMPLERS);
805 
806    const uint32_t max_varying_components = 16 * 4;
807    const uint32_t max_render_targets = 4;
808 
809    const uint32_t v3d_coord_shift = 6;
810 
811    const uint32_t v3d_point_line_granularity = 2.0f / (1 << v3d_coord_shift);
812    const uint32_t max_fb_size = 4096;
813 
814    const VkSampleCountFlags supported_sample_counts =
815       VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
816 
817    struct timespec clock_res;
818    clock_getres(CLOCK_MONOTONIC, &clock_res);
819    const float timestamp_period =
820       clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec;
821 
822    /* FIXME: this will probably require an in-depth review */
823    VkPhysicalDeviceLimits limits = {
824       .maxImageDimension1D                      = 4096,
825       .maxImageDimension2D                      = 4096,
826       .maxImageDimension3D                      = 4096,
827       .maxImageDimensionCube                    = 4096,
828       .maxImageArrayLayers                      = 2048,
829       .maxTexelBufferElements                   = (1ul << 28),
830       .maxUniformBufferRange                    = (1ul << 27),
831       .maxStorageBufferRange                    = (1ul << 27),
832       .maxPushConstantsSize                     = MAX_PUSH_CONSTANTS_SIZE,
833       .maxMemoryAllocationCount                 = mem_size / page_size,
834       .maxSamplerAllocationCount                = 64 * 1024,
835       .bufferImageGranularity                   = 256, /* A cache line */
836       .sparseAddressSpaceSize                   = 0,
837       .maxBoundDescriptorSets                   = MAX_SETS,
838       .maxPerStageDescriptorSamplers            = max_samplers,
839       .maxPerStageDescriptorUniformBuffers      = max_uniform_buffers,
840       .maxPerStageDescriptorStorageBuffers      = max_storage_buffers,
841       .maxPerStageDescriptorSampledImages       = max_sampled_images,
842       .maxPerStageDescriptorStorageImages       = max_storage_images,
843       .maxPerStageDescriptorInputAttachments    = max_input_attachments,
844       .maxPerStageResources                     = 128,
845 
846       /* We multiply some limits by 6 to account for all shader stages */
847       .maxDescriptorSetSamplers                 = 6 * max_samplers,
848       .maxDescriptorSetUniformBuffers           = 6 * max_uniform_buffers,
849       .maxDescriptorSetUniformBuffersDynamic    = 8,
850       .maxDescriptorSetStorageBuffers           = 6 * max_storage_buffers,
851       .maxDescriptorSetStorageBuffersDynamic    = 6 * max_dynamic_storage_buffers,
852       .maxDescriptorSetSampledImages            = 6 * max_sampled_images,
853       .maxDescriptorSetStorageImages            = 6 * max_storage_images,
854       .maxDescriptorSetInputAttachments         = 4,
855 
856       /* Vertex limits */
857       .maxVertexInputAttributes                 = MAX_VERTEX_ATTRIBS,
858       .maxVertexInputBindings                   = MAX_VBS,
859       .maxVertexInputAttributeOffset            = 0xffffffff,
860       .maxVertexInputBindingStride              = 0xffffffff,
861       .maxVertexOutputComponents                = max_varying_components,
862 
863       /* Tessellation limits */
864       .maxTessellationGenerationLevel           = 0,
865       .maxTessellationPatchSize                 = 0,
866       .maxTessellationControlPerVertexInputComponents = 0,
867       .maxTessellationControlPerVertexOutputComponents = 0,
868       .maxTessellationControlPerPatchOutputComponents = 0,
869       .maxTessellationControlTotalOutputComponents = 0,
870       .maxTessellationEvaluationInputComponents = 0,
871       .maxTessellationEvaluationOutputComponents = 0,
872 
873       /* Geometry limits */
874       .maxGeometryShaderInvocations             = 0,
875       .maxGeometryInputComponents               = 0,
876       .maxGeometryOutputComponents              = 0,
877       .maxGeometryOutputVertices                = 0,
878       .maxGeometryTotalOutputComponents         = 0,
879 
880       /* Fragment limits */
881       .maxFragmentInputComponents               = max_varying_components,
882       .maxFragmentOutputAttachments             = 4,
883       .maxFragmentDualSrcAttachments            = 0,
884       .maxFragmentCombinedOutputResources       = max_render_targets +
885                                                   max_storage_buffers +
886                                                   max_storage_images,
887 
888       /* Compute limits */
889       .maxComputeSharedMemorySize               = 16384,
890       .maxComputeWorkGroupCount                 = { 65535, 65535, 65535 },
891       .maxComputeWorkGroupInvocations           = 256,
892       .maxComputeWorkGroupSize                  = { 256, 256, 256 },
893 
894       .subPixelPrecisionBits                    = v3d_coord_shift,
895       .subTexelPrecisionBits                    = 8,
896       .mipmapPrecisionBits                      = 8,
897       .maxDrawIndexedIndexValue                 = 0x00ffffff,
898       .maxDrawIndirectCount                     = 0x7fffffff,
899       .maxSamplerLodBias                        = 14.0f,
900       .maxSamplerAnisotropy                     = 16.0f,
901       .maxViewports                             = MAX_VIEWPORTS,
902       .maxViewportDimensions                    = { max_fb_size, max_fb_size },
903       .viewportBoundsRange                      = { -2.0 * max_fb_size,
904                                                     2.0 * max_fb_size - 1 },
905       .viewportSubPixelBits                     = 0,
906       .minMemoryMapAlignment                    = page_size,
907       .minTexelBufferOffsetAlignment            = VC5_UIFBLOCK_SIZE,
908       .minUniformBufferOffsetAlignment          = 32,
909       .minStorageBufferOffsetAlignment          = 32,
910       .minTexelOffset                           = -8,
911       .maxTexelOffset                           = 7,
912       .minTexelGatherOffset                     = -8,
913       .maxTexelGatherOffset                     = 7,
914       .minInterpolationOffset                   = -0.5,
915       .maxInterpolationOffset                   = 0.5,
916       .subPixelInterpolationOffsetBits          = v3d_coord_shift,
917       .maxFramebufferWidth                      = max_fb_size,
918       .maxFramebufferHeight                     = max_fb_size,
919       .maxFramebufferLayers                     = 256,
920       .framebufferColorSampleCounts             = supported_sample_counts,
921       .framebufferDepthSampleCounts             = supported_sample_counts,
922       .framebufferStencilSampleCounts           = supported_sample_counts,
923       .framebufferNoAttachmentsSampleCounts     = supported_sample_counts,
924       .maxColorAttachments                      = max_render_targets,
925       .sampledImageColorSampleCounts            = supported_sample_counts,
926       .sampledImageIntegerSampleCounts          = supported_sample_counts,
927       .sampledImageDepthSampleCounts            = supported_sample_counts,
928       .sampledImageStencilSampleCounts          = supported_sample_counts,
929       .storageImageSampleCounts                 = VK_SAMPLE_COUNT_1_BIT,
930       .maxSampleMaskWords                       = 1,
931       .timestampComputeAndGraphics              = true,
932       .timestampPeriod                          = timestamp_period,
933       .maxClipDistances                         = 8,
934       .maxCullDistances                         = 0,
935       .maxCombinedClipAndCullDistances          = 8,
936       .discreteQueuePriorities                  = 2,
937       .pointSizeRange                           = { v3d_point_line_granularity,
938                                                     V3D_MAX_POINT_SIZE },
939       .lineWidthRange                           = { 1.0f, V3D_MAX_LINE_WIDTH },
940       .pointSizeGranularity                     = v3d_point_line_granularity,
941       .lineWidthGranularity                     = v3d_point_line_granularity,
942       .strictLines                              = true,
943       .standardSampleLocations                  = false,
944       .optimalBufferCopyOffsetAlignment         = 32,
945       .optimalBufferCopyRowPitchAlignment       = 32,
946       .nonCoherentAtomSize                      = 256,
947    };
948 
949    *pProperties = (VkPhysicalDeviceProperties) {
950       .apiVersion = v3dv_physical_device_api_version(pdevice),
951       .driverVersion = vk_get_driver_version(),
952       .vendorID = v3dv_physical_device_vendor_id(pdevice),
953       .deviceID = v3dv_physical_device_device_id(pdevice),
954       .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
955       .limits = limits,
956       .sparseProperties = { 0 },
957    };
958 
959    snprintf(pProperties->deviceName, sizeof(pProperties->deviceName),
960             "%s", pdevice->name);
961    memcpy(pProperties->pipelineCacheUUID,
962           pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
963 }
964 
965 void
v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties2 * pProperties)966 v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
967                                   VkPhysicalDeviceProperties2 *pProperties)
968 {
969    V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
970 
971    v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
972 
973    vk_foreach_struct(ext, pProperties->pNext) {
974       switch (ext->sType) {
975       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
976          VkPhysicalDeviceIDProperties *id_props =
977             (VkPhysicalDeviceIDProperties *)ext;
978          memcpy(id_props->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
979          memcpy(id_props->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
980          /* The LUID is for Windows. */
981          id_props->deviceLUIDValid = false;
982          break;
983       }
984       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
985          /* Do nothing, not even logging. This is a non-PCI device, so we will
986           * never provide this extension.
987           */
988          break;
989       default:
990          v3dv_debug_ignored_stype(ext->sType);
991          break;
992       }
993    }
994 }
995 
996 /* We support exactly one queue family. */
997 static const VkQueueFamilyProperties
998 v3dv_queue_family_properties = {
999    .queueFlags = VK_QUEUE_GRAPHICS_BIT |
1000                  VK_QUEUE_COMPUTE_BIT |
1001                  VK_QUEUE_TRANSFER_BIT,
1002    .queueCount = 1,
1003    .timestampValidBits = 64,
1004    .minImageTransferGranularity = { 1, 1, 1 },
1005 };
1006 
1007 void
v3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,uint32_t * pCount,VkQueueFamilyProperties * pQueueFamilyProperties)1008 v3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
1009                                             uint32_t *pCount,
1010                                             VkQueueFamilyProperties *pQueueFamilyProperties)
1011 {
1012    VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pCount);
1013 
1014    vk_outarray_append(&out, p) {
1015       *p = v3dv_queue_family_properties;
1016    }
1017 }
1018 
1019 void
v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)1020 v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
1021                                              uint32_t *pQueueFamilyPropertyCount,
1022                                              VkQueueFamilyProperties2 *pQueueFamilyProperties)
1023 {
1024    VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
1025 
1026    vk_outarray_append(&out, p) {
1027       p->queueFamilyProperties = v3dv_queue_family_properties;
1028 
1029       vk_foreach_struct(s, p->pNext) {
1030          v3dv_debug_ignored_stype(s->sType);
1031       }
1032    }
1033 }
1034 
1035 void
v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties * pMemoryProperties)1036 v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
1037                                        VkPhysicalDeviceMemoryProperties *pMemoryProperties)
1038 {
1039    V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
1040    *pMemoryProperties = device->memory;
1041 }
1042 
1043 void
v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)1044 v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
1045                                         VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1046 {
1047    v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice,
1048                                           &pMemoryProperties->memoryProperties);
1049 
1050    vk_foreach_struct(ext, pMemoryProperties->pNext) {
1051       switch (ext->sType) {
1052       default:
1053          v3dv_debug_ignored_stype(ext->sType);
1054          break;
1055       }
1056    }
1057 }
1058 
1059 PFN_vkVoidFunction
v3dv_GetInstanceProcAddr(VkInstance _instance,const char * pName)1060 v3dv_GetInstanceProcAddr(VkInstance _instance,
1061                          const char *pName)
1062 {
1063    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1064 
1065    /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly
1066     * when we have to return valid function pointers, NULL, or it's left
1067     * undefined.  See the table for exact details.
1068     */
1069    if (pName == NULL)
1070       return NULL;
1071 
1072 #define LOOKUP_V3DV_ENTRYPOINT(entrypoint)              \
1073    if (strcmp(pName, "vk" #entrypoint) == 0)            \
1074       return (PFN_vkVoidFunction)v3dv_##entrypoint
1075 
1076    LOOKUP_V3DV_ENTRYPOINT(EnumerateInstanceExtensionProperties);
1077    LOOKUP_V3DV_ENTRYPOINT(CreateInstance);
1078 
1079 #undef LOOKUP_V3DV_ENTRYPOINT
1080 
1081    if (instance == NULL)
1082       return NULL;
1083 
1084    int idx = v3dv_get_instance_entrypoint_index(pName);
1085    if (idx >= 0)
1086       return instance->dispatch.entrypoints[idx];
1087 
1088    idx = v3dv_get_physical_device_entrypoint_index(pName);
1089    if (idx >= 0)
1090       return instance->physicalDevice.dispatch.entrypoints[idx];
1091 
1092    idx = v3dv_get_device_entrypoint_index(pName);
1093    if (idx >= 0)
1094       return instance->device_dispatch.entrypoints[idx];
1095 
1096    return NULL;
1097 }
1098 
1099 /* With version 1+ of the loader interface the ICD should expose
1100  * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
1101  */
1102 PUBLIC
1103 VKAPI_ATTR PFN_vkVoidFunction
1104 VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,
1105                                      const char *pName);
1106 
1107 PUBLIC
1108 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)1109 vk_icdGetInstanceProcAddr(VkInstance instance,
1110                           const char*                                 pName)
1111 {
1112    return v3dv_GetInstanceProcAddr(instance, pName);
1113 }
1114 
1115 PFN_vkVoidFunction
v3dv_GetDeviceProcAddr(VkDevice _device,const char * pName)1116 v3dv_GetDeviceProcAddr(VkDevice _device,
1117                        const char *pName)
1118 {
1119    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1120 
1121    if (!device || !pName)
1122       return NULL;
1123 
1124    int idx = v3dv_get_device_entrypoint_index(pName);
1125    if (idx < 0)
1126       return NULL;
1127 
1128    return device->dispatch.entrypoints[idx];
1129 }
1130 
1131 /* With version 4+ of the loader interface the ICD should expose
1132  * vk_icdGetPhysicalDeviceProcAddr()
1133  */
1134 PUBLIC
1135 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1136 vk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
1137                                 const char* pName);
1138 
1139 PFN_vkVoidFunction
vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,const char * pName)1140 vk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
1141                                 const char* pName)
1142 {
1143    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1144 
1145    if (!pName || !instance)
1146       return NULL;
1147 
1148    int idx = v3dv_get_physical_device_entrypoint_index(pName);
1149    if (idx < 0)
1150       return NULL;
1151 
1152    return instance->physicalDevice.dispatch.entrypoints[idx];
1153 }
1154 
1155 VkResult
v3dv_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)1156 v3dv_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
1157                                         const char *pLayerName,
1158                                         uint32_t *pPropertyCount,
1159                                         VkExtensionProperties *pProperties)
1160 {
1161    /* We don't support any layers */
1162    if (pLayerName)
1163       return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1164 
1165    V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
1166    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
1167 
1168    for (int i = 0; i < V3DV_DEVICE_EXTENSION_COUNT; i++) {
1169       if (device->supported_extensions.extensions[i]) {
1170          vk_outarray_append(&out, prop) {
1171             *prop = v3dv_device_extensions[i];
1172          }
1173       }
1174    }
1175 
1176    return vk_outarray_status(&out);
1177 }
1178 
1179 VkResult
v3dv_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)1180 v3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1181                                       VkLayerProperties *pProperties)
1182 {
1183    if (pProperties == NULL) {
1184       *pPropertyCount = 0;
1185       return VK_SUCCESS;
1186    }
1187 
1188    return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1189 }
1190 
1191 VkResult
v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkLayerProperties * pProperties)1192 v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
1193                                     uint32_t *pPropertyCount,
1194                                     VkLayerProperties *pProperties)
1195 {
1196    V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1197 
1198    if (pProperties == NULL) {
1199       *pPropertyCount = 0;
1200       return VK_SUCCESS;
1201    }
1202 
1203    return vk_error(physical_device->instance, VK_ERROR_LAYER_NOT_PRESENT);
1204 }
1205 
1206 static VkResult
queue_init(struct v3dv_device * device,struct v3dv_queue * queue)1207 queue_init(struct v3dv_device *device, struct v3dv_queue *queue)
1208 {
1209    queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
1210    queue->device = device;
1211    queue->flags = 0;
1212    queue->noop_job = NULL;
1213    list_inithead(&queue->submit_wait_list);
1214    pthread_mutex_init(&queue->mutex, NULL);
1215    return VK_SUCCESS;
1216 }
1217 
1218 static void
queue_finish(struct v3dv_queue * queue)1219 queue_finish(struct v3dv_queue *queue)
1220 {
1221    assert(list_is_empty(&queue->submit_wait_list));
1222    if (queue->noop_job)
1223       v3dv_job_destroy(queue->noop_job);
1224    pthread_mutex_destroy(&queue->mutex);
1225 }
1226 
1227 static void
init_device_dispatch(struct v3dv_device * device)1228 init_device_dispatch(struct v3dv_device *device)
1229 {
1230    for (unsigned i = 0; i < ARRAY_SIZE(device->dispatch.entrypoints); i++) {
1231       /* Vulkan requires that entrypoints for extensions which have not been
1232        * enabled must not be advertised.
1233        */
1234       if (!v3dv_device_entrypoint_is_enabled(i, device->instance->app_info.api_version,
1235                                              &device->instance->enabled_extensions,
1236                                              &device->enabled_extensions)) {
1237          device->dispatch.entrypoints[i] = NULL;
1238       } else {
1239          device->dispatch.entrypoints[i] =
1240             v3dv_device_dispatch_table.entrypoints[i];
1241       }
1242    }
1243 }
1244 
1245 static void
init_device_meta(struct v3dv_device * device)1246 init_device_meta(struct v3dv_device *device)
1247 {
1248    mtx_init(&device->meta.mtx, mtx_plain);
1249    v3dv_meta_clear_init(device);
1250    v3dv_meta_blit_init(device);
1251 }
1252 
1253 static void
destroy_device_meta(struct v3dv_device * device)1254 destroy_device_meta(struct v3dv_device *device)
1255 {
1256    mtx_destroy(&device->meta.mtx);
1257    v3dv_meta_clear_finish(device);
1258    v3dv_meta_blit_finish(device);
1259 }
1260 
1261 VkResult
v3dv_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)1262 v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
1263                   const VkDeviceCreateInfo *pCreateInfo,
1264                   const VkAllocationCallbacks *pAllocator,
1265                   VkDevice *pDevice)
1266 {
1267    V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1268    struct v3dv_instance *instance = physical_device->instance;
1269    VkResult result;
1270    struct v3dv_device *device;
1271 
1272    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
1273 
1274    /* Check enabled extensions */
1275    struct v3dv_device_extension_table enabled_extensions = { };
1276    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
1277       int idx;
1278       for (idx = 0; idx < V3DV_DEVICE_EXTENSION_COUNT; idx++) {
1279          if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
1280                     v3dv_device_extensions[idx].extensionName) == 0)
1281             break;
1282       }
1283 
1284       if (idx >= V3DV_DEVICE_EXTENSION_COUNT)
1285          return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
1286 
1287       if (!physical_device->supported_extensions.extensions[idx])
1288          return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
1289 
1290       enabled_extensions.extensions[idx] = true;
1291    }
1292 
1293    /* Check enabled features */
1294    if (pCreateInfo->pEnabledFeatures) {
1295       VkPhysicalDeviceFeatures supported_features;
1296       v3dv_GetPhysicalDeviceFeatures(physicalDevice, &supported_features);
1297       VkBool32 *supported_feature = (VkBool32 *)&supported_features;
1298       VkBool32 *enabled_feature = (VkBool32 *)pCreateInfo->pEnabledFeatures;
1299       unsigned num_features = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
1300       for (uint32_t i = 0; i < num_features; i++) {
1301          if (enabled_feature[i] && !supported_feature[i])
1302             return vk_error(instance, VK_ERROR_FEATURE_NOT_PRESENT);
1303       }
1304    }
1305 
1306    /* Check requested queues (we only expose one queue ) */
1307    assert(pCreateInfo->queueCreateInfoCount == 1);
1308    for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
1309       assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0);
1310       assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1);
1311       if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
1312          return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
1313    }
1314 
1315    device = vk_zalloc2(&physical_device->instance->alloc, pAllocator,
1316                        sizeof(*device), 8,
1317                        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1318    if (!device)
1319       return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1320 
1321    device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
1322    device->instance = instance;
1323 
1324    if (pAllocator)
1325       device->alloc = *pAllocator;
1326    else
1327       device->alloc = physical_device->instance->alloc;
1328 
1329    device->render_fd = physical_device->render_fd;
1330    if (device->render_fd == -1) {
1331       result = VK_ERROR_INITIALIZATION_FAILED;
1332       goto fail;
1333    }
1334 
1335    if (physical_device->display_fd != -1) {
1336       device->display_fd = physical_device->display_fd;
1337       if (device->display_fd == -1) {
1338          result = VK_ERROR_INITIALIZATION_FAILED;
1339          goto fail;
1340       }
1341    } else {
1342       device->display_fd = -1;
1343    }
1344 
1345    pthread_mutex_init(&device->mutex, NULL);
1346 
1347    result = queue_init(device, &device->queue);
1348    if (result != VK_SUCCESS)
1349       goto fail;
1350 
1351    device->devinfo = physical_device->devinfo;
1352    device->enabled_extensions = enabled_extensions;
1353 
1354    if (pCreateInfo->pEnabledFeatures) {
1355       memcpy(&device->features, pCreateInfo->pEnabledFeatures,
1356              sizeof(device->features));
1357    }
1358 
1359    int ret = drmSyncobjCreate(device->render_fd,
1360                               DRM_SYNCOBJ_CREATE_SIGNALED,
1361                               &device->last_job_sync);
1362    if (ret) {
1363       result = VK_ERROR_INITIALIZATION_FAILED;
1364       goto fail;
1365    }
1366 
1367    init_device_dispatch(device);
1368    init_device_meta(device);
1369    v3dv_bo_cache_init(device);
1370    v3dv_pipeline_cache_init(&device->default_pipeline_cache, device,
1371                             device->instance->default_pipeline_cache_enabled);
1372 
1373    *pDevice = v3dv_device_to_handle(device);
1374 
1375    return VK_SUCCESS;
1376 
1377 fail:
1378    vk_free(&device->alloc, device);
1379 
1380    return result;
1381 }
1382 
1383 void
v3dv_DestroyDevice(VkDevice _device,const VkAllocationCallbacks * pAllocator)1384 v3dv_DestroyDevice(VkDevice _device,
1385                    const VkAllocationCallbacks *pAllocator)
1386 {
1387    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1388 
1389    v3dv_DeviceWaitIdle(_device);
1390    queue_finish(&device->queue);
1391    pthread_mutex_destroy(&device->mutex);
1392    drmSyncobjDestroy(device->render_fd, device->last_job_sync);
1393    destroy_device_meta(device);
1394    v3dv_pipeline_cache_finish(&device->default_pipeline_cache);
1395 
1396    /* Bo cache should be removed the last, as any other object could be
1397     * freeing their private bos
1398     */
1399    v3dv_bo_cache_destroy(device);
1400 
1401    vk_free2(&default_alloc, pAllocator, device);
1402 }
1403 
1404 void
v3dv_GetDeviceQueue(VkDevice _device,uint32_t queueFamilyIndex,uint32_t queueIndex,VkQueue * pQueue)1405 v3dv_GetDeviceQueue(VkDevice _device,
1406                     uint32_t queueFamilyIndex,
1407                     uint32_t queueIndex,
1408                     VkQueue *pQueue)
1409 {
1410    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1411 
1412    assert(queueIndex == 0);
1413    assert(queueFamilyIndex == 0);
1414 
1415    *pQueue = v3dv_queue_to_handle(&device->queue);
1416 }
1417 
1418 VkResult
v3dv_DeviceWaitIdle(VkDevice _device)1419 v3dv_DeviceWaitIdle(VkDevice _device)
1420 {
1421    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1422    return v3dv_QueueWaitIdle(v3dv_queue_to_handle(&device->queue));
1423 }
1424 
1425 VkResult
v3dv_CreateDebugReportCallbackEXT(VkInstance _instance,const VkDebugReportCallbackCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDebugReportCallbackEXT * pCallback)1426 v3dv_CreateDebugReportCallbackEXT(VkInstance _instance,
1427                                  const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
1428                                  const VkAllocationCallbacks* pAllocator,
1429                                  VkDebugReportCallbackEXT* pCallback)
1430 {
1431    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1432    return vk_create_debug_report_callback(&instance->debug_report_callbacks,
1433                                           pCreateInfo, pAllocator, &instance->alloc,
1434                                           pCallback);
1435 }
1436 
1437 void
v3dv_DestroyDebugReportCallbackEXT(VkInstance _instance,VkDebugReportCallbackEXT _callback,const VkAllocationCallbacks * pAllocator)1438 v3dv_DestroyDebugReportCallbackEXT(VkInstance _instance,
1439                                   VkDebugReportCallbackEXT _callback,
1440                                   const VkAllocationCallbacks* pAllocator)
1441 {
1442    V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1443    vk_destroy_debug_report_callback(&instance->debug_report_callbacks,
1444                                     _callback, pAllocator, &instance->alloc);
1445 }
1446 
1447 static VkResult
device_alloc(struct v3dv_device * device,struct v3dv_device_memory * mem,VkDeviceSize size)1448 device_alloc(struct v3dv_device *device,
1449              struct v3dv_device_memory *mem,
1450              VkDeviceSize size)
1451 {
1452    /* Our kernel interface is 32-bit */
1453    if (size > UINT32_MAX)
1454       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1455 
1456    mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false);
1457    if (!mem->bo)
1458       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1459 
1460    return VK_SUCCESS;
1461 }
1462 
1463 static void
device_free_wsi_dumb(int32_t display_fd,int32_t dumb_handle)1464 device_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle)
1465 {
1466    assert(display_fd != -1);
1467    if (dumb_handle < 0)
1468       return;
1469 
1470    struct drm_mode_destroy_dumb destroy_dumb = {
1471       .handle = dumb_handle,
1472    };
1473    v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
1474 }
1475 
1476 static void
device_free(struct v3dv_device * device,struct v3dv_device_memory * mem)1477 device_free(struct v3dv_device *device, struct v3dv_device_memory *mem)
1478 {
1479    /* If this memory allocation was for WSI, then we need to use the
1480     * display device to free the allocated dumb BO.
1481     */
1482    if (mem->is_for_wsi) {
1483       assert(mem->has_bo_ownership);
1484       device_free_wsi_dumb(device->instance->physicalDevice.display_fd,
1485                            mem->bo->dumb_handle);
1486    }
1487 
1488    if (mem->has_bo_ownership)
1489       v3dv_bo_free(device, mem->bo);
1490    else if (mem->bo)
1491       vk_free(&device->alloc, mem->bo);
1492 }
1493 
1494 static void
device_unmap(struct v3dv_device * device,struct v3dv_device_memory * mem)1495 device_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem)
1496 {
1497    assert(mem && mem->bo->map && mem->bo->map_size > 0);
1498    v3dv_bo_unmap(device, mem->bo);
1499 }
1500 
1501 static VkResult
device_map(struct v3dv_device * device,struct v3dv_device_memory * mem)1502 device_map(struct v3dv_device *device, struct v3dv_device_memory *mem)
1503 {
1504    assert(mem && mem->bo);
1505 
1506    /* From the spec:
1507     *
1508     *   "After a successful call to vkMapMemory the memory object memory is
1509     *   considered to be currently host mapped. It is an application error to
1510     *   call vkMapMemory on a memory object that is already host mapped."
1511     *
1512     * We are not concerned with this ourselves (validation layers should
1513     * catch these errors and warn users), however, the driver may internally
1514     * map things (for example for debug CLIF dumps or some CPU-side operations)
1515     * so by the time the user calls here the buffer might already been mapped
1516     * internally by the driver.
1517     */
1518    if (mem->bo->map) {
1519       assert(mem->bo->map_size == mem->bo->size);
1520       return VK_SUCCESS;
1521    }
1522 
1523    bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size);
1524    if (!ok)
1525       return VK_ERROR_MEMORY_MAP_FAILED;
1526 
1527    return VK_SUCCESS;
1528 }
1529 
1530 static VkResult
device_import_bo(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,int fd,uint64_t size,struct v3dv_bo ** bo)1531 device_import_bo(struct v3dv_device *device,
1532                  const VkAllocationCallbacks *pAllocator,
1533                  int fd, uint64_t size,
1534                  struct v3dv_bo **bo)
1535 {
1536    VkResult result;
1537 
1538    *bo = vk_alloc2(&device->alloc, pAllocator, sizeof(struct v3dv_bo), 8,
1539                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1540    if (*bo == NULL) {
1541       result = VK_ERROR_OUT_OF_HOST_MEMORY;
1542       goto fail;
1543    }
1544 
1545    off_t real_size = lseek(fd, 0, SEEK_END);
1546    lseek(fd, 0, SEEK_SET);
1547    if (real_size < 0 || (uint64_t) real_size < size) {
1548       result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1549       goto fail;
1550    }
1551 
1552    int ret;
1553    uint32_t handle;
1554    ret = drmPrimeFDToHandle(device->render_fd, fd, &handle);
1555    if (ret) {
1556       result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1557       goto fail;
1558    }
1559 
1560    struct drm_v3d_get_bo_offset get_offset = {
1561       .handle = handle,
1562    };
1563    ret = v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset);
1564    if (ret) {
1565       result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1566       goto fail;
1567    }
1568    assert(get_offset.offset != 0);
1569 
1570    v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false);
1571 
1572    return VK_SUCCESS;
1573 
1574 fail:
1575    if (*bo) {
1576       vk_free2(&device->alloc, pAllocator, *bo);
1577       *bo = NULL;
1578    }
1579    return result;
1580 }
1581 
1582 static VkResult
device_alloc_for_wsi(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,struct v3dv_device_memory * mem,VkDeviceSize size)1583 device_alloc_for_wsi(struct v3dv_device *device,
1584                      const VkAllocationCallbacks *pAllocator,
1585                      struct v3dv_device_memory *mem,
1586                      VkDeviceSize size)
1587 {
1588    /* In the simulator we can get away with a regular allocation since both
1589     * allocation and rendering happen in the same DRM render node. On actual
1590     * hardware we need to allocate our winsys BOs on the vc4 display device
1591     * and import them into v3d.
1592     */
1593 #if using_v3d_simulator
1594       return device_alloc(device, mem, size);
1595 #else
1596    mem->is_for_wsi = true;
1597 
1598    assert(device->display_fd != -1);
1599    int display_fd = device->instance->physicalDevice.display_fd;
1600    struct drm_mode_create_dumb create_dumb = {
1601       .width = 1024, /* one page */
1602       .height = align(size, 4096) / 4096,
1603       .bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM),
1604    };
1605 
1606    int err;
1607    err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
1608    if (err < 0)
1609       goto fail_create;
1610 
1611    int fd;
1612    err =
1613       drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd);
1614    if (err < 0)
1615       goto fail_export;
1616 
1617    VkResult result = device_import_bo(device, pAllocator, fd, size, &mem->bo);
1618    close(fd);
1619    if (result != VK_SUCCESS)
1620       goto fail_import;
1621 
1622    mem->bo->dumb_handle = create_dumb.handle;
1623    return VK_SUCCESS;
1624 
1625 fail_import:
1626 fail_export:
1627    device_free_wsi_dumb(display_fd, create_dumb.handle);
1628 
1629 fail_create:
1630    return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1631 #endif
1632 }
1633 
1634 VkResult
v3dv_AllocateMemory(VkDevice _device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMem)1635 v3dv_AllocateMemory(VkDevice _device,
1636                     const VkMemoryAllocateInfo *pAllocateInfo,
1637                     const VkAllocationCallbacks *pAllocator,
1638                     VkDeviceMemory *pMem)
1639 {
1640    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1641    struct v3dv_device_memory *mem;
1642    struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
1643 
1644    assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
1645 
1646    /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
1647    assert(pAllocateInfo->allocationSize > 0);
1648 
1649    mem = vk_alloc2(&device->alloc, pAllocator, sizeof(*mem), 8,
1650                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1651    if (mem == NULL)
1652       return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
1653 
1654    assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount);
1655    mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
1656    mem->has_bo_ownership = true;
1657    mem->is_for_wsi = false;
1658 
1659    const struct wsi_memory_allocate_info *wsi_info = NULL;
1660    const VkImportMemoryFdInfoKHR *fd_info = NULL;
1661    vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
1662       switch ((unsigned)ext->sType) {
1663       case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA:
1664          wsi_info = (void *)ext;
1665          break;
1666       case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
1667          fd_info = (void *)ext;
1668          break;
1669       default:
1670          v3dv_debug_ignored_stype(ext->sType);
1671          break;
1672       }
1673    }
1674 
1675    VkResult result = VK_SUCCESS;
1676    if (wsi_info) {
1677       result = device_alloc_for_wsi(device, pAllocator, mem,
1678                                     pAllocateInfo->allocationSize);
1679    } else if (fd_info && fd_info->handleType) {
1680       assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
1681              fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1682       result = device_import_bo(device, pAllocator,
1683                                 fd_info->fd, pAllocateInfo->allocationSize,
1684                                 &mem->bo);
1685       mem->has_bo_ownership = false;
1686       if (result == VK_SUCCESS)
1687          close(fd_info->fd);
1688    } else {
1689       result = device_alloc(device, mem, pAllocateInfo->allocationSize);
1690    }
1691 
1692    if (result != VK_SUCCESS) {
1693       vk_free2(&device->alloc, pAllocator, mem);
1694       return vk_error(device->instance, result);
1695    }
1696 
1697    *pMem = v3dv_device_memory_to_handle(mem);
1698    return result;
1699 }
1700 
1701 void
v3dv_FreeMemory(VkDevice _device,VkDeviceMemory _mem,const VkAllocationCallbacks * pAllocator)1702 v3dv_FreeMemory(VkDevice _device,
1703                 VkDeviceMemory _mem,
1704                 const VkAllocationCallbacks *pAllocator)
1705 {
1706    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1707    V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem);
1708 
1709    if (mem == NULL)
1710       return;
1711 
1712    if (mem->bo->map)
1713       v3dv_UnmapMemory(_device, _mem);
1714 
1715    device_free(device, mem);
1716 
1717    vk_free2(&device->alloc, pAllocator, mem);
1718 }
1719 
1720 VkResult
v3dv_MapMemory(VkDevice _device,VkDeviceMemory _memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags,void ** ppData)1721 v3dv_MapMemory(VkDevice _device,
1722                VkDeviceMemory _memory,
1723                VkDeviceSize offset,
1724                VkDeviceSize size,
1725                VkMemoryMapFlags flags,
1726                void **ppData)
1727 {
1728    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1729    V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1730 
1731    if (mem == NULL) {
1732       *ppData = NULL;
1733       return VK_SUCCESS;
1734    }
1735 
1736    assert(offset < mem->bo->size);
1737 
1738    /* Since the driver can map BOs internally as well and the mapped range
1739     * required by the user or the driver might not be the same, we always map
1740     * the entire BO and then add the requested offset to the start address
1741     * of the mapped region.
1742     */
1743    VkResult result = device_map(device, mem);
1744    if (result != VK_SUCCESS)
1745       return vk_error(device->instance, result);
1746 
1747    *ppData = ((uint8_t *) mem->bo->map) + offset;
1748    return VK_SUCCESS;
1749 }
1750 
1751 void
v3dv_UnmapMemory(VkDevice _device,VkDeviceMemory _memory)1752 v3dv_UnmapMemory(VkDevice _device,
1753                  VkDeviceMemory _memory)
1754 {
1755    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1756    V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1757 
1758    if (mem == NULL)
1759       return;
1760 
1761    device_unmap(device, mem);
1762 }
1763 
1764 VkResult
v3dv_FlushMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1765 v3dv_FlushMappedMemoryRanges(VkDevice _device,
1766                              uint32_t memoryRangeCount,
1767                              const VkMappedMemoryRange *pMemoryRanges)
1768 {
1769    return VK_SUCCESS;
1770 }
1771 
1772 VkResult
v3dv_InvalidateMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1773 v3dv_InvalidateMappedMemoryRanges(VkDevice _device,
1774                                   uint32_t memoryRangeCount,
1775                                   const VkMappedMemoryRange *pMemoryRanges)
1776 {
1777    return VK_SUCCESS;
1778 }
1779 
1780 void
v3dv_GetImageMemoryRequirements(VkDevice _device,VkImage _image,VkMemoryRequirements * pMemoryRequirements)1781 v3dv_GetImageMemoryRequirements(VkDevice _device,
1782                                 VkImage _image,
1783                                 VkMemoryRequirements *pMemoryRequirements)
1784 {
1785    V3DV_FROM_HANDLE(v3dv_image, image, _image);
1786 
1787    assert(image->size > 0);
1788 
1789    pMemoryRequirements->size = image->size;
1790    pMemoryRequirements->alignment = image->alignment;
1791    pMemoryRequirements->memoryTypeBits = 0x1;
1792 }
1793 
1794 VkResult
v3dv_BindImageMemory(VkDevice _device,VkImage _image,VkDeviceMemory _memory,VkDeviceSize memoryOffset)1795 v3dv_BindImageMemory(VkDevice _device,
1796                      VkImage _image,
1797                      VkDeviceMemory _memory,
1798                      VkDeviceSize memoryOffset)
1799 {
1800    V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1801    V3DV_FROM_HANDLE(v3dv_image, image, _image);
1802 
1803    /* Valid usage:
1804     *
1805     *   "memoryOffset must be an integer multiple of the alignment member of
1806     *    the VkMemoryRequirements structure returned from a call to
1807     *    vkGetImageMemoryRequirements with image"
1808     */
1809    assert(memoryOffset % image->alignment == 0);
1810    assert(memoryOffset < mem->bo->size);
1811 
1812    image->mem = mem;
1813    image->mem_offset = memoryOffset;
1814 
1815    return VK_SUCCESS;
1816 }
1817 
1818 void
v3dv_GetBufferMemoryRequirements(VkDevice _device,VkBuffer _buffer,VkMemoryRequirements * pMemoryRequirements)1819 v3dv_GetBufferMemoryRequirements(VkDevice _device,
1820                                  VkBuffer _buffer,
1821                                  VkMemoryRequirements* pMemoryRequirements)
1822 {
1823    V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1824 
1825    pMemoryRequirements->memoryTypeBits = 0x1;
1826    pMemoryRequirements->alignment = buffer->alignment;
1827    pMemoryRequirements->size =
1828       align64(buffer->size, pMemoryRequirements->alignment);
1829 }
1830 
1831 VkResult
v3dv_BindBufferMemory(VkDevice _device,VkBuffer _buffer,VkDeviceMemory _memory,VkDeviceSize memoryOffset)1832 v3dv_BindBufferMemory(VkDevice _device,
1833                       VkBuffer _buffer,
1834                       VkDeviceMemory _memory,
1835                       VkDeviceSize memoryOffset)
1836 {
1837    V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1838    V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1839 
1840    /* Valid usage:
1841     *
1842     *   "memoryOffset must be an integer multiple of the alignment member of
1843     *    the VkMemoryRequirements structure returned from a call to
1844     *    vkGetBufferMemoryRequirements with buffer"
1845     */
1846    assert(memoryOffset % buffer->alignment == 0);
1847    assert(memoryOffset < mem->bo->size);
1848 
1849    buffer->mem = mem;
1850    buffer->mem_offset = memoryOffset;
1851 
1852    return VK_SUCCESS;
1853 }
1854 
1855 VkResult
v3dv_CreateBuffer(VkDevice _device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)1856 v3dv_CreateBuffer(VkDevice  _device,
1857                   const VkBufferCreateInfo *pCreateInfo,
1858                   const VkAllocationCallbacks *pAllocator,
1859                   VkBuffer *pBuffer)
1860 {
1861    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1862    struct v3dv_buffer *buffer;
1863 
1864    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
1865    assert(pCreateInfo->usage != 0);
1866 
1867    /* We don't support any flags for now */
1868    assert(pCreateInfo->flags == 0);
1869 
1870    buffer = vk_alloc2(&device->alloc, pAllocator, sizeof(*buffer), 8,
1871                        VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1872    if (buffer == NULL)
1873       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1874 
1875    buffer->size = pCreateInfo->size;
1876    buffer->usage = pCreateInfo->usage;
1877    buffer->alignment = 256; /* nonCoherentAtomSize */
1878 
1879    /* Limit allocations to 32-bit */
1880    const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment);
1881    if (aligned_size > UINT32_MAX || aligned_size < buffer->size)
1882       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1883 
1884    *pBuffer = v3dv_buffer_to_handle(buffer);
1885 
1886    return VK_SUCCESS;
1887 }
1888 
1889 void
v3dv_DestroyBuffer(VkDevice _device,VkBuffer _buffer,const VkAllocationCallbacks * pAllocator)1890 v3dv_DestroyBuffer(VkDevice _device,
1891                    VkBuffer _buffer,
1892                    const VkAllocationCallbacks *pAllocator)
1893 {
1894    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1895    V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1896 
1897    if (!buffer)
1898       return;
1899 
1900    vk_free2(&device->alloc, pAllocator, buffer);
1901 }
1902 
1903 /**
1904  * This computes the maximum bpp used by any of the render targets used by
1905  * a particular subpass and checks if any of those render targets are
1906  * multisampled. If we don't have a subpass (when we are not inside a
1907  * render pass), then we assume that all framebuffer attachments are used.
1908  */
1909 void
v3dv_framebuffer_compute_internal_bpp_msaa(const struct v3dv_framebuffer * framebuffer,const struct v3dv_subpass * subpass,uint8_t * max_bpp,bool * msaa)1910 v3dv_framebuffer_compute_internal_bpp_msaa(
1911    const struct v3dv_framebuffer *framebuffer,
1912    const struct v3dv_subpass *subpass,
1913    uint8_t *max_bpp,
1914    bool *msaa)
1915 {
1916    STATIC_ASSERT(RENDER_TARGET_MAXIMUM_32BPP == 0);
1917    *max_bpp = RENDER_TARGET_MAXIMUM_32BPP;
1918    *msaa = false;
1919 
1920    if (subpass) {
1921       for (uint32_t i = 0; i < subpass->color_count; i++) {
1922          uint32_t att_idx = subpass->color_attachments[i].attachment;
1923          if (att_idx == VK_ATTACHMENT_UNUSED)
1924             continue;
1925 
1926          const struct v3dv_image_view *att = framebuffer->attachments[att_idx];
1927          assert(att);
1928 
1929          if (att->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1930             *max_bpp = MAX2(*max_bpp, att->internal_bpp);
1931 
1932          if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1933             *msaa = true;
1934       }
1935 
1936       if (!*msaa && subpass->ds_attachment.attachment != VK_ATTACHMENT_UNUSED) {
1937          const struct v3dv_image_view *att =
1938             framebuffer->attachments[subpass->ds_attachment.attachment];
1939          assert(att);
1940 
1941          if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1942             *msaa = true;
1943       }
1944 
1945       return;
1946    }
1947 
1948    assert(framebuffer->attachment_count <= 4);
1949    for (uint32_t i = 0; i < framebuffer->attachment_count; i++) {
1950       const struct v3dv_image_view *att = framebuffer->attachments[i];
1951       assert(att);
1952 
1953       if (att->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1954          *max_bpp = MAX2(*max_bpp, att->internal_bpp);
1955 
1956       if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1957          *msaa = true;
1958    }
1959 
1960    return;
1961 }
1962 
1963 VkResult
v3dv_CreateFramebuffer(VkDevice _device,const VkFramebufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFramebuffer * pFramebuffer)1964 v3dv_CreateFramebuffer(VkDevice _device,
1965                        const VkFramebufferCreateInfo *pCreateInfo,
1966                        const VkAllocationCallbacks *pAllocator,
1967                        VkFramebuffer *pFramebuffer)
1968 {
1969    V3DV_FROM_HANDLE(v3dv_device, device, _device);
1970    struct v3dv_framebuffer *framebuffer;
1971 
1972    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
1973 
1974    size_t size = sizeof(*framebuffer) +
1975                  sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount;
1976    framebuffer = vk_alloc2(&device->alloc, pAllocator, size, 8,
1977                            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1978    if (framebuffer == NULL)
1979       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1980 
1981    framebuffer->width = pCreateInfo->width;
1982    framebuffer->height = pCreateInfo->height;
1983    framebuffer->layers = pCreateInfo->layers;
1984    framebuffer->has_edge_padding = true;
1985 
1986    framebuffer->attachment_count = pCreateInfo->attachmentCount;
1987    framebuffer->color_attachment_count = 0;
1988    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
1989       framebuffer->attachments[i] =
1990          v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]);
1991       if (framebuffer->attachments[i]->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1992          framebuffer->color_attachment_count++;
1993    }
1994 
1995    *pFramebuffer = v3dv_framebuffer_to_handle(framebuffer);
1996 
1997    return VK_SUCCESS;
1998 }
1999 
2000 void
v3dv_DestroyFramebuffer(VkDevice _device,VkFramebuffer _fb,const VkAllocationCallbacks * pAllocator)2001 v3dv_DestroyFramebuffer(VkDevice _device,
2002                         VkFramebuffer _fb,
2003                         const VkAllocationCallbacks *pAllocator)
2004 {
2005    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2006    V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb);
2007 
2008    if (!fb)
2009       return;
2010 
2011    vk_free2(&device->alloc, pAllocator, fb);
2012 }
2013 
2014 VkResult
v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,VkExternalMemoryHandleTypeFlagBits handleType,int fd,VkMemoryFdPropertiesKHR * pMemoryFdProperties)2015 v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,
2016                               VkExternalMemoryHandleTypeFlagBits handleType,
2017                               int fd,
2018                               VkMemoryFdPropertiesKHR *pMemoryFdProperties)
2019 {
2020    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2021    struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
2022 
2023    switch (handleType) {
2024    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
2025       pMemoryFdProperties->memoryTypeBits =
2026          (1 << pdevice->memory.memoryTypeCount) - 1;
2027       return VK_SUCCESS;
2028    default:
2029       return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2030    }
2031 }
2032 
2033 VkResult
v3dv_GetMemoryFdKHR(VkDevice _device,const VkMemoryGetFdInfoKHR * pGetFdInfo,int * pFd)2034 v3dv_GetMemoryFdKHR(VkDevice _device,
2035                     const VkMemoryGetFdInfoKHR *pGetFdInfo,
2036                     int *pFd)
2037 {
2038    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2039    V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory);
2040 
2041    assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
2042    assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
2043           pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2044 
2045    int fd, ret;
2046    ret =
2047       drmPrimeHandleToFD(device->render_fd, mem->bo->handle, DRM_CLOEXEC, &fd);
2048    if (ret)
2049       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2050 
2051    *pFd = fd;
2052 
2053    return VK_SUCCESS;
2054 }
2055 
2056 VkResult
v3dv_CreateEvent(VkDevice _device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)2057 v3dv_CreateEvent(VkDevice _device,
2058                  const VkEventCreateInfo *pCreateInfo,
2059                  const VkAllocationCallbacks *pAllocator,
2060                  VkEvent *pEvent)
2061 {
2062    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2063    struct v3dv_event *event =
2064       vk_alloc2(&device->alloc, pAllocator, sizeof(*event), 8,
2065                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2066    if (!event)
2067       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2068 
2069    /* Events are created in the unsignaled state */
2070    event->state = false;
2071    *pEvent = v3dv_event_to_handle(event);
2072 
2073    return VK_SUCCESS;
2074 }
2075 
2076 void
v3dv_DestroyEvent(VkDevice _device,VkEvent _event,const VkAllocationCallbacks * pAllocator)2077 v3dv_DestroyEvent(VkDevice _device,
2078                   VkEvent _event,
2079                   const VkAllocationCallbacks *pAllocator)
2080 {
2081    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2082    V3DV_FROM_HANDLE(v3dv_event, event, _event);
2083 
2084    if (!event)
2085       return;
2086 
2087    vk_free2(&device->alloc, pAllocator, event);
2088 }
2089 
2090 VkResult
v3dv_GetEventStatus(VkDevice _device,VkEvent _event)2091 v3dv_GetEventStatus(VkDevice _device, VkEvent _event)
2092 {
2093    V3DV_FROM_HANDLE(v3dv_event, event, _event);
2094    return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET;
2095 }
2096 
2097 VkResult
v3dv_SetEvent(VkDevice _device,VkEvent _event)2098 v3dv_SetEvent(VkDevice _device, VkEvent _event)
2099 {
2100    V3DV_FROM_HANDLE(v3dv_event, event, _event);
2101    p_atomic_set(&event->state, 1);
2102    return VK_SUCCESS;
2103 }
2104 
2105 VkResult
v3dv_ResetEvent(VkDevice _device,VkEvent _event)2106 v3dv_ResetEvent(VkDevice _device, VkEvent _event)
2107 {
2108    V3DV_FROM_HANDLE(v3dv_event, event, _event);
2109    p_atomic_set(&event->state, 0);
2110    return VK_SUCCESS;
2111 }
2112 
2113 static const enum V3DX(Wrap_Mode) vk_to_v3d_wrap_mode[] = {
2114    [VK_SAMPLER_ADDRESS_MODE_REPEAT]          = V3D_WRAP_MODE_REPEAT,
2115    [VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT] = V3D_WRAP_MODE_MIRROR,
2116    [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE]   = V3D_WRAP_MODE_CLAMP,
2117    [VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE] = V3D_WRAP_MODE_MIRROR_ONCE,
2118    [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER] = V3D_WRAP_MODE_BORDER,
2119 };
2120 
2121 static const enum V3DX(Compare_Function)
2122 vk_to_v3d_compare_func[] = {
2123    [VK_COMPARE_OP_NEVER]                        = V3D_COMPARE_FUNC_NEVER,
2124    [VK_COMPARE_OP_LESS]                         = V3D_COMPARE_FUNC_LESS,
2125    [VK_COMPARE_OP_EQUAL]                        = V3D_COMPARE_FUNC_EQUAL,
2126    [VK_COMPARE_OP_LESS_OR_EQUAL]                = V3D_COMPARE_FUNC_LEQUAL,
2127    [VK_COMPARE_OP_GREATER]                      = V3D_COMPARE_FUNC_GREATER,
2128    [VK_COMPARE_OP_NOT_EQUAL]                    = V3D_COMPARE_FUNC_NOTEQUAL,
2129    [VK_COMPARE_OP_GREATER_OR_EQUAL]             = V3D_COMPARE_FUNC_GEQUAL,
2130    [VK_COMPARE_OP_ALWAYS]                       = V3D_COMPARE_FUNC_ALWAYS,
2131 };
2132 
2133 static void
pack_sampler_state(struct v3dv_sampler * sampler,const VkSamplerCreateInfo * pCreateInfo)2134 pack_sampler_state(struct v3dv_sampler *sampler,
2135                    const VkSamplerCreateInfo *pCreateInfo)
2136 {
2137    enum V3DX(Border_Color_Mode) border_color_mode;
2138 
2139    /* For now we only support the preset Vulkan border color modes. If we
2140     * want to implement VK_EXT_custom_border_color in the future we would have
2141     * to use V3D_BORDER_COLOR_FOLLOWS, and fill up border_color_word_[0/1/2/3]
2142     * SAMPLER_STATE.
2143     */
2144    switch (pCreateInfo->borderColor) {
2145    case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
2146    case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
2147       border_color_mode = V3D_BORDER_COLOR_0000;
2148       break;
2149    case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
2150    case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
2151       border_color_mode = V3D_BORDER_COLOR_0001;
2152       break;
2153    case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
2154    case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
2155       border_color_mode = V3D_BORDER_COLOR_1111;
2156       break;
2157    default:
2158       unreachable("Unknown border color");
2159       break;
2160    }
2161 
2162    /* For some texture formats, when clamping to transparent black border the
2163     * CTS expects alpha to be set to 1 instead of 0, but the border color mode
2164     * will take priority over the texture state swizzle, so the only way to
2165     * fix that is to apply a swizzle in the shader. Here we keep track of
2166     * whether we are activating that mode and we will decide if we need to
2167     * activate the texture swizzle lowering in the shader key at compile time
2168     * depending on the actual texture format.
2169     */
2170    if ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2171         pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2172         pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) &&
2173        border_color_mode == V3D_BORDER_COLOR_0000) {
2174       sampler->clamp_to_transparent_black_border = true;
2175    }
2176 
2177    v3dv_pack(sampler->sampler_state, SAMPLER_STATE, s) {
2178       if (pCreateInfo->anisotropyEnable) {
2179          s.anisotropy_enable = true;
2180          if (pCreateInfo->maxAnisotropy > 8)
2181             s.maximum_anisotropy = 3;
2182          else if (pCreateInfo->maxAnisotropy > 4)
2183             s.maximum_anisotropy = 2;
2184          else if (pCreateInfo->maxAnisotropy > 2)
2185             s.maximum_anisotropy = 1;
2186       }
2187 
2188       s.border_color_mode = border_color_mode;
2189 
2190       s.wrap_i_border = false; /* Also hardcoded on v3d */
2191       s.wrap_s = vk_to_v3d_wrap_mode[pCreateInfo->addressModeU];
2192       s.wrap_t = vk_to_v3d_wrap_mode[pCreateInfo->addressModeV];
2193       s.wrap_r = vk_to_v3d_wrap_mode[pCreateInfo->addressModeW];
2194       s.fixed_bias = pCreateInfo->mipLodBias;
2195       s.max_level_of_detail = MIN2(MAX2(0, pCreateInfo->maxLod), 15);
2196       s.min_level_of_detail = MIN2(MAX2(0, pCreateInfo->minLod), 15);
2197       s.srgb_disable = 0; /* Not even set by v3d */
2198       s.depth_compare_function =
2199          vk_to_v3d_compare_func[pCreateInfo->compareEnable ?
2200                                 pCreateInfo->compareOp : VK_COMPARE_OP_NEVER];
2201       s.mip_filter_nearest = pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST;
2202       s.min_filter_nearest = pCreateInfo->minFilter == VK_FILTER_NEAREST;
2203       s.mag_filter_nearest = pCreateInfo->magFilter == VK_FILTER_NEAREST;
2204    }
2205 }
2206 
2207 VkResult
v3dv_CreateSampler(VkDevice _device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler)2208 v3dv_CreateSampler(VkDevice _device,
2209                  const VkSamplerCreateInfo *pCreateInfo,
2210                  const VkAllocationCallbacks *pAllocator,
2211                  VkSampler *pSampler)
2212 {
2213    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2214    struct v3dv_sampler *sampler;
2215 
2216    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
2217 
2218    sampler = vk_zalloc2(&device->alloc, pAllocator, sizeof(*sampler), 8,
2219                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2220    if (!sampler)
2221       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2222 
2223    sampler->compare_enable = pCreateInfo->compareEnable;
2224    sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates;
2225    pack_sampler_state(sampler, pCreateInfo);
2226 
2227    *pSampler = v3dv_sampler_to_handle(sampler);
2228 
2229    return VK_SUCCESS;
2230 }
2231 
2232 void
v3dv_DestroySampler(VkDevice _device,VkSampler _sampler,const VkAllocationCallbacks * pAllocator)2233 v3dv_DestroySampler(VkDevice _device,
2234                   VkSampler _sampler,
2235                   const VkAllocationCallbacks *pAllocator)
2236 {
2237    V3DV_FROM_HANDLE(v3dv_device, device, _device);
2238    V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler);
2239 
2240    if (!sampler)
2241       return;
2242 
2243    vk_free2(&device->alloc, pAllocator, sampler);
2244 }
2245 
2246 void
v3dv_GetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory memory,VkDeviceSize * pCommittedMemoryInBytes)2247 v3dv_GetDeviceMemoryCommitment(VkDevice device,
2248                                VkDeviceMemory memory,
2249                                VkDeviceSize *pCommittedMemoryInBytes)
2250 {
2251    *pCommittedMemoryInBytes = 0;
2252 }
2253 
2254 void
v3dv_GetImageSparseMemoryRequirements(VkDevice device,VkImage image,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements * pSparseMemoryRequirements)2255 v3dv_GetImageSparseMemoryRequirements(
2256    VkDevice device,
2257    VkImage image,
2258    uint32_t *pSparseMemoryRequirementCount,
2259    VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
2260 {
2261    *pSparseMemoryRequirementCount = 0;
2262 }
2263 
2264 void
v3dv_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)2265 v3dv_GetImageSparseMemoryRequirements2(
2266    VkDevice device,
2267    const VkImageSparseMemoryRequirementsInfo2 *pInfo,
2268    uint32_t *pSparseMemoryRequirementCount,
2269    VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
2270 {
2271    *pSparseMemoryRequirementCount = 0;
2272 }
2273 
2274 /* vk_icd.h does not declare this function, so we declare it here to
2275  * suppress Wmissing-prototypes.
2276  */
2277 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
2278 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
2279 
2280 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t * pSupportedVersion)2281 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)
2282 {
2283    /* For the full details on loader interface versioning, see
2284     * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.
2285     * What follows is a condensed summary, to help you navigate the large and
2286     * confusing official doc.
2287     *
2288     *   - Loader interface v0 is incompatible with later versions. We don't
2289     *     support it.
2290     *
2291     *   - In loader interface v1:
2292     *       - The first ICD entrypoint called by the loader is
2293     *         vk_icdGetInstanceProcAddr(). The ICD must statically expose this
2294     *         entrypoint.
2295     *       - The ICD must statically expose no other Vulkan symbol unless it is
2296     *         linked with -Bsymbolic.
2297     *       - Each dispatchable Vulkan handle created by the ICD must be
2298     *         a pointer to a struct whose first member is VK_LOADER_DATA. The
2299     *         ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.
2300     *       - The loader implements vkCreate{PLATFORM}SurfaceKHR() and
2301     *         vkDestroySurfaceKHR(). The ICD must be capable of working with
2302     *         such loader-managed surfaces.
2303     *
2304     *    - Loader interface v2 differs from v1 in:
2305     *       - The first ICD entrypoint called by the loader is
2306     *         vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must
2307     *         statically expose this entrypoint.
2308     *
2309     *    - Loader interface v3 differs from v2 in:
2310     *        - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),
2311     *          vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,
2312     *          because the loader no longer does so.
2313     *
2314     *    - Loader interface v4 differs from v3 in:
2315     *        - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().
2316     */
2317    *pSupportedVersion = MIN2(*pSupportedVersion, 3u);
2318    return VK_SUCCESS;
2319 }
2320