17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2019 Raspberry Pi 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include <assert.h> 257ec681f3Smrg#include <fcntl.h> 267ec681f3Smrg#include <stdbool.h> 277ec681f3Smrg#include <string.h> 287ec681f3Smrg#include <sys/mman.h> 297ec681f3Smrg#include <sys/sysinfo.h> 307ec681f3Smrg#include <unistd.h> 317ec681f3Smrg#include <xf86drm.h> 327ec681f3Smrg 337ec681f3Smrg#ifdef MAJOR_IN_MKDEV 347ec681f3Smrg#include <sys/mkdev.h> 357ec681f3Smrg#endif 367ec681f3Smrg#ifdef MAJOR_IN_SYSMACROS 377ec681f3Smrg#include <sys/sysmacros.h> 387ec681f3Smrg#endif 397ec681f3Smrg 407ec681f3Smrg#include "v3dv_private.h" 417ec681f3Smrg 427ec681f3Smrg#include "common/v3d_debug.h" 437ec681f3Smrg 447ec681f3Smrg#include "compiler/v3d_compiler.h" 457ec681f3Smrg 467ec681f3Smrg#include "drm-uapi/v3d_drm.h" 477ec681f3Smrg#include "format/u_format.h" 487ec681f3Smrg#include "vk_util.h" 497ec681f3Smrg 507ec681f3Smrg#include "util/build_id.h" 517ec681f3Smrg#include "util/debug.h" 527ec681f3Smrg#include "util/u_cpu_detect.h" 537ec681f3Smrg 547ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR 557ec681f3Smrg#include <xcb/xcb.h> 567ec681f3Smrg#include <xcb/dri3.h> 577ec681f3Smrg#include <X11/Xlib-xcb.h> 587ec681f3Smrg#endif 597ec681f3Smrg 607ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR 617ec681f3Smrg#include <wayland-client.h> 627ec681f3Smrg#include "wayland-drm-client-protocol.h" 637ec681f3Smrg#endif 647ec681f3Smrg 657ec681f3Smrg#ifdef USE_V3D_SIMULATOR 667ec681f3Smrg#include "drm-uapi/i915_drm.h" 677ec681f3Smrg#endif 687ec681f3Smrg 697ec681f3Smrg#define V3DV_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION) 707ec681f3Smrg 717ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 727ec681f3Smrgv3dv_EnumerateInstanceVersion(uint32_t *pApiVersion) 737ec681f3Smrg{ 747ec681f3Smrg *pApiVersion = V3DV_API_VERSION; 757ec681f3Smrg return VK_SUCCESS; 767ec681f3Smrg} 777ec681f3Smrg 787ec681f3Smrg#if defined(VK_USE_PLATFORM_WIN32_KHR) || \ 797ec681f3Smrg defined(VK_USE_PLATFORM_WAYLAND_KHR) || \ 807ec681f3Smrg defined(VK_USE_PLATFORM_XCB_KHR) || \ 817ec681f3Smrg defined(VK_USE_PLATFORM_XLIB_KHR) || \ 827ec681f3Smrg defined(VK_USE_PLATFORM_DISPLAY_KHR) 837ec681f3Smrg#define V3DV_USE_WSI_PLATFORM 847ec681f3Smrg#endif 857ec681f3Smrg 867ec681f3Smrgstatic const struct vk_instance_extension_table instance_extensions = { 877ec681f3Smrg .KHR_device_group_creation = true, 887ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR 897ec681f3Smrg .KHR_display = true, 907ec681f3Smrg .KHR_get_display_properties2 = true, 917ec681f3Smrg#endif 927ec681f3Smrg .KHR_external_fence_capabilities = true, 937ec681f3Smrg .KHR_external_memory_capabilities = true, 947ec681f3Smrg .KHR_external_semaphore_capabilities = true, 957ec681f3Smrg .KHR_get_physical_device_properties2 = true, 967ec681f3Smrg#ifdef V3DV_USE_WSI_PLATFORM 977ec681f3Smrg .KHR_get_surface_capabilities2 = true, 987ec681f3Smrg .KHR_surface = true, 997ec681f3Smrg .KHR_surface_protected_capabilities = true, 1007ec681f3Smrg#endif 1017ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR 1027ec681f3Smrg .KHR_wayland_surface = true, 1037ec681f3Smrg#endif 1047ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR 1057ec681f3Smrg .KHR_xcb_surface = true, 1067ec681f3Smrg#endif 1077ec681f3Smrg#ifdef VK_USE_PLATFORM_XLIB_KHR 1087ec681f3Smrg .KHR_xlib_surface = true, 1097ec681f3Smrg#endif 1107ec681f3Smrg .EXT_debug_report = true, 1117ec681f3Smrg}; 1127ec681f3Smrg 1137ec681f3Smrgstatic void 1147ec681f3Smrgget_device_extensions(const struct v3dv_physical_device *device, 1157ec681f3Smrg struct vk_device_extension_table *ext) 1167ec681f3Smrg{ 1177ec681f3Smrg *ext = (struct vk_device_extension_table) { 1187ec681f3Smrg .KHR_bind_memory2 = true, 1197ec681f3Smrg .KHR_copy_commands2 = true, 1207ec681f3Smrg .KHR_dedicated_allocation = true, 1217ec681f3Smrg .KHR_device_group = true, 1227ec681f3Smrg .KHR_descriptor_update_template = true, 1237ec681f3Smrg .KHR_external_fence = true, 1247ec681f3Smrg .KHR_external_fence_fd = true, 1257ec681f3Smrg .KHR_external_memory = true, 1267ec681f3Smrg .KHR_external_memory_fd = true, 1277ec681f3Smrg .KHR_external_semaphore = true, 1287ec681f3Smrg .KHR_external_semaphore_fd = true, 1297ec681f3Smrg .KHR_get_memory_requirements2 = true, 1307ec681f3Smrg .KHR_image_format_list = true, 1317ec681f3Smrg .KHR_relaxed_block_layout = true, 1327ec681f3Smrg .KHR_maintenance1 = true, 1337ec681f3Smrg .KHR_maintenance2 = true, 1347ec681f3Smrg .KHR_maintenance3 = true, 1357ec681f3Smrg .KHR_multiview = true, 1367ec681f3Smrg .KHR_shader_non_semantic_info = true, 1377ec681f3Smrg .KHR_sampler_mirror_clamp_to_edge = true, 1387ec681f3Smrg .KHR_storage_buffer_storage_class = true, 1397ec681f3Smrg .KHR_uniform_buffer_standard_layout = true, 1407ec681f3Smrg#ifdef V3DV_USE_WSI_PLATFORM 1417ec681f3Smrg .KHR_swapchain = true, 1427ec681f3Smrg .KHR_incremental_present = true, 1437ec681f3Smrg#endif 1447ec681f3Smrg .KHR_variable_pointers = true, 1457ec681f3Smrg .EXT_color_write_enable = true, 1467ec681f3Smrg .EXT_custom_border_color = true, 1477ec681f3Smrg .EXT_external_memory_dma_buf = true, 1487ec681f3Smrg .EXT_index_type_uint8 = true, 1497ec681f3Smrg .EXT_physical_device_drm = true, 1507ec681f3Smrg .EXT_pipeline_creation_cache_control = true, 1517ec681f3Smrg .EXT_pipeline_creation_feedback = true, 1527ec681f3Smrg .EXT_private_data = true, 1537ec681f3Smrg .EXT_provoking_vertex = true, 1547ec681f3Smrg .EXT_vertex_attribute_divisor = true, 1557ec681f3Smrg }; 1567ec681f3Smrg} 1577ec681f3Smrg 1587ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 1597ec681f3Smrgv3dv_EnumerateInstanceExtensionProperties(const char *pLayerName, 1607ec681f3Smrg uint32_t *pPropertyCount, 1617ec681f3Smrg VkExtensionProperties *pProperties) 1627ec681f3Smrg{ 1637ec681f3Smrg /* We don't support any layers */ 1647ec681f3Smrg if (pLayerName) 1657ec681f3Smrg return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); 1667ec681f3Smrg 1677ec681f3Smrg return vk_enumerate_instance_extension_properties( 1687ec681f3Smrg &instance_extensions, pPropertyCount, pProperties); 1697ec681f3Smrg} 1707ec681f3Smrg 1717ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 1727ec681f3Smrgv3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, 1737ec681f3Smrg const VkAllocationCallbacks *pAllocator, 1747ec681f3Smrg VkInstance *pInstance) 1757ec681f3Smrg{ 1767ec681f3Smrg struct v3dv_instance *instance; 1777ec681f3Smrg VkResult result; 1787ec681f3Smrg 1797ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO); 1807ec681f3Smrg 1817ec681f3Smrg if (pAllocator == NULL) 1827ec681f3Smrg pAllocator = vk_default_allocator(); 1837ec681f3Smrg 1847ec681f3Smrg instance = vk_alloc(pAllocator, sizeof(*instance), 8, 1857ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1867ec681f3Smrg if (!instance) 1877ec681f3Smrg return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY); 1887ec681f3Smrg 1897ec681f3Smrg struct vk_instance_dispatch_table dispatch_table; 1907ec681f3Smrg vk_instance_dispatch_table_from_entrypoints( 1917ec681f3Smrg &dispatch_table, &v3dv_instance_entrypoints, true); 1927ec681f3Smrg vk_instance_dispatch_table_from_entrypoints( 1937ec681f3Smrg &dispatch_table, &wsi_instance_entrypoints, false); 1947ec681f3Smrg 1957ec681f3Smrg result = vk_instance_init(&instance->vk, 1967ec681f3Smrg &instance_extensions, 1977ec681f3Smrg &dispatch_table, 1987ec681f3Smrg pCreateInfo, pAllocator); 1997ec681f3Smrg 2007ec681f3Smrg if (result != VK_SUCCESS) { 2017ec681f3Smrg vk_free(pAllocator, instance); 2027ec681f3Smrg return vk_error(NULL, result); 2037ec681f3Smrg } 2047ec681f3Smrg 2057ec681f3Smrg v3d_process_debug_variable(); 2067ec681f3Smrg 2077ec681f3Smrg instance->physicalDeviceCount = -1; 2087ec681f3Smrg 2097ec681f3Smrg /* We start with the default values for the pipeline_cache envvars */ 2107ec681f3Smrg instance->pipeline_cache_enabled = true; 2117ec681f3Smrg instance->default_pipeline_cache_enabled = true; 2127ec681f3Smrg const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE"); 2137ec681f3Smrg if (pipeline_cache_str != NULL) { 2147ec681f3Smrg if (strncmp(pipeline_cache_str, "full", 4) == 0) { 2157ec681f3Smrg /* nothing to do, just to filter correct values */ 2167ec681f3Smrg } else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) { 2177ec681f3Smrg instance->default_pipeline_cache_enabled = false; 2187ec681f3Smrg } else if (strncmp(pipeline_cache_str, "off", 3) == 0) { 2197ec681f3Smrg instance->pipeline_cache_enabled = false; 2207ec681f3Smrg instance->default_pipeline_cache_enabled = false; 2217ec681f3Smrg } else { 2227ec681f3Smrg fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. " 2237ec681f3Smrg "Allowed values are: full, no-default-cache, off\n"); 2247ec681f3Smrg } 2257ec681f3Smrg } 2267ec681f3Smrg 2277ec681f3Smrg if (instance->pipeline_cache_enabled == false) { 2287ec681f3Smrg fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance " 2297ec681f3Smrg "can be affected negatively\n"); 2307ec681f3Smrg } else { 2317ec681f3Smrg if (instance->default_pipeline_cache_enabled == false) { 2327ec681f3Smrg fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. " 2337ec681f3Smrg "Performance can be affected negatively\n"); 2347ec681f3Smrg } 2357ec681f3Smrg } 2367ec681f3Smrg 2377ec681f3Smrg util_cpu_detect(); 2387ec681f3Smrg 2397ec681f3Smrg VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false)); 2407ec681f3Smrg 2417ec681f3Smrg *pInstance = v3dv_instance_to_handle(instance); 2427ec681f3Smrg 2437ec681f3Smrg return VK_SUCCESS; 2447ec681f3Smrg} 2457ec681f3Smrg 2467ec681f3Smrgstatic void 2477ec681f3Smrgv3dv_physical_device_free_disk_cache(struct v3dv_physical_device *device) 2487ec681f3Smrg{ 2497ec681f3Smrg#ifdef ENABLE_SHADER_CACHE 2507ec681f3Smrg if (device->disk_cache) 2517ec681f3Smrg disk_cache_destroy(device->disk_cache); 2527ec681f3Smrg#else 2537ec681f3Smrg assert(device->disk_cache == NULL); 2547ec681f3Smrg#endif 2557ec681f3Smrg} 2567ec681f3Smrg 2577ec681f3Smrgstatic void 2587ec681f3Smrgphysical_device_finish(struct v3dv_physical_device *device) 2597ec681f3Smrg{ 2607ec681f3Smrg v3dv_wsi_finish(device); 2617ec681f3Smrg v3dv_physical_device_free_disk_cache(device); 2627ec681f3Smrg v3d_compiler_free(device->compiler); 2637ec681f3Smrg 2647ec681f3Smrg close(device->render_fd); 2657ec681f3Smrg if (device->display_fd >= 0) 2667ec681f3Smrg close(device->display_fd); 2677ec681f3Smrg if (device->master_fd >= 0) 2687ec681f3Smrg close(device->master_fd); 2697ec681f3Smrg 2707ec681f3Smrg free(device->name); 2717ec681f3Smrg 2727ec681f3Smrg#if using_v3d_simulator 2737ec681f3Smrg v3d_simulator_destroy(device->sim_file); 2747ec681f3Smrg#endif 2757ec681f3Smrg 2767ec681f3Smrg vk_physical_device_finish(&device->vk); 2777ec681f3Smrg mtx_destroy(&device->mutex); 2787ec681f3Smrg} 2797ec681f3Smrg 2807ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 2817ec681f3Smrgv3dv_DestroyInstance(VkInstance _instance, 2827ec681f3Smrg const VkAllocationCallbacks *pAllocator) 2837ec681f3Smrg{ 2847ec681f3Smrg V3DV_FROM_HANDLE(v3dv_instance, instance, _instance); 2857ec681f3Smrg 2867ec681f3Smrg if (!instance) 2877ec681f3Smrg return; 2887ec681f3Smrg 2897ec681f3Smrg if (instance->physicalDeviceCount > 0) { 2907ec681f3Smrg /* We support at most one physical device. */ 2917ec681f3Smrg assert(instance->physicalDeviceCount == 1); 2927ec681f3Smrg physical_device_finish(&instance->physicalDevice); 2937ec681f3Smrg } 2947ec681f3Smrg 2957ec681f3Smrg VG(VALGRIND_DESTROY_MEMPOOL(instance)); 2967ec681f3Smrg 2977ec681f3Smrg vk_instance_finish(&instance->vk); 2987ec681f3Smrg vk_free(&instance->vk.alloc, instance); 2997ec681f3Smrg} 3007ec681f3Smrg 3017ec681f3Smrgstatic uint64_t 3027ec681f3Smrgcompute_heap_size() 3037ec681f3Smrg{ 3047ec681f3Smrg#if !using_v3d_simulator 3057ec681f3Smrg /* Query the total ram from the system */ 3067ec681f3Smrg struct sysinfo info; 3077ec681f3Smrg sysinfo(&info); 3087ec681f3Smrg 3097ec681f3Smrg uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit; 3107ec681f3Smrg#else 3117ec681f3Smrg uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size(); 3127ec681f3Smrg#endif 3137ec681f3Smrg 3147ec681f3Smrg /* We don't want to burn too much ram with the GPU. If the user has 4GiB 3157ec681f3Smrg * or less, we use at most half. If they have more than 4GiB, we use 3/4. 3167ec681f3Smrg */ 3177ec681f3Smrg uint64_t available_ram; 3187ec681f3Smrg if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull) 3197ec681f3Smrg available_ram = total_ram / 2; 3207ec681f3Smrg else 3217ec681f3Smrg available_ram = total_ram * 3 / 4; 3227ec681f3Smrg 3237ec681f3Smrg return available_ram; 3247ec681f3Smrg} 3257ec681f3Smrg 3267ec681f3Smrg#if !using_v3d_simulator 3277ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR 3287ec681f3Smrgstatic int 3297ec681f3Smrgcreate_display_fd_xcb(VkIcdSurfaceBase *surface) 3307ec681f3Smrg{ 3317ec681f3Smrg int fd = -1; 3327ec681f3Smrg 3337ec681f3Smrg xcb_connection_t *conn; 3347ec681f3Smrg xcb_dri3_open_reply_t *reply = NULL; 3357ec681f3Smrg if (surface) { 3367ec681f3Smrg if (surface->platform == VK_ICD_WSI_PLATFORM_XLIB) 3377ec681f3Smrg conn = XGetXCBConnection(((VkIcdSurfaceXlib *)surface)->dpy); 3387ec681f3Smrg else 3397ec681f3Smrg conn = ((VkIcdSurfaceXcb *)surface)->connection; 3407ec681f3Smrg } else { 3417ec681f3Smrg conn = xcb_connect(NULL, NULL); 3427ec681f3Smrg } 3437ec681f3Smrg 3447ec681f3Smrg if (xcb_connection_has_error(conn)) 3457ec681f3Smrg goto finish; 3467ec681f3Smrg 3477ec681f3Smrg const xcb_setup_t *setup = xcb_get_setup(conn); 3487ec681f3Smrg xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 3497ec681f3Smrg xcb_screen_t *screen = iter.data; 3507ec681f3Smrg 3517ec681f3Smrg xcb_dri3_open_cookie_t cookie; 3527ec681f3Smrg cookie = xcb_dri3_open(conn, screen->root, None); 3537ec681f3Smrg reply = xcb_dri3_open_reply(conn, cookie, NULL); 3547ec681f3Smrg if (!reply) 3557ec681f3Smrg goto finish; 3567ec681f3Smrg 3577ec681f3Smrg if (reply->nfd != 1) 3587ec681f3Smrg goto finish; 3597ec681f3Smrg 3607ec681f3Smrg fd = xcb_dri3_open_reply_fds(conn, reply)[0]; 3617ec681f3Smrg fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 3627ec681f3Smrg 3637ec681f3Smrgfinish: 3647ec681f3Smrg if (!surface) 3657ec681f3Smrg xcb_disconnect(conn); 3667ec681f3Smrg if (reply) 3677ec681f3Smrg free(reply); 3687ec681f3Smrg 3697ec681f3Smrg return fd; 3707ec681f3Smrg} 3717ec681f3Smrg#endif 3727ec681f3Smrg 3737ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR 3747ec681f3Smrgstruct v3dv_wayland_info { 3757ec681f3Smrg struct wl_drm *wl_drm; 3767ec681f3Smrg int fd; 3777ec681f3Smrg bool is_set; 3787ec681f3Smrg bool authenticated; 3797ec681f3Smrg}; 3807ec681f3Smrg 3817ec681f3Smrgstatic void 3827ec681f3Smrgv3dv_drm_handle_device(void *data, struct wl_drm *drm, const char *device) 3837ec681f3Smrg{ 3847ec681f3Smrg struct v3dv_wayland_info *info = data; 3857ec681f3Smrg info->fd = open(device, O_RDWR | O_CLOEXEC); 3867ec681f3Smrg info->is_set = info->fd != -1; 3877ec681f3Smrg if (!info->is_set) { 3887ec681f3Smrg fprintf(stderr, "v3dv_drm_handle_device: could not open %s (%s)\n", 3897ec681f3Smrg device, strerror(errno)); 3907ec681f3Smrg return; 3917ec681f3Smrg } 3927ec681f3Smrg 3937ec681f3Smrg drm_magic_t magic; 3947ec681f3Smrg if (drmGetMagic(info->fd, &magic)) { 3957ec681f3Smrg fprintf(stderr, "v3dv_drm_handle_device: drmGetMagic failed\n"); 3967ec681f3Smrg close(info->fd); 3977ec681f3Smrg info->fd = -1; 3987ec681f3Smrg info->is_set = false; 3997ec681f3Smrg return; 4007ec681f3Smrg } 4017ec681f3Smrg wl_drm_authenticate(info->wl_drm, magic); 4027ec681f3Smrg} 4037ec681f3Smrg 4047ec681f3Smrgstatic void 4057ec681f3Smrgv3dv_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 4067ec681f3Smrg{ 4077ec681f3Smrg} 4087ec681f3Smrg 4097ec681f3Smrgstatic void 4107ec681f3Smrgv3dv_drm_handle_authenticated(void *data, struct wl_drm *drm) 4117ec681f3Smrg{ 4127ec681f3Smrg struct v3dv_wayland_info *info = data; 4137ec681f3Smrg info->authenticated = true; 4147ec681f3Smrg} 4157ec681f3Smrg 4167ec681f3Smrgstatic void 4177ec681f3Smrgv3dv_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) 4187ec681f3Smrg{ 4197ec681f3Smrg} 4207ec681f3Smrg 4217ec681f3Smrgstruct wl_drm_listener v3dv_drm_listener = { 4227ec681f3Smrg .device = v3dv_drm_handle_device, 4237ec681f3Smrg .format = v3dv_drm_handle_format, 4247ec681f3Smrg .authenticated = v3dv_drm_handle_authenticated, 4257ec681f3Smrg .capabilities = v3dv_drm_handle_capabilities 4267ec681f3Smrg}; 4277ec681f3Smrg 4287ec681f3Smrgstatic void 4297ec681f3Smrgv3dv_registry_global(void *data, 4307ec681f3Smrg struct wl_registry *registry, 4317ec681f3Smrg uint32_t name, 4327ec681f3Smrg const char *interface, 4337ec681f3Smrg uint32_t version) 4347ec681f3Smrg{ 4357ec681f3Smrg struct v3dv_wayland_info *info = data; 4367ec681f3Smrg if (strcmp(interface, "wl_drm") == 0) { 4377ec681f3Smrg info->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface, 4387ec681f3Smrg MIN2(version, 2)); 4397ec681f3Smrg wl_drm_add_listener(info->wl_drm, &v3dv_drm_listener, data); 4407ec681f3Smrg }; 4417ec681f3Smrg} 4427ec681f3Smrg 4437ec681f3Smrgstatic void 4447ec681f3Smrgv3dv_registry_global_remove_cb(void *data, 4457ec681f3Smrg struct wl_registry *registry, 4467ec681f3Smrg uint32_t name) 4477ec681f3Smrg{ 4487ec681f3Smrg} 4497ec681f3Smrg 4507ec681f3Smrgstatic int 4517ec681f3Smrgcreate_display_fd_wayland(VkIcdSurfaceBase *surface) 4527ec681f3Smrg{ 4537ec681f3Smrg struct wl_display *display; 4547ec681f3Smrg struct wl_registry *registry = NULL; 4557ec681f3Smrg 4567ec681f3Smrg struct v3dv_wayland_info info = { 4577ec681f3Smrg .wl_drm = NULL, 4587ec681f3Smrg .fd = -1, 4597ec681f3Smrg .is_set = false, 4607ec681f3Smrg .authenticated = false 4617ec681f3Smrg }; 4627ec681f3Smrg 4637ec681f3Smrg if (surface) 4647ec681f3Smrg display = ((VkIcdSurfaceWayland *) surface)->display; 4657ec681f3Smrg else 4667ec681f3Smrg display = wl_display_connect(NULL); 4677ec681f3Smrg 4687ec681f3Smrg if (!display) 4697ec681f3Smrg return -1; 4707ec681f3Smrg 4717ec681f3Smrg registry = wl_display_get_registry(display); 4727ec681f3Smrg if (!registry) { 4737ec681f3Smrg if (!surface) 4747ec681f3Smrg wl_display_disconnect(display); 4757ec681f3Smrg return -1; 4767ec681f3Smrg } 4777ec681f3Smrg 4787ec681f3Smrg static const struct wl_registry_listener registry_listener = { 4797ec681f3Smrg v3dv_registry_global, 4807ec681f3Smrg v3dv_registry_global_remove_cb 4817ec681f3Smrg }; 4827ec681f3Smrg wl_registry_add_listener(registry, ®istry_listener, &info); 4837ec681f3Smrg 4847ec681f3Smrg wl_display_roundtrip(display); /* For the registry advertisement */ 4857ec681f3Smrg wl_display_roundtrip(display); /* For the DRM device event */ 4867ec681f3Smrg wl_display_roundtrip(display); /* For the authentication event */ 4877ec681f3Smrg 4887ec681f3Smrg wl_drm_destroy(info.wl_drm); 4897ec681f3Smrg wl_registry_destroy(registry); 4907ec681f3Smrg 4917ec681f3Smrg if (!surface) 4927ec681f3Smrg wl_display_disconnect(display); 4937ec681f3Smrg 4947ec681f3Smrg if (!info.is_set) 4957ec681f3Smrg return -1; 4967ec681f3Smrg 4977ec681f3Smrg if (!info.authenticated) 4987ec681f3Smrg return -1; 4997ec681f3Smrg 5007ec681f3Smrg return info.fd; 5017ec681f3Smrg} 5027ec681f3Smrg#endif 5037ec681f3Smrg 5047ec681f3Smrg/* Acquire an authenticated display fd without a surface reference. This is the 5057ec681f3Smrg * case where the application is making WSI allocations outside the Vulkan 5067ec681f3Smrg * swapchain context (only Zink, for now). Since we lack information about the 5077ec681f3Smrg * underlying surface we just try our best to figure out the correct display 5087ec681f3Smrg * and platform to use. It should work in most cases. 5097ec681f3Smrg */ 5107ec681f3Smrgstatic void 5117ec681f3Smrgacquire_display_device_no_surface(struct v3dv_instance *instance, 5127ec681f3Smrg struct v3dv_physical_device *pdevice) 5137ec681f3Smrg{ 5147ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR 5157ec681f3Smrg pdevice->display_fd = create_display_fd_wayland(NULL); 5167ec681f3Smrg#endif 5177ec681f3Smrg 5187ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR 5197ec681f3Smrg if (pdevice->display_fd == -1) 5207ec681f3Smrg pdevice->display_fd = create_display_fd_xcb(NULL); 5217ec681f3Smrg#endif 5227ec681f3Smrg 5237ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR 5247ec681f3Smrg if (pdevice->display_fd == - 1 && pdevice->master_fd >= 0) 5257ec681f3Smrg pdevice->display_fd = dup(pdevice->master_fd); 5267ec681f3Smrg#endif 5277ec681f3Smrg} 5287ec681f3Smrg 5297ec681f3Smrg/* Acquire an authenticated display fd from the surface. This is the regular 5307ec681f3Smrg * case where the application is using swapchains to create WSI allocations. 5317ec681f3Smrg * In this case we use the surface information to figure out the correct 5327ec681f3Smrg * display and platform combination. 5337ec681f3Smrg */ 5347ec681f3Smrgstatic void 5357ec681f3Smrgacquire_display_device_surface(struct v3dv_instance *instance, 5367ec681f3Smrg struct v3dv_physical_device *pdevice, 5377ec681f3Smrg VkIcdSurfaceBase *surface) 5387ec681f3Smrg{ 5397ec681f3Smrg /* Mesa will set both of VK_USE_PLATFORM_{XCB,XLIB} when building with 5407ec681f3Smrg * platform X11, so only check for XCB and rely on XCB to get an 5417ec681f3Smrg * authenticated device also for Xlib. 5427ec681f3Smrg */ 5437ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR 5447ec681f3Smrg if (surface->platform == VK_ICD_WSI_PLATFORM_XCB || 5457ec681f3Smrg surface->platform == VK_ICD_WSI_PLATFORM_XLIB) { 5467ec681f3Smrg pdevice->display_fd = create_display_fd_xcb(surface); 5477ec681f3Smrg } 5487ec681f3Smrg#endif 5497ec681f3Smrg 5507ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR 5517ec681f3Smrg if (surface->platform == VK_ICD_WSI_PLATFORM_WAYLAND) 5527ec681f3Smrg pdevice->display_fd = create_display_fd_wayland(surface); 5537ec681f3Smrg#endif 5547ec681f3Smrg 5557ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR 5567ec681f3Smrg if (surface->platform == VK_ICD_WSI_PLATFORM_DISPLAY && 5577ec681f3Smrg pdevice->master_fd >= 0) { 5587ec681f3Smrg pdevice->display_fd = dup(pdevice->master_fd); 5597ec681f3Smrg } 5607ec681f3Smrg#endif 5617ec681f3Smrg} 5627ec681f3Smrg#endif /* !using_v3d_simulator */ 5637ec681f3Smrg 5647ec681f3Smrg/* Attempts to get an authenticated display fd from the display server that 5657ec681f3Smrg * we can use to allocate BOs for presentable images. 5667ec681f3Smrg */ 5677ec681f3SmrgVkResult 5687ec681f3Smrgv3dv_physical_device_acquire_display(struct v3dv_instance *instance, 5697ec681f3Smrg struct v3dv_physical_device *pdevice, 5707ec681f3Smrg VkIcdSurfaceBase *surface) 5717ec681f3Smrg{ 5727ec681f3Smrg VkResult result = VK_SUCCESS; 5737ec681f3Smrg mtx_lock(&pdevice->mutex); 5747ec681f3Smrg 5757ec681f3Smrg if (pdevice->display_fd != -1) 5767ec681f3Smrg goto done; 5777ec681f3Smrg 5787ec681f3Smrg /* When running on the simulator we do everything on a single render node so 5797ec681f3Smrg * we don't need to get an authenticated display fd from the display server. 5807ec681f3Smrg */ 5817ec681f3Smrg#if !using_v3d_simulator 5827ec681f3Smrg if (surface) 5837ec681f3Smrg acquire_display_device_surface(instance, pdevice, surface); 5847ec681f3Smrg else 5857ec681f3Smrg acquire_display_device_no_surface(instance, pdevice); 5867ec681f3Smrg 5877ec681f3Smrg if (pdevice->display_fd == -1) 5887ec681f3Smrg result = VK_ERROR_INITIALIZATION_FAILED; 5897ec681f3Smrg#endif 5907ec681f3Smrg 5917ec681f3Smrgdone: 5927ec681f3Smrg mtx_unlock(&pdevice->mutex); 5937ec681f3Smrg return result; 5947ec681f3Smrg} 5957ec681f3Smrg 5967ec681f3Smrgstatic bool 5977ec681f3Smrgv3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature) 5987ec681f3Smrg{ 5997ec681f3Smrg struct drm_v3d_get_param p = { 6007ec681f3Smrg .param = feature, 6017ec681f3Smrg }; 6027ec681f3Smrg if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0) 6037ec681f3Smrg return false; 6047ec681f3Smrg return p.value; 6057ec681f3Smrg} 6067ec681f3Smrg 6077ec681f3Smrgstatic bool 6087ec681f3Smrgdevice_has_expected_features(struct v3dv_physical_device *device) 6097ec681f3Smrg{ 6107ec681f3Smrg return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) && 6117ec681f3Smrg v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) && 6127ec681f3Smrg v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH); 6137ec681f3Smrg} 6147ec681f3Smrg 6157ec681f3Smrg 6167ec681f3Smrgstatic VkResult 6177ec681f3Smrginit_uuids(struct v3dv_physical_device *device) 6187ec681f3Smrg{ 6197ec681f3Smrg const struct build_id_note *note = 6207ec681f3Smrg build_id_find_nhdr_for_addr(init_uuids); 6217ec681f3Smrg if (!note) { 6227ec681f3Smrg return vk_errorf(device->vk.instance, 6237ec681f3Smrg VK_ERROR_INITIALIZATION_FAILED, 6247ec681f3Smrg "Failed to find build-id"); 6257ec681f3Smrg } 6267ec681f3Smrg 6277ec681f3Smrg unsigned build_id_len = build_id_length(note); 6287ec681f3Smrg if (build_id_len < 20) { 6297ec681f3Smrg return vk_errorf(device->vk.instance, 6307ec681f3Smrg VK_ERROR_INITIALIZATION_FAILED, 6317ec681f3Smrg "build-id too short. It needs to be a SHA"); 6327ec681f3Smrg } 6337ec681f3Smrg 6347ec681f3Smrg memcpy(device->driver_build_sha1, build_id_data(note), 20); 6357ec681f3Smrg 6367ec681f3Smrg uint32_t vendor_id = v3dv_physical_device_vendor_id(device); 6377ec681f3Smrg uint32_t device_id = v3dv_physical_device_device_id(device); 6387ec681f3Smrg 6397ec681f3Smrg struct mesa_sha1 sha1_ctx; 6407ec681f3Smrg uint8_t sha1[20]; 6417ec681f3Smrg STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1)); 6427ec681f3Smrg 6437ec681f3Smrg /* The pipeline cache UUID is used for determining when a pipeline cache is 6447ec681f3Smrg * invalid. It needs both a driver build and the PCI ID of the device. 6457ec681f3Smrg */ 6467ec681f3Smrg _mesa_sha1_init(&sha1_ctx); 6477ec681f3Smrg _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len); 6487ec681f3Smrg _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id)); 6497ec681f3Smrg _mesa_sha1_final(&sha1_ctx, sha1); 6507ec681f3Smrg memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE); 6517ec681f3Smrg 6527ec681f3Smrg /* The driver UUID is used for determining sharability of images and memory 6537ec681f3Smrg * between two Vulkan instances in separate processes. People who want to 6547ec681f3Smrg * share memory need to also check the device UUID (below) so all this 6557ec681f3Smrg * needs to be is the build-id. 6567ec681f3Smrg */ 6577ec681f3Smrg memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE); 6587ec681f3Smrg 6597ec681f3Smrg /* The device UUID uniquely identifies the given device within the machine. 6607ec681f3Smrg * Since we never have more than one device, this doesn't need to be a real 6617ec681f3Smrg * UUID. 6627ec681f3Smrg */ 6637ec681f3Smrg _mesa_sha1_init(&sha1_ctx); 6647ec681f3Smrg _mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id)); 6657ec681f3Smrg _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id)); 6667ec681f3Smrg _mesa_sha1_final(&sha1_ctx, sha1); 6677ec681f3Smrg memcpy(device->device_uuid, sha1, VK_UUID_SIZE); 6687ec681f3Smrg 6697ec681f3Smrg return VK_SUCCESS; 6707ec681f3Smrg} 6717ec681f3Smrg 6727ec681f3Smrgstatic void 6737ec681f3Smrgv3dv_physical_device_init_disk_cache(struct v3dv_physical_device *device) 6747ec681f3Smrg{ 6757ec681f3Smrg#ifdef ENABLE_SHADER_CACHE 6767ec681f3Smrg char timestamp[41]; 6777ec681f3Smrg _mesa_sha1_format(timestamp, device->driver_build_sha1); 6787ec681f3Smrg 6797ec681f3Smrg assert(device->name); 6807ec681f3Smrg device->disk_cache = disk_cache_create(device->name, timestamp, 0); 6817ec681f3Smrg#else 6827ec681f3Smrg device->disk_cache = NULL; 6837ec681f3Smrg#endif 6847ec681f3Smrg} 6857ec681f3Smrg 6867ec681f3Smrgstatic VkResult 6877ec681f3Smrgphysical_device_init(struct v3dv_physical_device *device, 6887ec681f3Smrg struct v3dv_instance *instance, 6897ec681f3Smrg drmDevicePtr drm_render_device, 6907ec681f3Smrg drmDevicePtr drm_primary_device) 6917ec681f3Smrg{ 6927ec681f3Smrg VkResult result = VK_SUCCESS; 6937ec681f3Smrg int32_t master_fd = -1; 6947ec681f3Smrg int32_t render_fd = -1; 6957ec681f3Smrg 6967ec681f3Smrg struct vk_physical_device_dispatch_table dispatch_table; 6977ec681f3Smrg vk_physical_device_dispatch_table_from_entrypoints 6987ec681f3Smrg (&dispatch_table, &v3dv_physical_device_entrypoints, true); 6997ec681f3Smrg vk_physical_device_dispatch_table_from_entrypoints( 7007ec681f3Smrg &dispatch_table, &wsi_physical_device_entrypoints, false); 7017ec681f3Smrg 7027ec681f3Smrg result = vk_physical_device_init(&device->vk, &instance->vk, NULL, 7037ec681f3Smrg &dispatch_table); 7047ec681f3Smrg 7057ec681f3Smrg if (result != VK_SUCCESS) 7067ec681f3Smrg goto fail; 7077ec681f3Smrg 7087ec681f3Smrg assert(drm_render_device); 7097ec681f3Smrg const char *path = drm_render_device->nodes[DRM_NODE_RENDER]; 7107ec681f3Smrg render_fd = open(path, O_RDWR | O_CLOEXEC); 7117ec681f3Smrg if (render_fd < 0) { 7127ec681f3Smrg fprintf(stderr, "Opening %s failed: %s\n", path, strerror(errno)); 7137ec681f3Smrg result = VK_ERROR_INCOMPATIBLE_DRIVER; 7147ec681f3Smrg goto fail; 7157ec681f3Smrg } 7167ec681f3Smrg 7177ec681f3Smrg /* If we are running on VK_KHR_display we need to acquire the master 7187ec681f3Smrg * display device now for the v3dv_wsi_init() call below. For anything else 7197ec681f3Smrg * we postpone that until a swapchain is created. 7207ec681f3Smrg */ 7217ec681f3Smrg 7227ec681f3Smrg const char *primary_path; 7237ec681f3Smrg#if !using_v3d_simulator 7247ec681f3Smrg if (drm_primary_device) 7257ec681f3Smrg primary_path = drm_primary_device->nodes[DRM_NODE_PRIMARY]; 7267ec681f3Smrg else 7277ec681f3Smrg primary_path = NULL; 7287ec681f3Smrg#else 7297ec681f3Smrg primary_path = drm_render_device->nodes[DRM_NODE_PRIMARY]; 7307ec681f3Smrg#endif 7317ec681f3Smrg 7327ec681f3Smrg struct stat primary_stat = {0}, render_stat = {0}; 7337ec681f3Smrg 7347ec681f3Smrg device->has_primary = primary_path; 7357ec681f3Smrg if (device->has_primary) { 7367ec681f3Smrg if (stat(primary_path, &primary_stat) != 0) { 7377ec681f3Smrg result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 7387ec681f3Smrg "failed to stat DRM primary node %s", 7397ec681f3Smrg primary_path); 7407ec681f3Smrg goto fail; 7417ec681f3Smrg } 7427ec681f3Smrg 7437ec681f3Smrg device->primary_devid = primary_stat.st_rdev; 7447ec681f3Smrg } 7457ec681f3Smrg 7467ec681f3Smrg if (fstat(render_fd, &render_stat) != 0) { 7477ec681f3Smrg result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 7487ec681f3Smrg "failed to stat DRM render node %s", 7497ec681f3Smrg path); 7507ec681f3Smrg goto fail; 7517ec681f3Smrg } 7527ec681f3Smrg device->has_render = true; 7537ec681f3Smrg device->render_devid = render_stat.st_rdev; 7547ec681f3Smrg 7557ec681f3Smrg if (instance->vk.enabled_extensions.KHR_display) { 7567ec681f3Smrg#if !using_v3d_simulator 7577ec681f3Smrg /* Open the primary node on the vc4 display device */ 7587ec681f3Smrg assert(drm_primary_device); 7597ec681f3Smrg master_fd = open(primary_path, O_RDWR | O_CLOEXEC); 7607ec681f3Smrg#else 7617ec681f3Smrg /* There is only one device with primary and render nodes. 7627ec681f3Smrg * Open its primary node. 7637ec681f3Smrg */ 7647ec681f3Smrg master_fd = open(primary_path, O_RDWR | O_CLOEXEC); 7657ec681f3Smrg#endif 7667ec681f3Smrg } 7677ec681f3Smrg 7687ec681f3Smrg#if using_v3d_simulator 7697ec681f3Smrg device->sim_file = v3d_simulator_init(render_fd); 7707ec681f3Smrg#endif 7717ec681f3Smrg 7727ec681f3Smrg device->render_fd = render_fd; /* The v3d render node */ 7737ec681f3Smrg device->display_fd = -1; /* Authenticated vc4 primary node */ 7747ec681f3Smrg device->master_fd = master_fd; /* Master vc4 primary node */ 7757ec681f3Smrg 7767ec681f3Smrg if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) { 7777ec681f3Smrg result = VK_ERROR_INCOMPATIBLE_DRIVER; 7787ec681f3Smrg goto fail; 7797ec681f3Smrg } 7807ec681f3Smrg 7817ec681f3Smrg if (device->devinfo.ver < 42) { 7827ec681f3Smrg result = VK_ERROR_INCOMPATIBLE_DRIVER; 7837ec681f3Smrg goto fail; 7847ec681f3Smrg } 7857ec681f3Smrg 7867ec681f3Smrg if (!device_has_expected_features(device)) { 7877ec681f3Smrg result = VK_ERROR_INCOMPATIBLE_DRIVER; 7887ec681f3Smrg goto fail; 7897ec681f3Smrg } 7907ec681f3Smrg 7917ec681f3Smrg result = init_uuids(device); 7927ec681f3Smrg if (result != VK_SUCCESS) 7937ec681f3Smrg goto fail; 7947ec681f3Smrg 7957ec681f3Smrg device->compiler = v3d_compiler_init(&device->devinfo); 7967ec681f3Smrg device->next_program_id = 0; 7977ec681f3Smrg 7987ec681f3Smrg ASSERTED int len = 7997ec681f3Smrg asprintf(&device->name, "V3D %d.%d", 8007ec681f3Smrg device->devinfo.ver / 10, device->devinfo.ver % 10); 8017ec681f3Smrg assert(len != -1); 8027ec681f3Smrg 8037ec681f3Smrg v3dv_physical_device_init_disk_cache(device); 8047ec681f3Smrg 8057ec681f3Smrg /* Setup available memory heaps and types */ 8067ec681f3Smrg VkPhysicalDeviceMemoryProperties *mem = &device->memory; 8077ec681f3Smrg mem->memoryHeapCount = 1; 8087ec681f3Smrg mem->memoryHeaps[0].size = compute_heap_size(); 8097ec681f3Smrg mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; 8107ec681f3Smrg 8117ec681f3Smrg /* This is the only combination required by the spec */ 8127ec681f3Smrg mem->memoryTypeCount = 1; 8137ec681f3Smrg mem->memoryTypes[0].propertyFlags = 8147ec681f3Smrg VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | 8157ec681f3Smrg VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 8167ec681f3Smrg VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 8177ec681f3Smrg mem->memoryTypes[0].heapIndex = 0; 8187ec681f3Smrg 8197ec681f3Smrg device->options.merge_jobs = getenv("V3DV_NO_MERGE_JOBS") == NULL; 8207ec681f3Smrg 8217ec681f3Smrg result = v3dv_wsi_init(device); 8227ec681f3Smrg if (result != VK_SUCCESS) { 8237ec681f3Smrg vk_error(instance, result); 8247ec681f3Smrg goto fail; 8257ec681f3Smrg } 8267ec681f3Smrg 8277ec681f3Smrg get_device_extensions(device, &device->vk.supported_extensions); 8287ec681f3Smrg 8297ec681f3Smrg pthread_mutex_init(&device->mutex, NULL); 8307ec681f3Smrg 8317ec681f3Smrg return VK_SUCCESS; 8327ec681f3Smrg 8337ec681f3Smrgfail: 8347ec681f3Smrg vk_physical_device_finish(&device->vk); 8357ec681f3Smrg 8367ec681f3Smrg if (render_fd >= 0) 8377ec681f3Smrg close(render_fd); 8387ec681f3Smrg if (master_fd >= 0) 8397ec681f3Smrg close(master_fd); 8407ec681f3Smrg 8417ec681f3Smrg return result; 8427ec681f3Smrg} 8437ec681f3Smrg 8447ec681f3Smrgstatic VkResult 8457ec681f3Smrgenumerate_devices(struct v3dv_instance *instance) 8467ec681f3Smrg{ 8477ec681f3Smrg /* TODO: Check for more devices? */ 8487ec681f3Smrg drmDevicePtr devices[8]; 8497ec681f3Smrg VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER; 8507ec681f3Smrg int max_devices; 8517ec681f3Smrg 8527ec681f3Smrg instance->physicalDeviceCount = 0; 8537ec681f3Smrg 8547ec681f3Smrg max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 8557ec681f3Smrg if (max_devices < 1) 8567ec681f3Smrg return VK_ERROR_INCOMPATIBLE_DRIVER; 8577ec681f3Smrg 8587ec681f3Smrg#if !using_v3d_simulator 8597ec681f3Smrg int32_t v3d_idx = -1; 8607ec681f3Smrg int32_t vc4_idx = -1; 8617ec681f3Smrg#endif 8627ec681f3Smrg for (unsigned i = 0; i < (unsigned)max_devices; i++) { 8637ec681f3Smrg#if using_v3d_simulator 8647ec681f3Smrg /* In the simulator, we look for an Intel render node */ 8657ec681f3Smrg const int required_nodes = (1 << DRM_NODE_RENDER) | (1 << DRM_NODE_PRIMARY); 8667ec681f3Smrg if ((devices[i]->available_nodes & required_nodes) == required_nodes && 8677ec681f3Smrg devices[i]->bustype == DRM_BUS_PCI && 8687ec681f3Smrg devices[i]->deviceinfo.pci->vendor_id == 0x8086) { 8697ec681f3Smrg result = physical_device_init(&instance->physicalDevice, instance, 8707ec681f3Smrg devices[i], NULL); 8717ec681f3Smrg if (result != VK_ERROR_INCOMPATIBLE_DRIVER) 8727ec681f3Smrg break; 8737ec681f3Smrg } 8747ec681f3Smrg#else 8757ec681f3Smrg /* On actual hardware, we should have a render node (v3d) 8767ec681f3Smrg * and a primary node (vc4). We will need to use the primary 8777ec681f3Smrg * to allocate WSI buffers and share them with the render node 8787ec681f3Smrg * via prime, but that is a privileged operation so we need the 8797ec681f3Smrg * primary node to be authenticated, and for that we need the 8807ec681f3Smrg * display server to provide the device fd (with DRI3), so we 8817ec681f3Smrg * here we only check that the device is present but we don't 8827ec681f3Smrg * try to open it. 8837ec681f3Smrg */ 8847ec681f3Smrg if (devices[i]->bustype != DRM_BUS_PLATFORM) 8857ec681f3Smrg continue; 8867ec681f3Smrg 8877ec681f3Smrg if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) { 8887ec681f3Smrg char **compat = devices[i]->deviceinfo.platform->compatible; 8897ec681f3Smrg while (*compat) { 8907ec681f3Smrg if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) { 8917ec681f3Smrg v3d_idx = i; 8927ec681f3Smrg break; 8937ec681f3Smrg } 8947ec681f3Smrg compat++; 8957ec681f3Smrg } 8967ec681f3Smrg } else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) { 8977ec681f3Smrg char **compat = devices[i]->deviceinfo.platform->compatible; 8987ec681f3Smrg while (*compat) { 8997ec681f3Smrg if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 || 9007ec681f3Smrg strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) { 9017ec681f3Smrg vc4_idx = i; 9027ec681f3Smrg break; 9037ec681f3Smrg } 9047ec681f3Smrg compat++; 9057ec681f3Smrg } 9067ec681f3Smrg } 9077ec681f3Smrg#endif 9087ec681f3Smrg } 9097ec681f3Smrg 9107ec681f3Smrg#if !using_v3d_simulator 9117ec681f3Smrg if (v3d_idx == -1 || vc4_idx == -1) 9127ec681f3Smrg result = VK_ERROR_INCOMPATIBLE_DRIVER; 9137ec681f3Smrg else 9147ec681f3Smrg result = physical_device_init(&instance->physicalDevice, instance, 9157ec681f3Smrg devices[v3d_idx], devices[vc4_idx]); 9167ec681f3Smrg#endif 9177ec681f3Smrg 9187ec681f3Smrg drmFreeDevices(devices, max_devices); 9197ec681f3Smrg 9207ec681f3Smrg if (result == VK_SUCCESS) 9217ec681f3Smrg instance->physicalDeviceCount = 1; 9227ec681f3Smrg 9237ec681f3Smrg return result; 9247ec681f3Smrg} 9257ec681f3Smrg 9267ec681f3Smrgstatic VkResult 9277ec681f3Smrginstance_ensure_physical_device(struct v3dv_instance *instance) 9287ec681f3Smrg{ 9297ec681f3Smrg if (instance->physicalDeviceCount < 0) { 9307ec681f3Smrg VkResult result = enumerate_devices(instance); 9317ec681f3Smrg if (result != VK_SUCCESS && 9327ec681f3Smrg result != VK_ERROR_INCOMPATIBLE_DRIVER) 9337ec681f3Smrg return result; 9347ec681f3Smrg } 9357ec681f3Smrg 9367ec681f3Smrg return VK_SUCCESS; 9377ec681f3Smrg} 9387ec681f3Smrg 9397ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 9407ec681f3Smrgv3dv_EnumeratePhysicalDevices(VkInstance _instance, 9417ec681f3Smrg uint32_t *pPhysicalDeviceCount, 9427ec681f3Smrg VkPhysicalDevice *pPhysicalDevices) 9437ec681f3Smrg{ 9447ec681f3Smrg V3DV_FROM_HANDLE(v3dv_instance, instance, _instance); 9457ec681f3Smrg VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount); 9467ec681f3Smrg 9477ec681f3Smrg VkResult result = instance_ensure_physical_device(instance); 9487ec681f3Smrg if (result != VK_SUCCESS) 9497ec681f3Smrg return result; 9507ec681f3Smrg 9517ec681f3Smrg if (instance->physicalDeviceCount == 0) 9527ec681f3Smrg return VK_SUCCESS; 9537ec681f3Smrg 9547ec681f3Smrg assert(instance->physicalDeviceCount == 1); 9557ec681f3Smrg vk_outarray_append(&out, i) { 9567ec681f3Smrg *i = v3dv_physical_device_to_handle(&instance->physicalDevice); 9577ec681f3Smrg } 9587ec681f3Smrg 9597ec681f3Smrg return vk_outarray_status(&out); 9607ec681f3Smrg} 9617ec681f3Smrg 9627ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 9637ec681f3Smrgv3dv_EnumeratePhysicalDeviceGroups( 9647ec681f3Smrg VkInstance _instance, 9657ec681f3Smrg uint32_t *pPhysicalDeviceGroupCount, 9667ec681f3Smrg VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) 9677ec681f3Smrg{ 9687ec681f3Smrg V3DV_FROM_HANDLE(v3dv_instance, instance, _instance); 9697ec681f3Smrg VK_OUTARRAY_MAKE(out, pPhysicalDeviceGroupProperties, 9707ec681f3Smrg pPhysicalDeviceGroupCount); 9717ec681f3Smrg 9727ec681f3Smrg VkResult result = instance_ensure_physical_device(instance); 9737ec681f3Smrg if (result != VK_SUCCESS) 9747ec681f3Smrg return result; 9757ec681f3Smrg 9767ec681f3Smrg assert(instance->physicalDeviceCount == 1); 9777ec681f3Smrg 9787ec681f3Smrg vk_outarray_append(&out, p) { 9797ec681f3Smrg p->physicalDeviceCount = 1; 9807ec681f3Smrg memset(p->physicalDevices, 0, sizeof(p->physicalDevices)); 9817ec681f3Smrg p->physicalDevices[0] = 9827ec681f3Smrg v3dv_physical_device_to_handle(&instance->physicalDevice); 9837ec681f3Smrg p->subsetAllocation = false; 9847ec681f3Smrg 9857ec681f3Smrg vk_foreach_struct(ext, p->pNext) 9867ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 9877ec681f3Smrg } 9887ec681f3Smrg 9897ec681f3Smrg return vk_outarray_status(&out); 9907ec681f3Smrg} 9917ec681f3Smrg 9927ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 9937ec681f3Smrgv3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, 9947ec681f3Smrg VkPhysicalDeviceFeatures *pFeatures) 9957ec681f3Smrg{ 9967ec681f3Smrg memset(pFeatures, 0, sizeof(*pFeatures)); 9977ec681f3Smrg 9987ec681f3Smrg *pFeatures = (VkPhysicalDeviceFeatures) { 9997ec681f3Smrg .robustBufferAccess = true, /* This feature is mandatory */ 10007ec681f3Smrg .fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */ 10017ec681f3Smrg .imageCubeArray = true, 10027ec681f3Smrg .independentBlend = true, 10037ec681f3Smrg .geometryShader = true, 10047ec681f3Smrg .tessellationShader = false, 10057ec681f3Smrg .sampleRateShading = true, 10067ec681f3Smrg .dualSrcBlend = false, 10077ec681f3Smrg .logicOp = true, 10087ec681f3Smrg .multiDrawIndirect = false, 10097ec681f3Smrg .drawIndirectFirstInstance = true, 10107ec681f3Smrg .depthClamp = false, 10117ec681f3Smrg .depthBiasClamp = true, 10127ec681f3Smrg .fillModeNonSolid = true, 10137ec681f3Smrg .depthBounds = false, /* Only available since V3D 4.3.16.2 */ 10147ec681f3Smrg .wideLines = true, 10157ec681f3Smrg .largePoints = true, 10167ec681f3Smrg .alphaToOne = true, 10177ec681f3Smrg .multiViewport = false, 10187ec681f3Smrg .samplerAnisotropy = true, 10197ec681f3Smrg .textureCompressionETC2 = true, 10207ec681f3Smrg .textureCompressionASTC_LDR = true, 10217ec681f3Smrg /* Note that textureCompressionBC requires that the driver support all 10227ec681f3Smrg * the BC formats. V3D 4.2 only support the BC1-3, so we can't claim 10237ec681f3Smrg * that we support it. 10247ec681f3Smrg */ 10257ec681f3Smrg .textureCompressionBC = false, 10267ec681f3Smrg .occlusionQueryPrecise = true, 10277ec681f3Smrg .pipelineStatisticsQuery = false, 10287ec681f3Smrg .vertexPipelineStoresAndAtomics = true, 10297ec681f3Smrg .fragmentStoresAndAtomics = true, 10307ec681f3Smrg .shaderTessellationAndGeometryPointSize = true, 10317ec681f3Smrg .shaderImageGatherExtended = false, 10327ec681f3Smrg .shaderStorageImageExtendedFormats = true, 10337ec681f3Smrg .shaderStorageImageMultisample = false, 10347ec681f3Smrg .shaderStorageImageReadWithoutFormat = false, 10357ec681f3Smrg .shaderStorageImageWriteWithoutFormat = false, 10367ec681f3Smrg .shaderUniformBufferArrayDynamicIndexing = false, 10377ec681f3Smrg .shaderSampledImageArrayDynamicIndexing = false, 10387ec681f3Smrg .shaderStorageBufferArrayDynamicIndexing = false, 10397ec681f3Smrg .shaderStorageImageArrayDynamicIndexing = false, 10407ec681f3Smrg .shaderClipDistance = true, 10417ec681f3Smrg .shaderCullDistance = false, 10427ec681f3Smrg .shaderFloat64 = false, 10437ec681f3Smrg .shaderInt64 = false, 10447ec681f3Smrg .shaderInt16 = false, 10457ec681f3Smrg .shaderResourceResidency = false, 10467ec681f3Smrg .shaderResourceMinLod = false, 10477ec681f3Smrg .sparseBinding = false, 10487ec681f3Smrg .sparseResidencyBuffer = false, 10497ec681f3Smrg .sparseResidencyImage2D = false, 10507ec681f3Smrg .sparseResidencyImage3D = false, 10517ec681f3Smrg .sparseResidency2Samples = false, 10527ec681f3Smrg .sparseResidency4Samples = false, 10537ec681f3Smrg .sparseResidency8Samples = false, 10547ec681f3Smrg .sparseResidency16Samples = false, 10557ec681f3Smrg .sparseResidencyAliased = false, 10567ec681f3Smrg .variableMultisampleRate = false, 10577ec681f3Smrg .inheritedQueries = true, 10587ec681f3Smrg }; 10597ec681f3Smrg} 10607ec681f3Smrg 10617ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 10627ec681f3Smrgv3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, 10637ec681f3Smrg VkPhysicalDeviceFeatures2 *pFeatures) 10647ec681f3Smrg{ 10657ec681f3Smrg v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features); 10667ec681f3Smrg 10677ec681f3Smrg VkPhysicalDeviceVulkan11Features vk11 = { 10687ec681f3Smrg .storageBuffer16BitAccess = false, 10697ec681f3Smrg .uniformAndStorageBuffer16BitAccess = false, 10707ec681f3Smrg .storagePushConstant16 = false, 10717ec681f3Smrg .storageInputOutput16 = false, 10727ec681f3Smrg .multiview = true, 10737ec681f3Smrg .multiviewGeometryShader = false, 10747ec681f3Smrg .multiviewTessellationShader = false, 10757ec681f3Smrg .variablePointersStorageBuffer = true, 10767ec681f3Smrg /* FIXME: this needs support for non-constant index on UBO/SSBO */ 10777ec681f3Smrg .variablePointers = false, 10787ec681f3Smrg .protectedMemory = false, 10797ec681f3Smrg .samplerYcbcrConversion = false, 10807ec681f3Smrg .shaderDrawParameters = false, 10817ec681f3Smrg }; 10827ec681f3Smrg 10837ec681f3Smrg vk_foreach_struct(ext, pFeatures->pNext) { 10847ec681f3Smrg switch (ext->sType) { 10857ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: { 10867ec681f3Smrg VkPhysicalDeviceCustomBorderColorFeaturesEXT *features = 10877ec681f3Smrg (VkPhysicalDeviceCustomBorderColorFeaturesEXT *)ext; 10887ec681f3Smrg features->customBorderColors = true; 10897ec681f3Smrg features->customBorderColorWithoutFormat = false; 10907ec681f3Smrg break; 10917ec681f3Smrg } 10927ec681f3Smrg 10937ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: { 10947ec681f3Smrg VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *features = 10957ec681f3Smrg (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *)ext; 10967ec681f3Smrg features->uniformBufferStandardLayout = true; 10977ec681f3Smrg break; 10987ec681f3Smrg } 10997ec681f3Smrg 11007ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: { 11017ec681f3Smrg VkPhysicalDevicePrivateDataFeaturesEXT *features = 11027ec681f3Smrg (VkPhysicalDevicePrivateDataFeaturesEXT *)ext; 11037ec681f3Smrg features->privateData = true; 11047ec681f3Smrg break; 11057ec681f3Smrg } 11067ec681f3Smrg 11077ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: { 11087ec681f3Smrg VkPhysicalDeviceIndexTypeUint8FeaturesEXT *features = 11097ec681f3Smrg (VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)ext; 11107ec681f3Smrg features->indexTypeUint8 = true; 11117ec681f3Smrg break; 11127ec681f3Smrg } 11137ec681f3Smrg 11147ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: { 11157ec681f3Smrg VkPhysicalDeviceColorWriteEnableFeaturesEXT *features = (void *) ext; 11167ec681f3Smrg features->colorWriteEnable = true; 11177ec681f3Smrg break; 11187ec681f3Smrg } 11197ec681f3Smrg 11207ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT: { 11217ec681f3Smrg VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT *features = (void *) ext; 11227ec681f3Smrg features->pipelineCreationCacheControl = true; 11237ec681f3Smrg break; 11247ec681f3Smrg } 11257ec681f3Smrg 11267ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: { 11277ec681f3Smrg VkPhysicalDeviceProvokingVertexFeaturesEXT *features = (void *) ext; 11287ec681f3Smrg features->provokingVertexLast = true; 11297ec681f3Smrg /* FIXME: update when supporting EXT_transform_feedback */ 11307ec681f3Smrg features->transformFeedbackPreservesProvokingVertex = false; 11317ec681f3Smrg break; 11327ec681f3Smrg } 11337ec681f3Smrg 11347ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: { 11357ec681f3Smrg VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *features = 11367ec681f3Smrg (void *) ext; 11377ec681f3Smrg features->vertexAttributeInstanceRateDivisor = true; 11387ec681f3Smrg features->vertexAttributeInstanceRateZeroDivisor = false; 11397ec681f3Smrg break; 11407ec681f3Smrg } 11417ec681f3Smrg 11427ec681f3Smrg /* Vulkan 1.1 */ 11437ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: { 11447ec681f3Smrg VkPhysicalDeviceVulkan11Features *features = 11457ec681f3Smrg (VkPhysicalDeviceVulkan11Features *)ext; 11467ec681f3Smrg memcpy(features, &vk11, sizeof(VkPhysicalDeviceVulkan11Features)); 11477ec681f3Smrg break; 11487ec681f3Smrg } 11497ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: { 11507ec681f3Smrg VkPhysicalDevice16BitStorageFeatures *features = (void *) ext; 11517ec681f3Smrg features->storageBuffer16BitAccess = vk11.storageBuffer16BitAccess; 11527ec681f3Smrg features->uniformAndStorageBuffer16BitAccess = 11537ec681f3Smrg vk11.uniformAndStorageBuffer16BitAccess; 11547ec681f3Smrg features->storagePushConstant16 = vk11.storagePushConstant16; 11557ec681f3Smrg features->storageInputOutput16 = vk11.storageInputOutput16; 11567ec681f3Smrg break; 11577ec681f3Smrg } 11587ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: { 11597ec681f3Smrg VkPhysicalDeviceMultiviewFeatures *features = (void *) ext; 11607ec681f3Smrg features->multiview = vk11.multiview; 11617ec681f3Smrg features->multiviewGeometryShader = vk11.multiviewGeometryShader; 11627ec681f3Smrg features->multiviewTessellationShader = vk11.multiviewTessellationShader; 11637ec681f3Smrg break; 11647ec681f3Smrg } 11657ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: { 11667ec681f3Smrg VkPhysicalDeviceProtectedMemoryFeatures *features = (void *) ext; 11677ec681f3Smrg features->protectedMemory = vk11.protectedMemory; 11687ec681f3Smrg break; 11697ec681f3Smrg } 11707ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: { 11717ec681f3Smrg VkPhysicalDeviceSamplerYcbcrConversionFeatures *features = (void *) ext; 11727ec681f3Smrg features->samplerYcbcrConversion = vk11.samplerYcbcrConversion; 11737ec681f3Smrg break; 11747ec681f3Smrg } 11757ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: { 11767ec681f3Smrg VkPhysicalDeviceShaderDrawParametersFeatures *features = (void *) ext; 11777ec681f3Smrg features->shaderDrawParameters = vk11.shaderDrawParameters; 11787ec681f3Smrg break; 11797ec681f3Smrg } 11807ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: { 11817ec681f3Smrg VkPhysicalDeviceVariablePointersFeatures *features = (void *) ext; 11827ec681f3Smrg features->variablePointersStorageBuffer = 11837ec681f3Smrg vk11.variablePointersStorageBuffer; 11847ec681f3Smrg features->variablePointers = vk11.variablePointers; 11857ec681f3Smrg break; 11867ec681f3Smrg } 11877ec681f3Smrg 11887ec681f3Smrg default: 11897ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 11907ec681f3Smrg break; 11917ec681f3Smrg } 11927ec681f3Smrg } 11937ec681f3Smrg} 11947ec681f3Smrg 11957ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 11967ec681f3Smrgv3dv_GetDeviceGroupPeerMemoryFeatures(VkDevice device, 11977ec681f3Smrg uint32_t heapIndex, 11987ec681f3Smrg uint32_t localDeviceIndex, 11997ec681f3Smrg uint32_t remoteDeviceIndex, 12007ec681f3Smrg VkPeerMemoryFeatureFlags *pPeerMemoryFeatures) 12017ec681f3Smrg{ 12027ec681f3Smrg assert(localDeviceIndex == 0 && remoteDeviceIndex == 0); 12037ec681f3Smrg *pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT | 12047ec681f3Smrg VK_PEER_MEMORY_FEATURE_COPY_DST_BIT | 12057ec681f3Smrg VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT | 12067ec681f3Smrg VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT; 12077ec681f3Smrg} 12087ec681f3Smrg 12097ec681f3Smrguint32_t 12107ec681f3Smrgv3dv_physical_device_vendor_id(struct v3dv_physical_device *dev) 12117ec681f3Smrg{ 12127ec681f3Smrg return 0x14E4; /* Broadcom */ 12137ec681f3Smrg} 12147ec681f3Smrg 12157ec681f3Smrg 12167ec681f3Smrg#if using_v3d_simulator 12177ec681f3Smrgstatic bool 12187ec681f3Smrgget_i915_param(int fd, uint32_t param, int *value) 12197ec681f3Smrg{ 12207ec681f3Smrg int tmp; 12217ec681f3Smrg 12227ec681f3Smrg struct drm_i915_getparam gp = { 12237ec681f3Smrg .param = param, 12247ec681f3Smrg .value = &tmp, 12257ec681f3Smrg }; 12267ec681f3Smrg 12277ec681f3Smrg int ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); 12287ec681f3Smrg if (ret != 0) 12297ec681f3Smrg return false; 12307ec681f3Smrg 12317ec681f3Smrg *value = tmp; 12327ec681f3Smrg return true; 12337ec681f3Smrg} 12347ec681f3Smrg#endif 12357ec681f3Smrg 12367ec681f3Smrguint32_t 12377ec681f3Smrgv3dv_physical_device_device_id(struct v3dv_physical_device *dev) 12387ec681f3Smrg{ 12397ec681f3Smrg#if using_v3d_simulator 12407ec681f3Smrg int devid = 0; 12417ec681f3Smrg 12427ec681f3Smrg if (!get_i915_param(dev->render_fd, I915_PARAM_CHIPSET_ID, &devid)) 12437ec681f3Smrg fprintf(stderr, "Error getting device_id\n"); 12447ec681f3Smrg 12457ec681f3Smrg return devid; 12467ec681f3Smrg#else 12477ec681f3Smrg switch (dev->devinfo.ver) { 12487ec681f3Smrg case 42: 12497ec681f3Smrg return 0xBE485FD3; /* Broadcom deviceID for 2711 */ 12507ec681f3Smrg default: 12517ec681f3Smrg unreachable("Unsupported V3D version"); 12527ec681f3Smrg } 12537ec681f3Smrg#endif 12547ec681f3Smrg} 12557ec681f3Smrg 12567ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 12577ec681f3Smrgv3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, 12587ec681f3Smrg VkPhysicalDeviceProperties *pProperties) 12597ec681f3Smrg{ 12607ec681f3Smrg V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice); 12617ec681f3Smrg 12627ec681f3Smrg STATIC_ASSERT(MAX_SAMPLED_IMAGES + MAX_STORAGE_IMAGES + MAX_INPUT_ATTACHMENTS 12637ec681f3Smrg <= V3D_MAX_TEXTURE_SAMPLERS); 12647ec681f3Smrg STATIC_ASSERT(MAX_UNIFORM_BUFFERS >= MAX_DYNAMIC_UNIFORM_BUFFERS); 12657ec681f3Smrg STATIC_ASSERT(MAX_STORAGE_BUFFERS >= MAX_DYNAMIC_STORAGE_BUFFERS); 12667ec681f3Smrg 12677ec681f3Smrg const uint32_t page_size = 4096; 12687ec681f3Smrg const uint32_t mem_size = compute_heap_size(); 12697ec681f3Smrg 12707ec681f3Smrg const uint32_t max_varying_components = 16 * 4; 12717ec681f3Smrg 12727ec681f3Smrg const uint32_t v3d_coord_shift = 6; 12737ec681f3Smrg 12747ec681f3Smrg const float v3d_point_line_granularity = 2.0f / (1 << v3d_coord_shift); 12757ec681f3Smrg const uint32_t max_fb_size = 4096; 12767ec681f3Smrg 12777ec681f3Smrg const VkSampleCountFlags supported_sample_counts = 12787ec681f3Smrg VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT; 12797ec681f3Smrg 12807ec681f3Smrg struct timespec clock_res; 12817ec681f3Smrg clock_getres(CLOCK_MONOTONIC, &clock_res); 12827ec681f3Smrg const float timestamp_period = 12837ec681f3Smrg clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec; 12847ec681f3Smrg 12857ec681f3Smrg /* FIXME: this will probably require an in-depth review */ 12867ec681f3Smrg VkPhysicalDeviceLimits limits = { 12877ec681f3Smrg .maxImageDimension1D = 4096, 12887ec681f3Smrg .maxImageDimension2D = 4096, 12897ec681f3Smrg .maxImageDimension3D = 4096, 12907ec681f3Smrg .maxImageDimensionCube = 4096, 12917ec681f3Smrg .maxImageArrayLayers = 2048, 12927ec681f3Smrg .maxTexelBufferElements = (1ul << 28), 12937ec681f3Smrg .maxUniformBufferRange = V3D_MAX_BUFFER_RANGE, 12947ec681f3Smrg .maxStorageBufferRange = V3D_MAX_BUFFER_RANGE, 12957ec681f3Smrg .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE, 12967ec681f3Smrg .maxMemoryAllocationCount = mem_size / page_size, 12977ec681f3Smrg .maxSamplerAllocationCount = 64 * 1024, 12987ec681f3Smrg .bufferImageGranularity = 256, /* A cache line */ 12997ec681f3Smrg .sparseAddressSpaceSize = 0, 13007ec681f3Smrg .maxBoundDescriptorSets = MAX_SETS, 13017ec681f3Smrg .maxPerStageDescriptorSamplers = V3D_MAX_TEXTURE_SAMPLERS, 13027ec681f3Smrg .maxPerStageDescriptorUniformBuffers = MAX_UNIFORM_BUFFERS, 13037ec681f3Smrg .maxPerStageDescriptorStorageBuffers = MAX_STORAGE_BUFFERS, 13047ec681f3Smrg .maxPerStageDescriptorSampledImages = MAX_SAMPLED_IMAGES, 13057ec681f3Smrg .maxPerStageDescriptorStorageImages = MAX_STORAGE_IMAGES, 13067ec681f3Smrg .maxPerStageDescriptorInputAttachments = MAX_INPUT_ATTACHMENTS, 13077ec681f3Smrg .maxPerStageResources = 128, 13087ec681f3Smrg 13097ec681f3Smrg /* Some of these limits are multiplied by 6 because they need to 13107ec681f3Smrg * include all possible shader stages (even if not supported). See 13117ec681f3Smrg * 'Required Limits' table in the Vulkan spec. 13127ec681f3Smrg */ 13137ec681f3Smrg .maxDescriptorSetSamplers = 6 * V3D_MAX_TEXTURE_SAMPLERS, 13147ec681f3Smrg .maxDescriptorSetUniformBuffers = 6 * MAX_UNIFORM_BUFFERS, 13157ec681f3Smrg .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS, 13167ec681f3Smrg .maxDescriptorSetStorageBuffers = 6 * MAX_STORAGE_BUFFERS, 13177ec681f3Smrg .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS, 13187ec681f3Smrg .maxDescriptorSetSampledImages = 6 * MAX_SAMPLED_IMAGES, 13197ec681f3Smrg .maxDescriptorSetStorageImages = 6 * MAX_STORAGE_IMAGES, 13207ec681f3Smrg .maxDescriptorSetInputAttachments = MAX_INPUT_ATTACHMENTS, 13217ec681f3Smrg 13227ec681f3Smrg /* Vertex limits */ 13237ec681f3Smrg .maxVertexInputAttributes = MAX_VERTEX_ATTRIBS, 13247ec681f3Smrg .maxVertexInputBindings = MAX_VBS, 13257ec681f3Smrg .maxVertexInputAttributeOffset = 0xffffffff, 13267ec681f3Smrg .maxVertexInputBindingStride = 0xffffffff, 13277ec681f3Smrg .maxVertexOutputComponents = max_varying_components, 13287ec681f3Smrg 13297ec681f3Smrg /* Tessellation limits */ 13307ec681f3Smrg .maxTessellationGenerationLevel = 0, 13317ec681f3Smrg .maxTessellationPatchSize = 0, 13327ec681f3Smrg .maxTessellationControlPerVertexInputComponents = 0, 13337ec681f3Smrg .maxTessellationControlPerVertexOutputComponents = 0, 13347ec681f3Smrg .maxTessellationControlPerPatchOutputComponents = 0, 13357ec681f3Smrg .maxTessellationControlTotalOutputComponents = 0, 13367ec681f3Smrg .maxTessellationEvaluationInputComponents = 0, 13377ec681f3Smrg .maxTessellationEvaluationOutputComponents = 0, 13387ec681f3Smrg 13397ec681f3Smrg /* Geometry limits */ 13407ec681f3Smrg .maxGeometryShaderInvocations = 32, 13417ec681f3Smrg .maxGeometryInputComponents = 64, 13427ec681f3Smrg .maxGeometryOutputComponents = 64, 13437ec681f3Smrg .maxGeometryOutputVertices = 256, 13447ec681f3Smrg .maxGeometryTotalOutputComponents = 1024, 13457ec681f3Smrg 13467ec681f3Smrg /* Fragment limits */ 13477ec681f3Smrg .maxFragmentInputComponents = max_varying_components, 13487ec681f3Smrg .maxFragmentOutputAttachments = 4, 13497ec681f3Smrg .maxFragmentDualSrcAttachments = 0, 13507ec681f3Smrg .maxFragmentCombinedOutputResources = MAX_RENDER_TARGETS + 13517ec681f3Smrg MAX_STORAGE_BUFFERS + 13527ec681f3Smrg MAX_STORAGE_IMAGES, 13537ec681f3Smrg 13547ec681f3Smrg /* Compute limits */ 13557ec681f3Smrg .maxComputeSharedMemorySize = 16384, 13567ec681f3Smrg .maxComputeWorkGroupCount = { 65535, 65535, 65535 }, 13577ec681f3Smrg .maxComputeWorkGroupInvocations = 256, 13587ec681f3Smrg .maxComputeWorkGroupSize = { 256, 256, 256 }, 13597ec681f3Smrg 13607ec681f3Smrg .subPixelPrecisionBits = v3d_coord_shift, 13617ec681f3Smrg .subTexelPrecisionBits = 8, 13627ec681f3Smrg .mipmapPrecisionBits = 8, 13637ec681f3Smrg .maxDrawIndexedIndexValue = 0x00ffffff, 13647ec681f3Smrg .maxDrawIndirectCount = 0x7fffffff, 13657ec681f3Smrg .maxSamplerLodBias = 14.0f, 13667ec681f3Smrg .maxSamplerAnisotropy = 16.0f, 13677ec681f3Smrg .maxViewports = MAX_VIEWPORTS, 13687ec681f3Smrg .maxViewportDimensions = { max_fb_size, max_fb_size }, 13697ec681f3Smrg .viewportBoundsRange = { -2.0 * max_fb_size, 13707ec681f3Smrg 2.0 * max_fb_size - 1 }, 13717ec681f3Smrg .viewportSubPixelBits = 0, 13727ec681f3Smrg .minMemoryMapAlignment = page_size, 13737ec681f3Smrg .minTexelBufferOffsetAlignment = V3D_UIFBLOCK_SIZE, 13747ec681f3Smrg .minUniformBufferOffsetAlignment = 32, 13757ec681f3Smrg .minStorageBufferOffsetAlignment = 32, 13767ec681f3Smrg .minTexelOffset = -8, 13777ec681f3Smrg .maxTexelOffset = 7, 13787ec681f3Smrg .minTexelGatherOffset = -8, 13797ec681f3Smrg .maxTexelGatherOffset = 7, 13807ec681f3Smrg .minInterpolationOffset = -0.5, 13817ec681f3Smrg .maxInterpolationOffset = 0.5, 13827ec681f3Smrg .subPixelInterpolationOffsetBits = v3d_coord_shift, 13837ec681f3Smrg .maxFramebufferWidth = max_fb_size, 13847ec681f3Smrg .maxFramebufferHeight = max_fb_size, 13857ec681f3Smrg .maxFramebufferLayers = 256, 13867ec681f3Smrg .framebufferColorSampleCounts = supported_sample_counts, 13877ec681f3Smrg .framebufferDepthSampleCounts = supported_sample_counts, 13887ec681f3Smrg .framebufferStencilSampleCounts = supported_sample_counts, 13897ec681f3Smrg .framebufferNoAttachmentsSampleCounts = supported_sample_counts, 13907ec681f3Smrg .maxColorAttachments = MAX_RENDER_TARGETS, 13917ec681f3Smrg .sampledImageColorSampleCounts = supported_sample_counts, 13927ec681f3Smrg .sampledImageIntegerSampleCounts = supported_sample_counts, 13937ec681f3Smrg .sampledImageDepthSampleCounts = supported_sample_counts, 13947ec681f3Smrg .sampledImageStencilSampleCounts = supported_sample_counts, 13957ec681f3Smrg .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT, 13967ec681f3Smrg .maxSampleMaskWords = 1, 13977ec681f3Smrg .timestampComputeAndGraphics = true, 13987ec681f3Smrg .timestampPeriod = timestamp_period, 13997ec681f3Smrg .maxClipDistances = 8, 14007ec681f3Smrg .maxCullDistances = 0, 14017ec681f3Smrg .maxCombinedClipAndCullDistances = 8, 14027ec681f3Smrg .discreteQueuePriorities = 2, 14037ec681f3Smrg .pointSizeRange = { v3d_point_line_granularity, 14047ec681f3Smrg V3D_MAX_POINT_SIZE }, 14057ec681f3Smrg .lineWidthRange = { 1.0f, V3D_MAX_LINE_WIDTH }, 14067ec681f3Smrg .pointSizeGranularity = v3d_point_line_granularity, 14077ec681f3Smrg .lineWidthGranularity = v3d_point_line_granularity, 14087ec681f3Smrg .strictLines = true, 14097ec681f3Smrg .standardSampleLocations = false, 14107ec681f3Smrg .optimalBufferCopyOffsetAlignment = 32, 14117ec681f3Smrg .optimalBufferCopyRowPitchAlignment = 32, 14127ec681f3Smrg .nonCoherentAtomSize = 256, 14137ec681f3Smrg }; 14147ec681f3Smrg 14157ec681f3Smrg *pProperties = (VkPhysicalDeviceProperties) { 14167ec681f3Smrg .apiVersion = V3DV_API_VERSION, 14177ec681f3Smrg .driverVersion = vk_get_driver_version(), 14187ec681f3Smrg .vendorID = v3dv_physical_device_vendor_id(pdevice), 14197ec681f3Smrg .deviceID = v3dv_physical_device_device_id(pdevice), 14207ec681f3Smrg .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, 14217ec681f3Smrg .limits = limits, 14227ec681f3Smrg .sparseProperties = { 0 }, 14237ec681f3Smrg }; 14247ec681f3Smrg 14257ec681f3Smrg snprintf(pProperties->deviceName, sizeof(pProperties->deviceName), 14267ec681f3Smrg "%s", pdevice->name); 14277ec681f3Smrg memcpy(pProperties->pipelineCacheUUID, 14287ec681f3Smrg pdevice->pipeline_cache_uuid, VK_UUID_SIZE); 14297ec681f3Smrg} 14307ec681f3Smrg 14317ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 14327ec681f3Smrgv3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, 14337ec681f3Smrg VkPhysicalDeviceProperties2 *pProperties) 14347ec681f3Smrg{ 14357ec681f3Smrg V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice); 14367ec681f3Smrg 14377ec681f3Smrg v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties); 14387ec681f3Smrg 14397ec681f3Smrg vk_foreach_struct(ext, pProperties->pNext) { 14407ec681f3Smrg switch (ext->sType) { 14417ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: { 14427ec681f3Smrg VkPhysicalDeviceCustomBorderColorPropertiesEXT *props = 14437ec681f3Smrg (VkPhysicalDeviceCustomBorderColorPropertiesEXT *)ext; 14447ec681f3Smrg props->maxCustomBorderColorSamplers = V3D_MAX_TEXTURE_SAMPLERS; 14457ec681f3Smrg break; 14467ec681f3Smrg } 14477ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: { 14487ec681f3Smrg VkPhysicalDeviceProvokingVertexPropertiesEXT *props = 14497ec681f3Smrg (VkPhysicalDeviceProvokingVertexPropertiesEXT *)ext; 14507ec681f3Smrg props->provokingVertexModePerPipeline = true; 14517ec681f3Smrg /* FIXME: update when supporting EXT_transform_feedback */ 14527ec681f3Smrg props->transformFeedbackPreservesTriangleFanProvokingVertex = false; 14537ec681f3Smrg break; 14547ec681f3Smrg } 14557ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { 14567ec681f3Smrg VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *props = 14577ec681f3Smrg (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext; 14587ec681f3Smrg props->maxVertexAttribDivisor = 0xffff; 14597ec681f3Smrg break; 14607ec681f3Smrg } 14617ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: { 14627ec681f3Smrg VkPhysicalDeviceIDProperties *id_props = 14637ec681f3Smrg (VkPhysicalDeviceIDProperties *)ext; 14647ec681f3Smrg memcpy(id_props->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE); 14657ec681f3Smrg memcpy(id_props->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE); 14667ec681f3Smrg /* The LUID is for Windows. */ 14677ec681f3Smrg id_props->deviceLUIDValid = false; 14687ec681f3Smrg break; 14697ec681f3Smrg } 14707ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT: { 14717ec681f3Smrg VkPhysicalDeviceDrmPropertiesEXT *props = 14727ec681f3Smrg (VkPhysicalDeviceDrmPropertiesEXT *)ext; 14737ec681f3Smrg props->hasPrimary = pdevice->has_primary; 14747ec681f3Smrg if (props->hasPrimary) { 14757ec681f3Smrg props->primaryMajor = (int64_t) major(pdevice->primary_devid); 14767ec681f3Smrg props->primaryMinor = (int64_t) minor(pdevice->primary_devid); 14777ec681f3Smrg } 14787ec681f3Smrg props->hasRender = pdevice->has_render; 14797ec681f3Smrg if (props->hasRender) { 14807ec681f3Smrg props->renderMajor = (int64_t) major(pdevice->render_devid); 14817ec681f3Smrg props->renderMinor = (int64_t) minor(pdevice->render_devid); 14827ec681f3Smrg } 14837ec681f3Smrg break; 14847ec681f3Smrg } 14857ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: { 14867ec681f3Smrg VkPhysicalDeviceMaintenance3Properties *props = 14877ec681f3Smrg (VkPhysicalDeviceMaintenance3Properties *)ext; 14887ec681f3Smrg /* We don't really have special restrictions for the maximum 14897ec681f3Smrg * descriptors per set, other than maybe not exceeding the limits 14907ec681f3Smrg * of addressable memory in a single allocation on either the host 14917ec681f3Smrg * or the GPU. This will be a much larger limit than any of the 14927ec681f3Smrg * per-stage limits already available in Vulkan though, so in practice, 14937ec681f3Smrg * it is not expected to limit anything beyond what is already 14947ec681f3Smrg * constrained through per-stage limits. 14957ec681f3Smrg */ 14967ec681f3Smrg uint32_t max_host_descriptors = 14977ec681f3Smrg (UINT32_MAX - sizeof(struct v3dv_descriptor_set)) / 14987ec681f3Smrg sizeof(struct v3dv_descriptor); 14997ec681f3Smrg uint32_t max_gpu_descriptors = 15007ec681f3Smrg (UINT32_MAX / v3dv_X(pdevice, max_descriptor_bo_size)()); 15017ec681f3Smrg props->maxPerSetDescriptors = 15027ec681f3Smrg MIN2(max_host_descriptors, max_gpu_descriptors); 15037ec681f3Smrg 15047ec681f3Smrg /* Minimum required by the spec */ 15057ec681f3Smrg props->maxMemoryAllocationSize = MAX_MEMORY_ALLOCATION_SIZE; 15067ec681f3Smrg break; 15077ec681f3Smrg } 15087ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: { 15097ec681f3Smrg VkPhysicalDeviceMultiviewProperties *props = 15107ec681f3Smrg (VkPhysicalDeviceMultiviewProperties *)ext; 15117ec681f3Smrg props->maxMultiviewViewCount = MAX_MULTIVIEW_VIEW_COUNT; 15127ec681f3Smrg props->maxMultiviewInstanceIndex = UINT32_MAX - 1; 15137ec681f3Smrg break; 15147ec681f3Smrg } 15157ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT: 15167ec681f3Smrg /* Do nothing, not even logging. This is a non-PCI device, so we will 15177ec681f3Smrg * never provide this extension. 15187ec681f3Smrg */ 15197ec681f3Smrg break; 15207ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: { 15217ec681f3Smrg VkPhysicalDevicePointClippingProperties *props = 15227ec681f3Smrg (VkPhysicalDevicePointClippingProperties *)ext; 15237ec681f3Smrg props->pointClippingBehavior = 15247ec681f3Smrg VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES; 15257ec681f3Smrg break; 15267ec681f3Smrg } 15277ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: { 15287ec681f3Smrg VkPhysicalDeviceProtectedMemoryProperties *props = 15297ec681f3Smrg (VkPhysicalDeviceProtectedMemoryProperties *)ext; 15307ec681f3Smrg props->protectedNoFault = false; 15317ec681f3Smrg break; 15327ec681f3Smrg } 15337ec681f3Smrg case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: { 15347ec681f3Smrg VkPhysicalDeviceSubgroupProperties *props = 15357ec681f3Smrg (VkPhysicalDeviceSubgroupProperties *)ext; 15367ec681f3Smrg props->subgroupSize = V3D_CHANNELS; 15377ec681f3Smrg props->supportedStages = VK_SHADER_STAGE_COMPUTE_BIT; 15387ec681f3Smrg props->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT; 15397ec681f3Smrg props->quadOperationsInAllStages = false; 15407ec681f3Smrg break; 15417ec681f3Smrg } 15427ec681f3Smrg default: 15437ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 15447ec681f3Smrg break; 15457ec681f3Smrg } 15467ec681f3Smrg } 15477ec681f3Smrg} 15487ec681f3Smrg 15497ec681f3Smrg/* We support exactly one queue family. */ 15507ec681f3Smrgstatic const VkQueueFamilyProperties 15517ec681f3Smrgv3dv_queue_family_properties = { 15527ec681f3Smrg .queueFlags = VK_QUEUE_GRAPHICS_BIT | 15537ec681f3Smrg VK_QUEUE_COMPUTE_BIT | 15547ec681f3Smrg VK_QUEUE_TRANSFER_BIT, 15557ec681f3Smrg .queueCount = 1, 15567ec681f3Smrg .timestampValidBits = 64, 15577ec681f3Smrg .minImageTransferGranularity = { 1, 1, 1 }, 15587ec681f3Smrg}; 15597ec681f3Smrg 15607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 15617ec681f3Smrgv3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, 15627ec681f3Smrg uint32_t *pCount, 15637ec681f3Smrg VkQueueFamilyProperties *pQueueFamilyProperties) 15647ec681f3Smrg{ 15657ec681f3Smrg VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pCount); 15667ec681f3Smrg 15677ec681f3Smrg vk_outarray_append(&out, p) { 15687ec681f3Smrg *p = v3dv_queue_family_properties; 15697ec681f3Smrg } 15707ec681f3Smrg} 15717ec681f3Smrg 15727ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 15737ec681f3Smrgv3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, 15747ec681f3Smrg uint32_t *pQueueFamilyPropertyCount, 15757ec681f3Smrg VkQueueFamilyProperties2 *pQueueFamilyProperties) 15767ec681f3Smrg{ 15777ec681f3Smrg VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount); 15787ec681f3Smrg 15797ec681f3Smrg vk_outarray_append(&out, p) { 15807ec681f3Smrg p->queueFamilyProperties = v3dv_queue_family_properties; 15817ec681f3Smrg 15827ec681f3Smrg vk_foreach_struct(s, p->pNext) { 15837ec681f3Smrg v3dv_debug_ignored_stype(s->sType); 15847ec681f3Smrg } 15857ec681f3Smrg } 15867ec681f3Smrg} 15877ec681f3Smrg 15887ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 15897ec681f3Smrgv3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, 15907ec681f3Smrg VkPhysicalDeviceMemoryProperties *pMemoryProperties) 15917ec681f3Smrg{ 15927ec681f3Smrg V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice); 15937ec681f3Smrg *pMemoryProperties = device->memory; 15947ec681f3Smrg} 15957ec681f3Smrg 15967ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 15977ec681f3Smrgv3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, 15987ec681f3Smrg VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) 15997ec681f3Smrg{ 16007ec681f3Smrg v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice, 16017ec681f3Smrg &pMemoryProperties->memoryProperties); 16027ec681f3Smrg 16037ec681f3Smrg vk_foreach_struct(ext, pMemoryProperties->pNext) { 16047ec681f3Smrg switch (ext->sType) { 16057ec681f3Smrg default: 16067ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 16077ec681f3Smrg break; 16087ec681f3Smrg } 16097ec681f3Smrg } 16107ec681f3Smrg} 16117ec681f3Smrg 16127ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 16137ec681f3Smrgv3dv_GetInstanceProcAddr(VkInstance _instance, 16147ec681f3Smrg const char *pName) 16157ec681f3Smrg{ 16167ec681f3Smrg V3DV_FROM_HANDLE(v3dv_instance, instance, _instance); 16177ec681f3Smrg return vk_instance_get_proc_addr(&instance->vk, 16187ec681f3Smrg &v3dv_instance_entrypoints, 16197ec681f3Smrg pName); 16207ec681f3Smrg} 16217ec681f3Smrg 16227ec681f3Smrg/* With version 1+ of the loader interface the ICD should expose 16237ec681f3Smrg * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps. 16247ec681f3Smrg */ 16257ec681f3SmrgPUBLIC 16267ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction 16277ec681f3SmrgVKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, 16287ec681f3Smrg const char *pName); 16297ec681f3Smrg 16307ec681f3SmrgPUBLIC 16317ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 16327ec681f3Smrgvk_icdGetInstanceProcAddr(VkInstance instance, 16337ec681f3Smrg const char* pName) 16347ec681f3Smrg{ 16357ec681f3Smrg return v3dv_GetInstanceProcAddr(instance, pName); 16367ec681f3Smrg} 16377ec681f3Smrg 16387ec681f3Smrg/* With version 4+ of the loader interface the ICD should expose 16397ec681f3Smrg * vk_icdGetPhysicalDeviceProcAddr() 16407ec681f3Smrg */ 16417ec681f3SmrgPUBLIC 16427ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 16437ec681f3Smrgvk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, 16447ec681f3Smrg const char* pName); 16457ec681f3Smrg 16467ec681f3SmrgPFN_vkVoidFunction 16477ec681f3Smrgvk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, 16487ec681f3Smrg const char* pName) 16497ec681f3Smrg{ 16507ec681f3Smrg V3DV_FROM_HANDLE(v3dv_instance, instance, _instance); 16517ec681f3Smrg 16527ec681f3Smrg return vk_instance_get_physical_device_proc_addr(&instance->vk, pName); 16537ec681f3Smrg} 16547ec681f3Smrg 16557ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 16567ec681f3Smrgv3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount, 16577ec681f3Smrg VkLayerProperties *pProperties) 16587ec681f3Smrg{ 16597ec681f3Smrg if (pProperties == NULL) { 16607ec681f3Smrg *pPropertyCount = 0; 16617ec681f3Smrg return VK_SUCCESS; 16627ec681f3Smrg } 16637ec681f3Smrg 16647ec681f3Smrg return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); 16657ec681f3Smrg} 16667ec681f3Smrg 16677ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 16687ec681f3Smrgv3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, 16697ec681f3Smrg uint32_t *pPropertyCount, 16707ec681f3Smrg VkLayerProperties *pProperties) 16717ec681f3Smrg{ 16727ec681f3Smrg V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice); 16737ec681f3Smrg 16747ec681f3Smrg if (pProperties == NULL) { 16757ec681f3Smrg *pPropertyCount = 0; 16767ec681f3Smrg return VK_SUCCESS; 16777ec681f3Smrg } 16787ec681f3Smrg 16797ec681f3Smrg return vk_error(physical_device, VK_ERROR_LAYER_NOT_PRESENT); 16807ec681f3Smrg} 16817ec681f3Smrg 16827ec681f3Smrgstatic VkResult 16837ec681f3Smrgqueue_init(struct v3dv_device *device, struct v3dv_queue *queue, 16847ec681f3Smrg const VkDeviceQueueCreateInfo *create_info, 16857ec681f3Smrg uint32_t index_in_family) 16867ec681f3Smrg{ 16877ec681f3Smrg VkResult result = vk_queue_init(&queue->vk, &device->vk, create_info, 16887ec681f3Smrg index_in_family); 16897ec681f3Smrg if (result != VK_SUCCESS) 16907ec681f3Smrg return result; 16917ec681f3Smrg queue->device = device; 16927ec681f3Smrg queue->noop_job = NULL; 16937ec681f3Smrg list_inithead(&queue->submit_wait_list); 16947ec681f3Smrg pthread_mutex_init(&queue->mutex, NULL); 16957ec681f3Smrg return VK_SUCCESS; 16967ec681f3Smrg} 16977ec681f3Smrg 16987ec681f3Smrgstatic void 16997ec681f3Smrgqueue_finish(struct v3dv_queue *queue) 17007ec681f3Smrg{ 17017ec681f3Smrg vk_queue_finish(&queue->vk); 17027ec681f3Smrg assert(list_is_empty(&queue->submit_wait_list)); 17037ec681f3Smrg if (queue->noop_job) 17047ec681f3Smrg v3dv_job_destroy(queue->noop_job); 17057ec681f3Smrg pthread_mutex_destroy(&queue->mutex); 17067ec681f3Smrg} 17077ec681f3Smrg 17087ec681f3Smrgstatic void 17097ec681f3Smrginit_device_meta(struct v3dv_device *device) 17107ec681f3Smrg{ 17117ec681f3Smrg mtx_init(&device->meta.mtx, mtx_plain); 17127ec681f3Smrg v3dv_meta_clear_init(device); 17137ec681f3Smrg v3dv_meta_blit_init(device); 17147ec681f3Smrg v3dv_meta_texel_buffer_copy_init(device); 17157ec681f3Smrg} 17167ec681f3Smrg 17177ec681f3Smrgstatic void 17187ec681f3Smrgdestroy_device_meta(struct v3dv_device *device) 17197ec681f3Smrg{ 17207ec681f3Smrg mtx_destroy(&device->meta.mtx); 17217ec681f3Smrg v3dv_meta_clear_finish(device); 17227ec681f3Smrg v3dv_meta_blit_finish(device); 17237ec681f3Smrg v3dv_meta_texel_buffer_copy_finish(device); 17247ec681f3Smrg} 17257ec681f3Smrg 17267ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 17277ec681f3Smrgv3dv_CreateDevice(VkPhysicalDevice physicalDevice, 17287ec681f3Smrg const VkDeviceCreateInfo *pCreateInfo, 17297ec681f3Smrg const VkAllocationCallbacks *pAllocator, 17307ec681f3Smrg VkDevice *pDevice) 17317ec681f3Smrg{ 17327ec681f3Smrg V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice); 17337ec681f3Smrg struct v3dv_instance *instance = (struct v3dv_instance*) physical_device->vk.instance; 17347ec681f3Smrg VkResult result; 17357ec681f3Smrg struct v3dv_device *device; 17367ec681f3Smrg 17377ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO); 17387ec681f3Smrg 17397ec681f3Smrg /* Check requested queues (we only expose one queue ) */ 17407ec681f3Smrg assert(pCreateInfo->queueCreateInfoCount == 1); 17417ec681f3Smrg for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { 17427ec681f3Smrg assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0); 17437ec681f3Smrg assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1); 17447ec681f3Smrg if (pCreateInfo->pQueueCreateInfos[i].flags != 0) 17457ec681f3Smrg return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); 17467ec681f3Smrg } 17477ec681f3Smrg 17487ec681f3Smrg device = vk_zalloc2(&physical_device->vk.instance->alloc, pAllocator, 17497ec681f3Smrg sizeof(*device), 8, 17507ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 17517ec681f3Smrg if (!device) 17527ec681f3Smrg return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY); 17537ec681f3Smrg 17547ec681f3Smrg struct vk_device_dispatch_table dispatch_table; 17557ec681f3Smrg vk_device_dispatch_table_from_entrypoints(&dispatch_table, 17567ec681f3Smrg &v3dv_device_entrypoints, true); 17577ec681f3Smrg vk_device_dispatch_table_from_entrypoints(&dispatch_table, 17587ec681f3Smrg &wsi_device_entrypoints, false); 17597ec681f3Smrg result = vk_device_init(&device->vk, &physical_device->vk, 17607ec681f3Smrg &dispatch_table, pCreateInfo, pAllocator); 17617ec681f3Smrg if (result != VK_SUCCESS) { 17627ec681f3Smrg vk_free(&device->vk.alloc, device); 17637ec681f3Smrg return vk_error(NULL, result); 17647ec681f3Smrg } 17657ec681f3Smrg 17667ec681f3Smrg device->instance = instance; 17677ec681f3Smrg device->pdevice = physical_device; 17687ec681f3Smrg 17697ec681f3Smrg if (pAllocator) 17707ec681f3Smrg device->vk.alloc = *pAllocator; 17717ec681f3Smrg else 17727ec681f3Smrg device->vk.alloc = physical_device->vk.instance->alloc; 17737ec681f3Smrg 17747ec681f3Smrg pthread_mutex_init(&device->mutex, NULL); 17757ec681f3Smrg 17767ec681f3Smrg result = queue_init(device, &device->queue, 17777ec681f3Smrg pCreateInfo->pQueueCreateInfos, 0); 17787ec681f3Smrg if (result != VK_SUCCESS) 17797ec681f3Smrg goto fail; 17807ec681f3Smrg 17817ec681f3Smrg device->devinfo = physical_device->devinfo; 17827ec681f3Smrg 17837ec681f3Smrg /* Vulkan 1.1 and VK_KHR_get_physical_device_properties2 added 17847ec681f3Smrg * VkPhysicalDeviceFeatures2 which can be used in the pNext chain of 17857ec681f3Smrg * vkDeviceCreateInfo, in which case it should be used instead of 17867ec681f3Smrg * pEnabledFeatures. 17877ec681f3Smrg */ 17887ec681f3Smrg const VkPhysicalDeviceFeatures2 *features2 = 17897ec681f3Smrg vk_find_struct_const(pCreateInfo->pNext, PHYSICAL_DEVICE_FEATURES_2); 17907ec681f3Smrg if (features2) { 17917ec681f3Smrg memcpy(&device->features, &features2->features, 17927ec681f3Smrg sizeof(device->features)); 17937ec681f3Smrg } else if (pCreateInfo->pEnabledFeatures) { 17947ec681f3Smrg memcpy(&device->features, pCreateInfo->pEnabledFeatures, 17957ec681f3Smrg sizeof(device->features)); 17967ec681f3Smrg } 17977ec681f3Smrg 17987ec681f3Smrg if (device->features.robustBufferAccess) 17997ec681f3Smrg perf_debug("Device created with Robust Buffer Access enabled.\n"); 18007ec681f3Smrg 18017ec681f3Smrg int ret = drmSyncobjCreate(physical_device->render_fd, 18027ec681f3Smrg DRM_SYNCOBJ_CREATE_SIGNALED, 18037ec681f3Smrg &device->last_job_sync); 18047ec681f3Smrg if (ret) { 18057ec681f3Smrg result = VK_ERROR_INITIALIZATION_FAILED; 18067ec681f3Smrg goto fail; 18077ec681f3Smrg } 18087ec681f3Smrg 18097ec681f3Smrg#ifdef DEBUG 18107ec681f3Smrg v3dv_X(device, device_check_prepacked_sizes)(); 18117ec681f3Smrg#endif 18127ec681f3Smrg init_device_meta(device); 18137ec681f3Smrg v3dv_bo_cache_init(device); 18147ec681f3Smrg v3dv_pipeline_cache_init(&device->default_pipeline_cache, device, 0, 18157ec681f3Smrg device->instance->default_pipeline_cache_enabled); 18167ec681f3Smrg device->default_attribute_float = 18177ec681f3Smrg v3dv_pipeline_create_default_attribute_values(device, NULL); 18187ec681f3Smrg 18197ec681f3Smrg *pDevice = v3dv_device_to_handle(device); 18207ec681f3Smrg 18217ec681f3Smrg return VK_SUCCESS; 18227ec681f3Smrg 18237ec681f3Smrgfail: 18247ec681f3Smrg vk_device_finish(&device->vk); 18257ec681f3Smrg vk_free(&device->vk.alloc, device); 18267ec681f3Smrg 18277ec681f3Smrg return result; 18287ec681f3Smrg} 18297ec681f3Smrg 18307ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 18317ec681f3Smrgv3dv_DestroyDevice(VkDevice _device, 18327ec681f3Smrg const VkAllocationCallbacks *pAllocator) 18337ec681f3Smrg{ 18347ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 18357ec681f3Smrg 18367ec681f3Smrg v3dv_DeviceWaitIdle(_device); 18377ec681f3Smrg queue_finish(&device->queue); 18387ec681f3Smrg pthread_mutex_destroy(&device->mutex); 18397ec681f3Smrg drmSyncobjDestroy(device->pdevice->render_fd, device->last_job_sync); 18407ec681f3Smrg destroy_device_meta(device); 18417ec681f3Smrg v3dv_pipeline_cache_finish(&device->default_pipeline_cache); 18427ec681f3Smrg 18437ec681f3Smrg if (device->default_attribute_float) { 18447ec681f3Smrg v3dv_bo_free(device, device->default_attribute_float); 18457ec681f3Smrg device->default_attribute_float = NULL; 18467ec681f3Smrg } 18477ec681f3Smrg 18487ec681f3Smrg /* Bo cache should be removed the last, as any other object could be 18497ec681f3Smrg * freeing their private bos 18507ec681f3Smrg */ 18517ec681f3Smrg v3dv_bo_cache_destroy(device); 18527ec681f3Smrg 18537ec681f3Smrg vk_device_finish(&device->vk); 18547ec681f3Smrg vk_free2(&device->vk.alloc, pAllocator, device); 18557ec681f3Smrg} 18567ec681f3Smrg 18577ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 18587ec681f3Smrgv3dv_DeviceWaitIdle(VkDevice _device) 18597ec681f3Smrg{ 18607ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 18617ec681f3Smrg return v3dv_QueueWaitIdle(v3dv_queue_to_handle(&device->queue)); 18627ec681f3Smrg} 18637ec681f3Smrg 18647ec681f3Smrgstatic VkResult 18657ec681f3Smrgdevice_alloc(struct v3dv_device *device, 18667ec681f3Smrg struct v3dv_device_memory *mem, 18677ec681f3Smrg VkDeviceSize size) 18687ec681f3Smrg{ 18697ec681f3Smrg /* Our kernel interface is 32-bit */ 18707ec681f3Smrg assert(size <= UINT32_MAX); 18717ec681f3Smrg 18727ec681f3Smrg mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false); 18737ec681f3Smrg if (!mem->bo) 18747ec681f3Smrg return VK_ERROR_OUT_OF_DEVICE_MEMORY; 18757ec681f3Smrg 18767ec681f3Smrg return VK_SUCCESS; 18777ec681f3Smrg} 18787ec681f3Smrg 18797ec681f3Smrgstatic void 18807ec681f3Smrgdevice_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle) 18817ec681f3Smrg{ 18827ec681f3Smrg assert(display_fd != -1); 18837ec681f3Smrg if (dumb_handle < 0) 18847ec681f3Smrg return; 18857ec681f3Smrg 18867ec681f3Smrg struct drm_mode_destroy_dumb destroy_dumb = { 18877ec681f3Smrg .handle = dumb_handle, 18887ec681f3Smrg }; 18897ec681f3Smrg if (v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb)) { 18907ec681f3Smrg fprintf(stderr, "destroy dumb object %d: %s\n", dumb_handle, strerror(errno)); 18917ec681f3Smrg } 18927ec681f3Smrg} 18937ec681f3Smrg 18947ec681f3Smrgstatic void 18957ec681f3Smrgdevice_free(struct v3dv_device *device, struct v3dv_device_memory *mem) 18967ec681f3Smrg{ 18977ec681f3Smrg /* If this memory allocation was for WSI, then we need to use the 18987ec681f3Smrg * display device to free the allocated dumb BO. 18997ec681f3Smrg */ 19007ec681f3Smrg if (mem->is_for_wsi) { 19017ec681f3Smrg assert(mem->has_bo_ownership); 19027ec681f3Smrg device_free_wsi_dumb(device->instance->physicalDevice.display_fd, 19037ec681f3Smrg mem->bo->dumb_handle); 19047ec681f3Smrg } 19057ec681f3Smrg 19067ec681f3Smrg if (mem->has_bo_ownership) 19077ec681f3Smrg v3dv_bo_free(device, mem->bo); 19087ec681f3Smrg else if (mem->bo) 19097ec681f3Smrg vk_free(&device->vk.alloc, mem->bo); 19107ec681f3Smrg} 19117ec681f3Smrg 19127ec681f3Smrgstatic void 19137ec681f3Smrgdevice_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem) 19147ec681f3Smrg{ 19157ec681f3Smrg assert(mem && mem->bo->map && mem->bo->map_size > 0); 19167ec681f3Smrg v3dv_bo_unmap(device, mem->bo); 19177ec681f3Smrg} 19187ec681f3Smrg 19197ec681f3Smrgstatic VkResult 19207ec681f3Smrgdevice_map(struct v3dv_device *device, struct v3dv_device_memory *mem) 19217ec681f3Smrg{ 19227ec681f3Smrg assert(mem && mem->bo); 19237ec681f3Smrg 19247ec681f3Smrg /* From the spec: 19257ec681f3Smrg * 19267ec681f3Smrg * "After a successful call to vkMapMemory the memory object memory is 19277ec681f3Smrg * considered to be currently host mapped. It is an application error to 19287ec681f3Smrg * call vkMapMemory on a memory object that is already host mapped." 19297ec681f3Smrg * 19307ec681f3Smrg * We are not concerned with this ourselves (validation layers should 19317ec681f3Smrg * catch these errors and warn users), however, the driver may internally 19327ec681f3Smrg * map things (for example for debug CLIF dumps or some CPU-side operations) 19337ec681f3Smrg * so by the time the user calls here the buffer might already been mapped 19347ec681f3Smrg * internally by the driver. 19357ec681f3Smrg */ 19367ec681f3Smrg if (mem->bo->map) { 19377ec681f3Smrg assert(mem->bo->map_size == mem->bo->size); 19387ec681f3Smrg return VK_SUCCESS; 19397ec681f3Smrg } 19407ec681f3Smrg 19417ec681f3Smrg bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size); 19427ec681f3Smrg if (!ok) 19437ec681f3Smrg return VK_ERROR_MEMORY_MAP_FAILED; 19447ec681f3Smrg 19457ec681f3Smrg return VK_SUCCESS; 19467ec681f3Smrg} 19477ec681f3Smrg 19487ec681f3Smrgstatic VkResult 19497ec681f3Smrgdevice_import_bo(struct v3dv_device *device, 19507ec681f3Smrg const VkAllocationCallbacks *pAllocator, 19517ec681f3Smrg int fd, uint64_t size, 19527ec681f3Smrg struct v3dv_bo **bo) 19537ec681f3Smrg{ 19547ec681f3Smrg VkResult result; 19557ec681f3Smrg 19567ec681f3Smrg *bo = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(struct v3dv_bo), 8, 19577ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 19587ec681f3Smrg if (*bo == NULL) { 19597ec681f3Smrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 19607ec681f3Smrg goto fail; 19617ec681f3Smrg } 19627ec681f3Smrg 19637ec681f3Smrg off_t real_size = lseek(fd, 0, SEEK_END); 19647ec681f3Smrg lseek(fd, 0, SEEK_SET); 19657ec681f3Smrg if (real_size < 0 || (uint64_t) real_size < size) { 19667ec681f3Smrg result = VK_ERROR_INVALID_EXTERNAL_HANDLE; 19677ec681f3Smrg goto fail; 19687ec681f3Smrg } 19697ec681f3Smrg 19707ec681f3Smrg int render_fd = device->pdevice->render_fd; 19717ec681f3Smrg assert(render_fd >= 0); 19727ec681f3Smrg 19737ec681f3Smrg int ret; 19747ec681f3Smrg uint32_t handle; 19757ec681f3Smrg ret = drmPrimeFDToHandle(render_fd, fd, &handle); 19767ec681f3Smrg if (ret) { 19777ec681f3Smrg result = VK_ERROR_INVALID_EXTERNAL_HANDLE; 19787ec681f3Smrg goto fail; 19797ec681f3Smrg } 19807ec681f3Smrg 19817ec681f3Smrg struct drm_v3d_get_bo_offset get_offset = { 19827ec681f3Smrg .handle = handle, 19837ec681f3Smrg }; 19847ec681f3Smrg ret = v3dv_ioctl(render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset); 19857ec681f3Smrg if (ret) { 19867ec681f3Smrg result = VK_ERROR_INVALID_EXTERNAL_HANDLE; 19877ec681f3Smrg goto fail; 19887ec681f3Smrg } 19897ec681f3Smrg assert(get_offset.offset != 0); 19907ec681f3Smrg 19917ec681f3Smrg v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false); 19927ec681f3Smrg 19937ec681f3Smrg return VK_SUCCESS; 19947ec681f3Smrg 19957ec681f3Smrgfail: 19967ec681f3Smrg if (*bo) { 19977ec681f3Smrg vk_free2(&device->vk.alloc, pAllocator, *bo); 19987ec681f3Smrg *bo = NULL; 19997ec681f3Smrg } 20007ec681f3Smrg return result; 20017ec681f3Smrg} 20027ec681f3Smrg 20037ec681f3Smrgstatic VkResult 20047ec681f3Smrgdevice_alloc_for_wsi(struct v3dv_device *device, 20057ec681f3Smrg const VkAllocationCallbacks *pAllocator, 20067ec681f3Smrg struct v3dv_device_memory *mem, 20077ec681f3Smrg VkDeviceSize size) 20087ec681f3Smrg{ 20097ec681f3Smrg /* In the simulator we can get away with a regular allocation since both 20107ec681f3Smrg * allocation and rendering happen in the same DRM render node. On actual 20117ec681f3Smrg * hardware we need to allocate our winsys BOs on the vc4 display device 20127ec681f3Smrg * and import them into v3d. 20137ec681f3Smrg */ 20147ec681f3Smrg#if using_v3d_simulator 20157ec681f3Smrg return device_alloc(device, mem, size); 20167ec681f3Smrg#else 20177ec681f3Smrg /* If we are allocating for WSI we should have a swapchain and thus, 20187ec681f3Smrg * we should've initialized the display device. However, Zink doesn't 20197ec681f3Smrg * use swapchains, so in that case we can get here without acquiring the 20207ec681f3Smrg * display device and we need to do it now. 20217ec681f3Smrg */ 20227ec681f3Smrg VkResult result; 20237ec681f3Smrg struct v3dv_instance *instance = device->instance; 20247ec681f3Smrg struct v3dv_physical_device *pdevice = &device->instance->physicalDevice; 20257ec681f3Smrg if (unlikely(pdevice->display_fd < 0)) { 20267ec681f3Smrg result = v3dv_physical_device_acquire_display(instance, pdevice, NULL); 20277ec681f3Smrg if (result != VK_SUCCESS) 20287ec681f3Smrg return result; 20297ec681f3Smrg } 20307ec681f3Smrg assert(pdevice->display_fd != -1); 20317ec681f3Smrg 20327ec681f3Smrg mem->is_for_wsi = true; 20337ec681f3Smrg 20347ec681f3Smrg int display_fd = pdevice->display_fd; 20357ec681f3Smrg struct drm_mode_create_dumb create_dumb = { 20367ec681f3Smrg .width = 1024, /* one page */ 20377ec681f3Smrg .height = align(size, 4096) / 4096, 20387ec681f3Smrg .bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM), 20397ec681f3Smrg }; 20407ec681f3Smrg 20417ec681f3Smrg int err; 20427ec681f3Smrg err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); 20437ec681f3Smrg if (err < 0) 20447ec681f3Smrg goto fail_create; 20457ec681f3Smrg 20467ec681f3Smrg int fd; 20477ec681f3Smrg err = 20487ec681f3Smrg drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd); 20497ec681f3Smrg if (err < 0) 20507ec681f3Smrg goto fail_export; 20517ec681f3Smrg 20527ec681f3Smrg result = device_import_bo(device, pAllocator, fd, size, &mem->bo); 20537ec681f3Smrg close(fd); 20547ec681f3Smrg if (result != VK_SUCCESS) 20557ec681f3Smrg goto fail_import; 20567ec681f3Smrg 20577ec681f3Smrg mem->bo->dumb_handle = create_dumb.handle; 20587ec681f3Smrg return VK_SUCCESS; 20597ec681f3Smrg 20607ec681f3Smrgfail_import: 20617ec681f3Smrgfail_export: 20627ec681f3Smrg device_free_wsi_dumb(display_fd, create_dumb.handle); 20637ec681f3Smrg 20647ec681f3Smrgfail_create: 20657ec681f3Smrg return VK_ERROR_OUT_OF_DEVICE_MEMORY; 20667ec681f3Smrg#endif 20677ec681f3Smrg} 20687ec681f3Smrg 20697ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 20707ec681f3Smrgv3dv_AllocateMemory(VkDevice _device, 20717ec681f3Smrg const VkMemoryAllocateInfo *pAllocateInfo, 20727ec681f3Smrg const VkAllocationCallbacks *pAllocator, 20737ec681f3Smrg VkDeviceMemory *pMem) 20747ec681f3Smrg{ 20757ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 20767ec681f3Smrg struct v3dv_device_memory *mem; 20777ec681f3Smrg struct v3dv_physical_device *pdevice = &device->instance->physicalDevice; 20787ec681f3Smrg 20797ec681f3Smrg assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); 20807ec681f3Smrg 20817ec681f3Smrg /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */ 20827ec681f3Smrg assert(pAllocateInfo->allocationSize > 0); 20837ec681f3Smrg 20847ec681f3Smrg mem = vk_object_zalloc(&device->vk, pAllocator, sizeof(*mem), 20857ec681f3Smrg VK_OBJECT_TYPE_DEVICE_MEMORY); 20867ec681f3Smrg if (mem == NULL) 20877ec681f3Smrg return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY); 20887ec681f3Smrg 20897ec681f3Smrg assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount); 20907ec681f3Smrg mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex]; 20917ec681f3Smrg mem->has_bo_ownership = true; 20927ec681f3Smrg mem->is_for_wsi = false; 20937ec681f3Smrg 20947ec681f3Smrg const struct wsi_memory_allocate_info *wsi_info = NULL; 20957ec681f3Smrg const VkImportMemoryFdInfoKHR *fd_info = NULL; 20967ec681f3Smrg vk_foreach_struct_const(ext, pAllocateInfo->pNext) { 20977ec681f3Smrg switch ((unsigned)ext->sType) { 20987ec681f3Smrg case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA: 20997ec681f3Smrg wsi_info = (void *)ext; 21007ec681f3Smrg break; 21017ec681f3Smrg case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: 21027ec681f3Smrg fd_info = (void *)ext; 21037ec681f3Smrg break; 21047ec681f3Smrg case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: 21057ec681f3Smrg /* We don't support VK_KHR_buffer_device_address or multiple 21067ec681f3Smrg * devices per device group, so we can ignore this. 21077ec681f3Smrg */ 21087ec681f3Smrg break; 21097ec681f3Smrg case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR: 21107ec681f3Smrg /* We don't have particular optimizations associated with memory 21117ec681f3Smrg * allocations that won't be suballocated to multiple resources. 21127ec681f3Smrg */ 21137ec681f3Smrg break; 21147ec681f3Smrg case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR: 21157ec681f3Smrg /* The mask of handle types specified here must be supported 21167ec681f3Smrg * according to VkExternalImageFormatProperties, so it must be 21177ec681f3Smrg * fd or dmabuf, which don't have special requirements for us. 21187ec681f3Smrg */ 21197ec681f3Smrg break; 21207ec681f3Smrg default: 21217ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 21227ec681f3Smrg break; 21237ec681f3Smrg } 21247ec681f3Smrg } 21257ec681f3Smrg 21267ec681f3Smrg VkResult result = VK_SUCCESS; 21277ec681f3Smrg 21287ec681f3Smrg /* We always allocate device memory in multiples of a page, so round up 21297ec681f3Smrg * requested size to that. 21307ec681f3Smrg */ 21317ec681f3Smrg VkDeviceSize alloc_size = ALIGN(pAllocateInfo->allocationSize, 4096); 21327ec681f3Smrg 21337ec681f3Smrg if (unlikely(alloc_size > MAX_MEMORY_ALLOCATION_SIZE)) { 21347ec681f3Smrg result = VK_ERROR_OUT_OF_DEVICE_MEMORY; 21357ec681f3Smrg } else { 21367ec681f3Smrg if (wsi_info) { 21377ec681f3Smrg result = device_alloc_for_wsi(device, pAllocator, mem, alloc_size); 21387ec681f3Smrg } else if (fd_info && fd_info->handleType) { 21397ec681f3Smrg assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT || 21407ec681f3Smrg fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); 21417ec681f3Smrg result = device_import_bo(device, pAllocator, 21427ec681f3Smrg fd_info->fd, alloc_size, &mem->bo); 21437ec681f3Smrg mem->has_bo_ownership = false; 21447ec681f3Smrg if (result == VK_SUCCESS) 21457ec681f3Smrg close(fd_info->fd); 21467ec681f3Smrg } else { 21477ec681f3Smrg result = device_alloc(device, mem, alloc_size); 21487ec681f3Smrg } 21497ec681f3Smrg } 21507ec681f3Smrg 21517ec681f3Smrg if (result != VK_SUCCESS) { 21527ec681f3Smrg vk_object_free(&device->vk, pAllocator, mem); 21537ec681f3Smrg return vk_error(device, result); 21547ec681f3Smrg } 21557ec681f3Smrg 21567ec681f3Smrg *pMem = v3dv_device_memory_to_handle(mem); 21577ec681f3Smrg return result; 21587ec681f3Smrg} 21597ec681f3Smrg 21607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 21617ec681f3Smrgv3dv_FreeMemory(VkDevice _device, 21627ec681f3Smrg VkDeviceMemory _mem, 21637ec681f3Smrg const VkAllocationCallbacks *pAllocator) 21647ec681f3Smrg{ 21657ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 21667ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem); 21677ec681f3Smrg 21687ec681f3Smrg if (mem == NULL) 21697ec681f3Smrg return; 21707ec681f3Smrg 21717ec681f3Smrg if (mem->bo->map) 21727ec681f3Smrg v3dv_UnmapMemory(_device, _mem); 21737ec681f3Smrg 21747ec681f3Smrg device_free(device, mem); 21757ec681f3Smrg 21767ec681f3Smrg vk_object_free(&device->vk, pAllocator, mem); 21777ec681f3Smrg} 21787ec681f3Smrg 21797ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 21807ec681f3Smrgv3dv_MapMemory(VkDevice _device, 21817ec681f3Smrg VkDeviceMemory _memory, 21827ec681f3Smrg VkDeviceSize offset, 21837ec681f3Smrg VkDeviceSize size, 21847ec681f3Smrg VkMemoryMapFlags flags, 21857ec681f3Smrg void **ppData) 21867ec681f3Smrg{ 21877ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 21887ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory); 21897ec681f3Smrg 21907ec681f3Smrg if (mem == NULL) { 21917ec681f3Smrg *ppData = NULL; 21927ec681f3Smrg return VK_SUCCESS; 21937ec681f3Smrg } 21947ec681f3Smrg 21957ec681f3Smrg assert(offset < mem->bo->size); 21967ec681f3Smrg 21977ec681f3Smrg /* Since the driver can map BOs internally as well and the mapped range 21987ec681f3Smrg * required by the user or the driver might not be the same, we always map 21997ec681f3Smrg * the entire BO and then add the requested offset to the start address 22007ec681f3Smrg * of the mapped region. 22017ec681f3Smrg */ 22027ec681f3Smrg VkResult result = device_map(device, mem); 22037ec681f3Smrg if (result != VK_SUCCESS) 22047ec681f3Smrg return vk_error(device, result); 22057ec681f3Smrg 22067ec681f3Smrg *ppData = ((uint8_t *) mem->bo->map) + offset; 22077ec681f3Smrg return VK_SUCCESS; 22087ec681f3Smrg} 22097ec681f3Smrg 22107ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 22117ec681f3Smrgv3dv_UnmapMemory(VkDevice _device, 22127ec681f3Smrg VkDeviceMemory _memory) 22137ec681f3Smrg{ 22147ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 22157ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory); 22167ec681f3Smrg 22177ec681f3Smrg if (mem == NULL) 22187ec681f3Smrg return; 22197ec681f3Smrg 22207ec681f3Smrg device_unmap(device, mem); 22217ec681f3Smrg} 22227ec681f3Smrg 22237ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 22247ec681f3Smrgv3dv_FlushMappedMemoryRanges(VkDevice _device, 22257ec681f3Smrg uint32_t memoryRangeCount, 22267ec681f3Smrg const VkMappedMemoryRange *pMemoryRanges) 22277ec681f3Smrg{ 22287ec681f3Smrg return VK_SUCCESS; 22297ec681f3Smrg} 22307ec681f3Smrg 22317ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 22327ec681f3Smrgv3dv_InvalidateMappedMemoryRanges(VkDevice _device, 22337ec681f3Smrg uint32_t memoryRangeCount, 22347ec681f3Smrg const VkMappedMemoryRange *pMemoryRanges) 22357ec681f3Smrg{ 22367ec681f3Smrg return VK_SUCCESS; 22377ec681f3Smrg} 22387ec681f3Smrg 22397ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 22407ec681f3Smrgv3dv_GetImageMemoryRequirements2(VkDevice device, 22417ec681f3Smrg const VkImageMemoryRequirementsInfo2 *pInfo, 22427ec681f3Smrg VkMemoryRequirements2 *pMemoryRequirements) 22437ec681f3Smrg{ 22447ec681f3Smrg V3DV_FROM_HANDLE(v3dv_image, image, pInfo->image); 22457ec681f3Smrg 22467ec681f3Smrg pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) { 22477ec681f3Smrg .memoryTypeBits = 0x1, 22487ec681f3Smrg .alignment = image->alignment, 22497ec681f3Smrg .size = image->size 22507ec681f3Smrg }; 22517ec681f3Smrg 22527ec681f3Smrg vk_foreach_struct(ext, pMemoryRequirements->pNext) { 22537ec681f3Smrg switch (ext->sType) { 22547ec681f3Smrg case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: { 22557ec681f3Smrg VkMemoryDedicatedRequirements *req = 22567ec681f3Smrg (VkMemoryDedicatedRequirements *) ext; 22577ec681f3Smrg req->requiresDedicatedAllocation = image->vk.external_handle_types != 0; 22587ec681f3Smrg req->prefersDedicatedAllocation = image->vk.external_handle_types != 0; 22597ec681f3Smrg break; 22607ec681f3Smrg } 22617ec681f3Smrg default: 22627ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 22637ec681f3Smrg break; 22647ec681f3Smrg } 22657ec681f3Smrg } 22667ec681f3Smrg} 22677ec681f3Smrg 22687ec681f3Smrgstatic void 22697ec681f3Smrgbind_image_memory(const VkBindImageMemoryInfo *info) 22707ec681f3Smrg{ 22717ec681f3Smrg V3DV_FROM_HANDLE(v3dv_image, image, info->image); 22727ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory); 22737ec681f3Smrg 22747ec681f3Smrg /* Valid usage: 22757ec681f3Smrg * 22767ec681f3Smrg * "memoryOffset must be an integer multiple of the alignment member of 22777ec681f3Smrg * the VkMemoryRequirements structure returned from a call to 22787ec681f3Smrg * vkGetImageMemoryRequirements with image" 22797ec681f3Smrg */ 22807ec681f3Smrg assert(info->memoryOffset % image->alignment == 0); 22817ec681f3Smrg assert(info->memoryOffset < mem->bo->size); 22827ec681f3Smrg 22837ec681f3Smrg image->mem = mem; 22847ec681f3Smrg image->mem_offset = info->memoryOffset; 22857ec681f3Smrg} 22867ec681f3Smrg 22877ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 22887ec681f3Smrgv3dv_BindImageMemory2(VkDevice _device, 22897ec681f3Smrg uint32_t bindInfoCount, 22907ec681f3Smrg const VkBindImageMemoryInfo *pBindInfos) 22917ec681f3Smrg{ 22927ec681f3Smrg for (uint32_t i = 0; i < bindInfoCount; i++) { 22937ec681f3Smrg const VkBindImageMemorySwapchainInfoKHR *swapchain_info = 22947ec681f3Smrg vk_find_struct_const(pBindInfos->pNext, 22957ec681f3Smrg BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR); 22967ec681f3Smrg if (swapchain_info && swapchain_info->swapchain) { 22977ec681f3Smrg struct v3dv_image *swapchain_image = 22987ec681f3Smrg v3dv_wsi_get_image_from_swapchain(swapchain_info->swapchain, 22997ec681f3Smrg swapchain_info->imageIndex); 23007ec681f3Smrg VkBindImageMemoryInfo swapchain_bind = { 23017ec681f3Smrg .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, 23027ec681f3Smrg .image = pBindInfos[i].image, 23037ec681f3Smrg .memory = v3dv_device_memory_to_handle(swapchain_image->mem), 23047ec681f3Smrg .memoryOffset = swapchain_image->mem_offset, 23057ec681f3Smrg }; 23067ec681f3Smrg bind_image_memory(&swapchain_bind); 23077ec681f3Smrg } else { 23087ec681f3Smrg bind_image_memory(&pBindInfos[i]); 23097ec681f3Smrg } 23107ec681f3Smrg } 23117ec681f3Smrg 23127ec681f3Smrg return VK_SUCCESS; 23137ec681f3Smrg} 23147ec681f3Smrg 23157ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 23167ec681f3Smrgv3dv_GetBufferMemoryRequirements2(VkDevice device, 23177ec681f3Smrg const VkBufferMemoryRequirementsInfo2 *pInfo, 23187ec681f3Smrg VkMemoryRequirements2 *pMemoryRequirements) 23197ec681f3Smrg{ 23207ec681f3Smrg V3DV_FROM_HANDLE(v3dv_buffer, buffer, pInfo->buffer); 23217ec681f3Smrg 23227ec681f3Smrg pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) { 23237ec681f3Smrg .memoryTypeBits = 0x1, 23247ec681f3Smrg .alignment = buffer->alignment, 23257ec681f3Smrg .size = align64(buffer->size, buffer->alignment), 23267ec681f3Smrg }; 23277ec681f3Smrg 23287ec681f3Smrg vk_foreach_struct(ext, pMemoryRequirements->pNext) { 23297ec681f3Smrg switch (ext->sType) { 23307ec681f3Smrg case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: { 23317ec681f3Smrg VkMemoryDedicatedRequirements *req = 23327ec681f3Smrg (VkMemoryDedicatedRequirements *) ext; 23337ec681f3Smrg req->requiresDedicatedAllocation = false; 23347ec681f3Smrg req->prefersDedicatedAllocation = false; 23357ec681f3Smrg break; 23367ec681f3Smrg } 23377ec681f3Smrg default: 23387ec681f3Smrg v3dv_debug_ignored_stype(ext->sType); 23397ec681f3Smrg break; 23407ec681f3Smrg } 23417ec681f3Smrg } 23427ec681f3Smrg} 23437ec681f3Smrg 23447ec681f3Smrgstatic void 23457ec681f3Smrgbind_buffer_memory(const VkBindBufferMemoryInfo *info) 23467ec681f3Smrg{ 23477ec681f3Smrg V3DV_FROM_HANDLE(v3dv_buffer, buffer, info->buffer); 23487ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory); 23497ec681f3Smrg 23507ec681f3Smrg /* Valid usage: 23517ec681f3Smrg * 23527ec681f3Smrg * "memoryOffset must be an integer multiple of the alignment member of 23537ec681f3Smrg * the VkMemoryRequirements structure returned from a call to 23547ec681f3Smrg * vkGetBufferMemoryRequirements with buffer" 23557ec681f3Smrg */ 23567ec681f3Smrg assert(info->memoryOffset % buffer->alignment == 0); 23577ec681f3Smrg assert(info->memoryOffset < mem->bo->size); 23587ec681f3Smrg 23597ec681f3Smrg buffer->mem = mem; 23607ec681f3Smrg buffer->mem_offset = info->memoryOffset; 23617ec681f3Smrg} 23627ec681f3Smrg 23637ec681f3Smrg 23647ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 23657ec681f3Smrgv3dv_BindBufferMemory2(VkDevice device, 23667ec681f3Smrg uint32_t bindInfoCount, 23677ec681f3Smrg const VkBindBufferMemoryInfo *pBindInfos) 23687ec681f3Smrg{ 23697ec681f3Smrg for (uint32_t i = 0; i < bindInfoCount; i++) 23707ec681f3Smrg bind_buffer_memory(&pBindInfos[i]); 23717ec681f3Smrg 23727ec681f3Smrg return VK_SUCCESS; 23737ec681f3Smrg} 23747ec681f3Smrg 23757ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 23767ec681f3Smrgv3dv_CreateBuffer(VkDevice _device, 23777ec681f3Smrg const VkBufferCreateInfo *pCreateInfo, 23787ec681f3Smrg const VkAllocationCallbacks *pAllocator, 23797ec681f3Smrg VkBuffer *pBuffer) 23807ec681f3Smrg{ 23817ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 23827ec681f3Smrg struct v3dv_buffer *buffer; 23837ec681f3Smrg 23847ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO); 23857ec681f3Smrg assert(pCreateInfo->usage != 0); 23867ec681f3Smrg 23877ec681f3Smrg /* We don't support any flags for now */ 23887ec681f3Smrg assert(pCreateInfo->flags == 0); 23897ec681f3Smrg 23907ec681f3Smrg buffer = vk_object_zalloc(&device->vk, pAllocator, sizeof(*buffer), 23917ec681f3Smrg VK_OBJECT_TYPE_BUFFER); 23927ec681f3Smrg if (buffer == NULL) 23937ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 23947ec681f3Smrg 23957ec681f3Smrg buffer->size = pCreateInfo->size; 23967ec681f3Smrg buffer->usage = pCreateInfo->usage; 23977ec681f3Smrg buffer->alignment = 256; /* nonCoherentAtomSize */ 23987ec681f3Smrg 23997ec681f3Smrg /* Limit allocations to 32-bit */ 24007ec681f3Smrg const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment); 24017ec681f3Smrg if (aligned_size > UINT32_MAX || aligned_size < buffer->size) 24027ec681f3Smrg return VK_ERROR_OUT_OF_DEVICE_MEMORY; 24037ec681f3Smrg 24047ec681f3Smrg *pBuffer = v3dv_buffer_to_handle(buffer); 24057ec681f3Smrg 24067ec681f3Smrg return VK_SUCCESS; 24077ec681f3Smrg} 24087ec681f3Smrg 24097ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 24107ec681f3Smrgv3dv_DestroyBuffer(VkDevice _device, 24117ec681f3Smrg VkBuffer _buffer, 24127ec681f3Smrg const VkAllocationCallbacks *pAllocator) 24137ec681f3Smrg{ 24147ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 24157ec681f3Smrg V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer); 24167ec681f3Smrg 24177ec681f3Smrg if (!buffer) 24187ec681f3Smrg return; 24197ec681f3Smrg 24207ec681f3Smrg vk_object_free(&device->vk, pAllocator, buffer); 24217ec681f3Smrg} 24227ec681f3Smrg 24237ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24247ec681f3Smrgv3dv_CreateFramebuffer(VkDevice _device, 24257ec681f3Smrg const VkFramebufferCreateInfo *pCreateInfo, 24267ec681f3Smrg const VkAllocationCallbacks *pAllocator, 24277ec681f3Smrg VkFramebuffer *pFramebuffer) 24287ec681f3Smrg{ 24297ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 24307ec681f3Smrg struct v3dv_framebuffer *framebuffer; 24317ec681f3Smrg 24327ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); 24337ec681f3Smrg 24347ec681f3Smrg size_t size = sizeof(*framebuffer) + 24357ec681f3Smrg sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount; 24367ec681f3Smrg framebuffer = vk_object_zalloc(&device->vk, pAllocator, size, 24377ec681f3Smrg VK_OBJECT_TYPE_FRAMEBUFFER); 24387ec681f3Smrg if (framebuffer == NULL) 24397ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 24407ec681f3Smrg 24417ec681f3Smrg framebuffer->width = pCreateInfo->width; 24427ec681f3Smrg framebuffer->height = pCreateInfo->height; 24437ec681f3Smrg framebuffer->layers = pCreateInfo->layers; 24447ec681f3Smrg framebuffer->has_edge_padding = true; 24457ec681f3Smrg 24467ec681f3Smrg framebuffer->attachment_count = pCreateInfo->attachmentCount; 24477ec681f3Smrg framebuffer->color_attachment_count = 0; 24487ec681f3Smrg for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { 24497ec681f3Smrg framebuffer->attachments[i] = 24507ec681f3Smrg v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]); 24517ec681f3Smrg if (framebuffer->attachments[i]->vk.aspects & VK_IMAGE_ASPECT_COLOR_BIT) 24527ec681f3Smrg framebuffer->color_attachment_count++; 24537ec681f3Smrg } 24547ec681f3Smrg 24557ec681f3Smrg *pFramebuffer = v3dv_framebuffer_to_handle(framebuffer); 24567ec681f3Smrg 24577ec681f3Smrg return VK_SUCCESS; 24587ec681f3Smrg} 24597ec681f3Smrg 24607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 24617ec681f3Smrgv3dv_DestroyFramebuffer(VkDevice _device, 24627ec681f3Smrg VkFramebuffer _fb, 24637ec681f3Smrg const VkAllocationCallbacks *pAllocator) 24647ec681f3Smrg{ 24657ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 24667ec681f3Smrg V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb); 24677ec681f3Smrg 24687ec681f3Smrg if (!fb) 24697ec681f3Smrg return; 24707ec681f3Smrg 24717ec681f3Smrg vk_object_free(&device->vk, pAllocator, fb); 24727ec681f3Smrg} 24737ec681f3Smrg 24747ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24757ec681f3Smrgv3dv_GetMemoryFdPropertiesKHR(VkDevice _device, 24767ec681f3Smrg VkExternalMemoryHandleTypeFlagBits handleType, 24777ec681f3Smrg int fd, 24787ec681f3Smrg VkMemoryFdPropertiesKHR *pMemoryFdProperties) 24797ec681f3Smrg{ 24807ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 24817ec681f3Smrg struct v3dv_physical_device *pdevice = &device->instance->physicalDevice; 24827ec681f3Smrg 24837ec681f3Smrg switch (handleType) { 24847ec681f3Smrg case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: 24857ec681f3Smrg pMemoryFdProperties->memoryTypeBits = 24867ec681f3Smrg (1 << pdevice->memory.memoryTypeCount) - 1; 24877ec681f3Smrg return VK_SUCCESS; 24887ec681f3Smrg default: 24897ec681f3Smrg return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE); 24907ec681f3Smrg } 24917ec681f3Smrg} 24927ec681f3Smrg 24937ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24947ec681f3Smrgv3dv_GetMemoryFdKHR(VkDevice _device, 24957ec681f3Smrg const VkMemoryGetFdInfoKHR *pGetFdInfo, 24967ec681f3Smrg int *pFd) 24977ec681f3Smrg{ 24987ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 24997ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory); 25007ec681f3Smrg 25017ec681f3Smrg assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR); 25027ec681f3Smrg assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT || 25037ec681f3Smrg pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); 25047ec681f3Smrg 25057ec681f3Smrg int fd, ret; 25067ec681f3Smrg ret = drmPrimeHandleToFD(device->pdevice->render_fd, 25077ec681f3Smrg mem->bo->handle, 25087ec681f3Smrg DRM_CLOEXEC, &fd); 25097ec681f3Smrg if (ret) 25107ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 25117ec681f3Smrg 25127ec681f3Smrg *pFd = fd; 25137ec681f3Smrg 25147ec681f3Smrg return VK_SUCCESS; 25157ec681f3Smrg} 25167ec681f3Smrg 25177ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25187ec681f3Smrgv3dv_CreateEvent(VkDevice _device, 25197ec681f3Smrg const VkEventCreateInfo *pCreateInfo, 25207ec681f3Smrg const VkAllocationCallbacks *pAllocator, 25217ec681f3Smrg VkEvent *pEvent) 25227ec681f3Smrg{ 25237ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 25247ec681f3Smrg struct v3dv_event *event = 25257ec681f3Smrg vk_object_zalloc(&device->vk, pAllocator, sizeof(*event), 25267ec681f3Smrg VK_OBJECT_TYPE_EVENT); 25277ec681f3Smrg if (!event) 25287ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 25297ec681f3Smrg 25307ec681f3Smrg /* Events are created in the unsignaled state */ 25317ec681f3Smrg event->state = false; 25327ec681f3Smrg *pEvent = v3dv_event_to_handle(event); 25337ec681f3Smrg 25347ec681f3Smrg return VK_SUCCESS; 25357ec681f3Smrg} 25367ec681f3Smrg 25377ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 25387ec681f3Smrgv3dv_DestroyEvent(VkDevice _device, 25397ec681f3Smrg VkEvent _event, 25407ec681f3Smrg const VkAllocationCallbacks *pAllocator) 25417ec681f3Smrg{ 25427ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 25437ec681f3Smrg V3DV_FROM_HANDLE(v3dv_event, event, _event); 25447ec681f3Smrg 25457ec681f3Smrg if (!event) 25467ec681f3Smrg return; 25477ec681f3Smrg 25487ec681f3Smrg vk_object_free(&device->vk, pAllocator, event); 25497ec681f3Smrg} 25507ec681f3Smrg 25517ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25527ec681f3Smrgv3dv_GetEventStatus(VkDevice _device, VkEvent _event) 25537ec681f3Smrg{ 25547ec681f3Smrg V3DV_FROM_HANDLE(v3dv_event, event, _event); 25557ec681f3Smrg return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET; 25567ec681f3Smrg} 25577ec681f3Smrg 25587ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25597ec681f3Smrgv3dv_SetEvent(VkDevice _device, VkEvent _event) 25607ec681f3Smrg{ 25617ec681f3Smrg V3DV_FROM_HANDLE(v3dv_event, event, _event); 25627ec681f3Smrg p_atomic_set(&event->state, 1); 25637ec681f3Smrg return VK_SUCCESS; 25647ec681f3Smrg} 25657ec681f3Smrg 25667ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25677ec681f3Smrgv3dv_ResetEvent(VkDevice _device, VkEvent _event) 25687ec681f3Smrg{ 25697ec681f3Smrg V3DV_FROM_HANDLE(v3dv_event, event, _event); 25707ec681f3Smrg p_atomic_set(&event->state, 0); 25717ec681f3Smrg return VK_SUCCESS; 25727ec681f3Smrg} 25737ec681f3Smrg 25747ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25757ec681f3Smrgv3dv_CreateSampler(VkDevice _device, 25767ec681f3Smrg const VkSamplerCreateInfo *pCreateInfo, 25777ec681f3Smrg const VkAllocationCallbacks *pAllocator, 25787ec681f3Smrg VkSampler *pSampler) 25797ec681f3Smrg{ 25807ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 25817ec681f3Smrg struct v3dv_sampler *sampler; 25827ec681f3Smrg 25837ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); 25847ec681f3Smrg 25857ec681f3Smrg sampler = vk_object_zalloc(&device->vk, pAllocator, sizeof(*sampler), 25867ec681f3Smrg VK_OBJECT_TYPE_SAMPLER); 25877ec681f3Smrg if (!sampler) 25887ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 25897ec681f3Smrg 25907ec681f3Smrg sampler->compare_enable = pCreateInfo->compareEnable; 25917ec681f3Smrg sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates; 25927ec681f3Smrg 25937ec681f3Smrg const VkSamplerCustomBorderColorCreateInfoEXT *bc_info = 25947ec681f3Smrg vk_find_struct_const(pCreateInfo->pNext, 25957ec681f3Smrg SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT); 25967ec681f3Smrg 25977ec681f3Smrg v3dv_X(device, pack_sampler_state)(sampler, pCreateInfo, bc_info); 25987ec681f3Smrg 25997ec681f3Smrg *pSampler = v3dv_sampler_to_handle(sampler); 26007ec681f3Smrg 26017ec681f3Smrg return VK_SUCCESS; 26027ec681f3Smrg} 26037ec681f3Smrg 26047ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 26057ec681f3Smrgv3dv_DestroySampler(VkDevice _device, 26067ec681f3Smrg VkSampler _sampler, 26077ec681f3Smrg const VkAllocationCallbacks *pAllocator) 26087ec681f3Smrg{ 26097ec681f3Smrg V3DV_FROM_HANDLE(v3dv_device, device, _device); 26107ec681f3Smrg V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler); 26117ec681f3Smrg 26127ec681f3Smrg if (!sampler) 26137ec681f3Smrg return; 26147ec681f3Smrg 26157ec681f3Smrg vk_object_free(&device->vk, pAllocator, sampler); 26167ec681f3Smrg} 26177ec681f3Smrg 26187ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 26197ec681f3Smrgv3dv_GetDeviceMemoryCommitment(VkDevice device, 26207ec681f3Smrg VkDeviceMemory memory, 26217ec681f3Smrg VkDeviceSize *pCommittedMemoryInBytes) 26227ec681f3Smrg{ 26237ec681f3Smrg *pCommittedMemoryInBytes = 0; 26247ec681f3Smrg} 26257ec681f3Smrg 26267ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 26277ec681f3Smrgv3dv_GetImageSparseMemoryRequirements( 26287ec681f3Smrg VkDevice device, 26297ec681f3Smrg VkImage image, 26307ec681f3Smrg uint32_t *pSparseMemoryRequirementCount, 26317ec681f3Smrg VkSparseImageMemoryRequirements *pSparseMemoryRequirements) 26327ec681f3Smrg{ 26337ec681f3Smrg *pSparseMemoryRequirementCount = 0; 26347ec681f3Smrg} 26357ec681f3Smrg 26367ec681f3SmrgVKAPI_ATTR void VKAPI_CALL 26377ec681f3Smrgv3dv_GetImageSparseMemoryRequirements2( 26387ec681f3Smrg VkDevice device, 26397ec681f3Smrg const VkImageSparseMemoryRequirementsInfo2 *pInfo, 26407ec681f3Smrg uint32_t *pSparseMemoryRequirementCount, 26417ec681f3Smrg VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) 26427ec681f3Smrg{ 26437ec681f3Smrg *pSparseMemoryRequirementCount = 0; 26447ec681f3Smrg} 26457ec681f3Smrg 26467ec681f3Smrg/* vk_icd.h does not declare this function, so we declare it here to 26477ec681f3Smrg * suppress Wmissing-prototypes. 26487ec681f3Smrg */ 26497ec681f3SmrgPUBLIC VKAPI_ATTR VkResult VKAPI_CALL 26507ec681f3Smrgvk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion); 26517ec681f3Smrg 26527ec681f3SmrgPUBLIC VKAPI_ATTR VkResult VKAPI_CALL 26537ec681f3Smrgvk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion) 26547ec681f3Smrg{ 26557ec681f3Smrg /* For the full details on loader interface versioning, see 26567ec681f3Smrg * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>. 26577ec681f3Smrg * What follows is a condensed summary, to help you navigate the large and 26587ec681f3Smrg * confusing official doc. 26597ec681f3Smrg * 26607ec681f3Smrg * - Loader interface v0 is incompatible with later versions. We don't 26617ec681f3Smrg * support it. 26627ec681f3Smrg * 26637ec681f3Smrg * - In loader interface v1: 26647ec681f3Smrg * - The first ICD entrypoint called by the loader is 26657ec681f3Smrg * vk_icdGetInstanceProcAddr(). The ICD must statically expose this 26667ec681f3Smrg * entrypoint. 26677ec681f3Smrg * - The ICD must statically expose no other Vulkan symbol unless it is 26687ec681f3Smrg * linked with -Bsymbolic. 26697ec681f3Smrg * - Each dispatchable Vulkan handle created by the ICD must be 26707ec681f3Smrg * a pointer to a struct whose first member is VK_LOADER_DATA. The 26717ec681f3Smrg * ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC. 26727ec681f3Smrg * - The loader implements vkCreate{PLATFORM}SurfaceKHR() and 26737ec681f3Smrg * vkDestroySurfaceKHR(). The ICD must be capable of working with 26747ec681f3Smrg * such loader-managed surfaces. 26757ec681f3Smrg * 26767ec681f3Smrg * - Loader interface v2 differs from v1 in: 26777ec681f3Smrg * - The first ICD entrypoint called by the loader is 26787ec681f3Smrg * vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must 26797ec681f3Smrg * statically expose this entrypoint. 26807ec681f3Smrg * 26817ec681f3Smrg * - Loader interface v3 differs from v2 in: 26827ec681f3Smrg * - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(), 26837ec681f3Smrg * vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR, 26847ec681f3Smrg * because the loader no longer does so. 26857ec681f3Smrg * 26867ec681f3Smrg * - Loader interface v4 differs from v3 in: 26877ec681f3Smrg * - The ICD must implement vk_icdGetPhysicalDeviceProcAddr(). 26887ec681f3Smrg */ 26897ec681f3Smrg *pSupportedVersion = MIN2(*pSupportedVersion, 3u); 26907ec681f3Smrg return VK_SUCCESS; 26917ec681f3Smrg} 2692