Path: blob/21.2-virgl/src/broadcom/vulkan/v3dv_device.c
4560 views
/*1* Copyright © 2019 Raspberry Pi2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <assert.h>24#include <fcntl.h>25#include <stdbool.h>26#include <string.h>27#include <sys/mman.h>28#include <sys/sysinfo.h>29#include <unistd.h>30#include <xf86drm.h>3132#include "v3dv_private.h"3334#include "common/v3d_debug.h"3536#include "compiler/v3d_compiler.h"3738#include "drm-uapi/v3d_drm.h"39#include "format/u_format.h"40#include "vk_util.h"4142#include "util/build_id.h"43#include "util/debug.h"44#include "util/u_cpu_detect.h"4546#ifdef VK_USE_PLATFORM_XCB_KHR47#include <xcb/xcb.h>48#include <xcb/dri3.h>49#include <X11/Xlib-xcb.h>50#endif5152#ifdef VK_USE_PLATFORM_WAYLAND_KHR53#include <wayland-client.h>54#include "wayland-drm-client-protocol.h"55#endif5657#ifdef USE_V3D_SIMULATOR58#include "drm-uapi/i915_drm.h"59#endif6061#define V3DV_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)6263VKAPI_ATTR VkResult VKAPI_CALL64v3dv_EnumerateInstanceVersion(uint32_t *pApiVersion)65{66*pApiVersion = V3DV_API_VERSION;67return VK_SUCCESS;68}6970#define V3DV_HAS_SURFACE (VK_USE_PLATFORM_WIN32_KHR || \71VK_USE_PLATFORM_WAYLAND_KHR || \72VK_USE_PLATFORM_XCB_KHR || \73VK_USE_PLATFORM_XLIB_KHR || \74VK_USE_PLATFORM_DISPLAY_KHR)7576static const struct vk_instance_extension_table instance_extensions = {77.KHR_device_group_creation = true,78#ifdef VK_USE_PLATFORM_DISPLAY_KHR79.KHR_display = true,80#endif81.KHR_external_fence_capabilities = true,82.KHR_external_memory_capabilities = true,83.KHR_external_semaphore_capabilities = true,84.KHR_get_display_properties2 = true,85.KHR_get_physical_device_properties2 = true,86#ifdef V3DV_HAS_SURFACE87.KHR_get_surface_capabilities2 = true,88.KHR_surface = true,89#endif90#ifdef VK_USE_PLATFORM_WAYLAND_KHR91.KHR_wayland_surface = true,92#endif93#ifdef VK_USE_PLATFORM_XCB_KHR94.KHR_xcb_surface = true,95#endif96#ifdef VK_USE_PLATFORM_XLIB_KHR97.KHR_xlib_surface = true,98#endif99.EXT_debug_report = true,100};101102static void103get_device_extensions(const struct v3dv_physical_device *device,104struct vk_device_extension_table *ext)105{106*ext = (struct vk_device_extension_table) {107.KHR_bind_memory2 = true,108.KHR_copy_commands2 = true,109.KHR_dedicated_allocation = true,110.KHR_device_group = true,111.KHR_descriptor_update_template = true,112.KHR_external_fence = true,113.KHR_external_fence_fd = true,114.KHR_external_memory = true,115.KHR_external_memory_fd = true,116.KHR_external_semaphore = true,117.KHR_external_semaphore_fd = true,118.KHR_get_memory_requirements2 = true,119.KHR_image_format_list = true,120.KHR_relaxed_block_layout = true,121.KHR_maintenance1 = true,122.KHR_maintenance2 = true,123.KHR_maintenance3 = true,124.KHR_shader_non_semantic_info = true,125.KHR_sampler_mirror_clamp_to_edge = true,126.KHR_storage_buffer_storage_class = true,127.KHR_uniform_buffer_standard_layout = true,128#ifdef V3DV_HAS_SURFACE129.KHR_swapchain = true,130.KHR_incremental_present = true,131#endif132.KHR_variable_pointers = true,133.EXT_external_memory_dma_buf = true,134.EXT_index_type_uint8 = true,135.EXT_private_data = true,136};137}138139VKAPI_ATTR VkResult VKAPI_CALL140v3dv_EnumerateInstanceExtensionProperties(const char *pLayerName,141uint32_t *pPropertyCount,142VkExtensionProperties *pProperties)143{144/* We don't support any layers */145if (pLayerName)146return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);147148return vk_enumerate_instance_extension_properties(149&instance_extensions, pPropertyCount, pProperties);150}151152VKAPI_ATTR VkResult VKAPI_CALL153v3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,154const VkAllocationCallbacks *pAllocator,155VkInstance *pInstance)156{157struct v3dv_instance *instance;158VkResult result;159160assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);161162if (pAllocator == NULL)163pAllocator = vk_default_allocator();164165instance = vk_alloc(pAllocator, sizeof(*instance), 8,166VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);167if (!instance)168return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);169170struct vk_instance_dispatch_table dispatch_table;171vk_instance_dispatch_table_from_entrypoints(172&dispatch_table, &v3dv_instance_entrypoints, true);173174result = vk_instance_init(&instance->vk,175&instance_extensions,176&dispatch_table,177pCreateInfo, pAllocator);178179if (result != VK_SUCCESS) {180vk_free(pAllocator, instance);181return vk_error(instance, result);182}183184v3d_process_debug_variable();185186instance->physicalDeviceCount = -1;187188/* We start with the default values for the pipeline_cache envvars */189instance->pipeline_cache_enabled = true;190instance->default_pipeline_cache_enabled = true;191const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE");192if (pipeline_cache_str != NULL) {193if (strncmp(pipeline_cache_str, "full", 4) == 0) {194/* nothing to do, just to filter correct values */195} else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) {196instance->default_pipeline_cache_enabled = false;197} else if (strncmp(pipeline_cache_str, "off", 3) == 0) {198instance->pipeline_cache_enabled = false;199instance->default_pipeline_cache_enabled = false;200} else {201fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. "202"Allowed values are: full, no-default-cache, off\n");203}204}205206if (instance->pipeline_cache_enabled == false) {207fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance "208"can be affected negatively\n");209} else {210if (instance->default_pipeline_cache_enabled == false) {211fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. "212"Performance can be affected negatively\n");213}214}215216util_cpu_detect();217218VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));219220*pInstance = v3dv_instance_to_handle(instance);221222return VK_SUCCESS;223}224225static void226v3dv_physical_device_free_disk_cache(struct v3dv_physical_device *device)227{228#ifdef ENABLE_SHADER_CACHE229if (device->disk_cache)230disk_cache_destroy(device->disk_cache);231#else232assert(device->disk_cache == NULL);233#endif234}235236static void237physical_device_finish(struct v3dv_physical_device *device)238{239v3dv_wsi_finish(device);240v3dv_physical_device_free_disk_cache(device);241v3d_compiler_free(device->compiler);242243close(device->render_fd);244if (device->display_fd >= 0)245close(device->display_fd);246if (device->master_fd >= 0)247close(device->master_fd);248249free(device->name);250251#if using_v3d_simulator252v3d_simulator_destroy(device->sim_file);253#endif254255vk_physical_device_finish(&device->vk);256mtx_destroy(&device->mutex);257}258259VKAPI_ATTR void VKAPI_CALL260v3dv_DestroyInstance(VkInstance _instance,261const VkAllocationCallbacks *pAllocator)262{263V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);264265if (!instance)266return;267268if (instance->physicalDeviceCount > 0) {269/* We support at most one physical device. */270assert(instance->physicalDeviceCount == 1);271physical_device_finish(&instance->physicalDevice);272}273274VG(VALGRIND_DESTROY_MEMPOOL(instance));275276vk_instance_finish(&instance->vk);277vk_free(&instance->vk.alloc, instance);278}279280static uint64_t281compute_heap_size()282{283#if !using_v3d_simulator284/* Query the total ram from the system */285struct sysinfo info;286sysinfo(&info);287288uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;289#else290uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size();291#endif292293/* We don't want to burn too much ram with the GPU. If the user has 4GiB294* or less, we use at most half. If they have more than 4GiB, we use 3/4.295*/296uint64_t available_ram;297if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull)298available_ram = total_ram / 2;299else300available_ram = total_ram * 3 / 4;301302return available_ram;303}304305#if !using_v3d_simulator306#ifdef VK_USE_PLATFORM_XCB_KHR307static int308create_display_fd_xcb(VkIcdSurfaceBase *surface)309{310int fd = -1;311312xcb_connection_t *conn;313xcb_dri3_open_reply_t *reply = NULL;314if (surface) {315if (surface->platform == VK_ICD_WSI_PLATFORM_XLIB)316conn = XGetXCBConnection(((VkIcdSurfaceXlib *)surface)->dpy);317else318conn = ((VkIcdSurfaceXcb *)surface)->connection;319} else {320conn = xcb_connect(NULL, NULL);321}322323if (xcb_connection_has_error(conn))324goto finish;325326const xcb_setup_t *setup = xcb_get_setup(conn);327xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);328xcb_screen_t *screen = iter.data;329330xcb_dri3_open_cookie_t cookie;331cookie = xcb_dri3_open(conn, screen->root, None);332reply = xcb_dri3_open_reply(conn, cookie, NULL);333if (!reply)334goto finish;335336if (reply->nfd != 1)337goto finish;338339fd = xcb_dri3_open_reply_fds(conn, reply)[0];340fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);341342finish:343if (!surface)344xcb_disconnect(conn);345if (reply)346free(reply);347348return fd;349}350#endif351352#ifdef VK_USE_PLATFORM_WAYLAND_KHR353struct v3dv_wayland_info {354struct wl_drm *wl_drm;355int fd;356bool is_set;357bool authenticated;358};359360static void361v3dv_drm_handle_device(void *data, struct wl_drm *drm, const char *device)362{363struct v3dv_wayland_info *info = data;364info->fd = open(device, O_RDWR | O_CLOEXEC);365info->is_set = info->fd != -1;366if (!info->is_set) {367fprintf(stderr, "v3dv_drm_handle_device: could not open %s (%s)\n",368device, strerror(errno));369return;370}371372drm_magic_t magic;373if (drmGetMagic(info->fd, &magic)) {374fprintf(stderr, "v3dv_drm_handle_device: drmGetMagic failed\n");375close(info->fd);376info->fd = -1;377info->is_set = false;378return;379}380wl_drm_authenticate(info->wl_drm, magic);381}382383static void384v3dv_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)385{386}387388static void389v3dv_drm_handle_authenticated(void *data, struct wl_drm *drm)390{391struct v3dv_wayland_info *info = data;392info->authenticated = true;393}394395static void396v3dv_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)397{398}399400struct wl_drm_listener v3dv_drm_listener = {401.device = v3dv_drm_handle_device,402.format = v3dv_drm_handle_format,403.authenticated = v3dv_drm_handle_authenticated,404.capabilities = v3dv_drm_handle_capabilities405};406407static void408v3dv_registry_global(void *data,409struct wl_registry *registry,410uint32_t name,411const char *interface,412uint32_t version)413{414struct v3dv_wayland_info *info = data;415if (strcmp(interface, "wl_drm") == 0) {416info->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface,417MIN2(version, 2));418wl_drm_add_listener(info->wl_drm, &v3dv_drm_listener, data);419};420}421422static void423v3dv_registry_global_remove_cb(void *data,424struct wl_registry *registry,425uint32_t name)426{427}428429static int430create_display_fd_wayland(VkIcdSurfaceBase *surface)431{432struct wl_display *display;433struct wl_registry *registry = NULL;434435struct v3dv_wayland_info info = {436.wl_drm = NULL,437.fd = -1,438.is_set = false,439.authenticated = false440};441442if (surface)443display = ((VkIcdSurfaceWayland *) surface)->display;444else445display = wl_display_connect(NULL);446447if (!display)448return -1;449450registry = wl_display_get_registry(display);451if (!registry) {452if (!surface)453wl_display_disconnect(display);454return -1;455}456457static const struct wl_registry_listener registry_listener = {458v3dv_registry_global,459v3dv_registry_global_remove_cb460};461wl_registry_add_listener(registry, ®istry_listener, &info);462463wl_display_roundtrip(display); /* For the registry advertisement */464wl_display_roundtrip(display); /* For the DRM device event */465wl_display_roundtrip(display); /* For the authentication event */466467wl_drm_destroy(info.wl_drm);468wl_registry_destroy(registry);469470if (!surface)471wl_display_disconnect(display);472473if (!info.is_set)474return -1;475476if (!info.authenticated)477return -1;478479return info.fd;480}481#endif482483/* Acquire an authenticated display fd without a surface reference. This is the484* case where the application is making WSI allocations outside the Vulkan485* swapchain context (only Zink, for now). Since we lack information about the486* underlying surface we just try our best to figure out the correct display487* and platform to use. It should work in most cases.488*/489static void490acquire_display_device_no_surface(struct v3dv_instance *instance,491struct v3dv_physical_device *pdevice)492{493#ifdef VK_USE_PLATFORM_WAYLAND_KHR494pdevice->display_fd = create_display_fd_wayland(NULL);495#endif496497#ifdef VK_USE_PLATFORM_XCB_KHR498if (pdevice->display_fd == -1)499pdevice->display_fd = create_display_fd_xcb(NULL);500#endif501502#ifdef VK_USE_PLATFORM_DISPLAY_KHR503if (pdevice->display_fd == - 1 && pdevice->master_fd >= 0)504pdevice->display_fd = dup(pdevice->master_fd);505#endif506}507508/* Acquire an authenticated display fd from the surface. This is the regular509* case where the application is using swapchains to create WSI allocations.510* In this case we use the surface information to figure out the correct511* display and platform combination.512*/513static void514acquire_display_device_surface(struct v3dv_instance *instance,515struct v3dv_physical_device *pdevice,516VkIcdSurfaceBase *surface)517{518/* Mesa will set both of VK_USE_PLATFORM_{XCB,XLIB} when building with519* platform X11, so only check for XCB and rely on XCB to get an520* authenticated device also for Xlib.521*/522#ifdef VK_USE_PLATFORM_XCB_KHR523if (surface->platform == VK_ICD_WSI_PLATFORM_XCB ||524surface->platform == VK_ICD_WSI_PLATFORM_XLIB) {525pdevice->display_fd = create_display_fd_xcb(surface);526}527#endif528529#ifdef VK_USE_PLATFORM_WAYLAND_KHR530if (surface->platform == VK_ICD_WSI_PLATFORM_WAYLAND)531pdevice->display_fd = create_display_fd_wayland(surface);532#endif533534#ifdef VK_USE_PLATFORM_DISPLAY_KHR535if (surface->platform == VK_ICD_WSI_PLATFORM_DISPLAY &&536pdevice->master_fd >= 0) {537pdevice->display_fd = dup(pdevice->master_fd);538}539#endif540}541#endif /* !using_v3d_simulator */542543/* Attempts to get an authenticated display fd from the display server that544* we can use to allocate BOs for presentable images.545*/546VkResult547v3dv_physical_device_acquire_display(struct v3dv_instance *instance,548struct v3dv_physical_device *pdevice,549VkIcdSurfaceBase *surface)550{551VkResult result = VK_SUCCESS;552mtx_lock(&pdevice->mutex);553554if (pdevice->display_fd != -1)555goto done;556557/* When running on the simulator we do everything on a single render node so558* we don't need to get an authenticated display fd from the display server.559*/560#if !using_v3d_simulator561if (surface)562acquire_display_device_surface(instance, pdevice, surface);563else564acquire_display_device_no_surface(instance, pdevice);565566if (pdevice->display_fd == -1)567result = VK_ERROR_INITIALIZATION_FAILED;568#endif569570done:571mtx_unlock(&pdevice->mutex);572return result;573}574575static bool576v3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature)577{578struct drm_v3d_get_param p = {579.param = feature,580};581if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0)582return false;583return p.value;584}585586static bool587device_has_expected_features(struct v3dv_physical_device *device)588{589return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) &&590v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) &&591v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);592}593594595static VkResult596init_uuids(struct v3dv_physical_device *device)597{598const struct build_id_note *note =599build_id_find_nhdr_for_addr(init_uuids);600if (!note) {601return vk_errorf((struct v3dv_instance*) device->vk.instance,602VK_ERROR_INITIALIZATION_FAILED,603"Failed to find build-id");604}605606unsigned build_id_len = build_id_length(note);607if (build_id_len < 20) {608return vk_errorf((struct v3dv_instance*) device->vk.instance,609VK_ERROR_INITIALIZATION_FAILED,610"build-id too short. It needs to be a SHA");611}612613memcpy(device->driver_build_sha1, build_id_data(note), 20);614615uint32_t vendor_id = v3dv_physical_device_vendor_id(device);616uint32_t device_id = v3dv_physical_device_device_id(device);617618struct mesa_sha1 sha1_ctx;619uint8_t sha1[20];620STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));621622/* The pipeline cache UUID is used for determining when a pipeline cache is623* invalid. It needs both a driver build and the PCI ID of the device.624*/625_mesa_sha1_init(&sha1_ctx);626_mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);627_mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));628_mesa_sha1_final(&sha1_ctx, sha1);629memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);630631/* The driver UUID is used for determining sharability of images and memory632* between two Vulkan instances in separate processes. People who want to633* share memory need to also check the device UUID (below) so all this634* needs to be is the build-id.635*/636memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE);637638/* The device UUID uniquely identifies the given device within the machine.639* Since we never have more than one device, this doesn't need to be a real640* UUID.641*/642_mesa_sha1_init(&sha1_ctx);643_mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id));644_mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));645_mesa_sha1_final(&sha1_ctx, sha1);646memcpy(device->device_uuid, sha1, VK_UUID_SIZE);647648return VK_SUCCESS;649}650651static void652v3dv_physical_device_init_disk_cache(struct v3dv_physical_device *device)653{654#ifdef ENABLE_SHADER_CACHE655char timestamp[41];656_mesa_sha1_format(timestamp, device->driver_build_sha1);657658assert(device->name);659device->disk_cache = disk_cache_create(device->name, timestamp, 0);660#else661device->disk_cache = NULL;662#endif663}664665static VkResult666physical_device_init(struct v3dv_physical_device *device,667struct v3dv_instance *instance,668drmDevicePtr drm_render_device,669drmDevicePtr drm_primary_device)670{671VkResult result = VK_SUCCESS;672int32_t master_fd = -1;673int32_t render_fd = -1;674675struct vk_physical_device_dispatch_table dispatch_table;676vk_physical_device_dispatch_table_from_entrypoints677(&dispatch_table, &v3dv_physical_device_entrypoints, true);678679result = vk_physical_device_init(&device->vk, &instance->vk, NULL,680&dispatch_table);681682if (result != VK_SUCCESS)683goto fail;684685assert(drm_render_device);686const char *path = drm_render_device->nodes[DRM_NODE_RENDER];687render_fd = open(path, O_RDWR | O_CLOEXEC);688if (render_fd < 0) {689fprintf(stderr, "Opening %s failed: %s\n", path, strerror(errno));690result = VK_ERROR_INCOMPATIBLE_DRIVER;691goto fail;692}693694/* If we are running on VK_KHR_display we need to acquire the master695* display device now for the v3dv_wsi_init() call below. For anything else696* we postpone that until a swapchain is created.697*/698699if (instance->vk.enabled_extensions.KHR_display) {700#if !using_v3d_simulator701/* Open the primary node on the vc4 display device */702assert(drm_primary_device);703const char *primary_path = drm_primary_device->nodes[DRM_NODE_PRIMARY];704master_fd = open(primary_path, O_RDWR | O_CLOEXEC);705#else706/* There is only one device with primary and render nodes.707* Open its primary node.708*/709const char *primary_path = drm_render_device->nodes[DRM_NODE_PRIMARY];710master_fd = open(primary_path, O_RDWR | O_CLOEXEC);711#endif712}713714#if using_v3d_simulator715device->sim_file = v3d_simulator_init(render_fd);716#endif717718device->render_fd = render_fd; /* The v3d render node */719device->display_fd = -1; /* Authenticated vc4 primary node */720device->master_fd = master_fd; /* Master vc4 primary node */721722if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {723result = VK_ERROR_INCOMPATIBLE_DRIVER;724goto fail;725}726727if (device->devinfo.ver < 42) {728result = VK_ERROR_INCOMPATIBLE_DRIVER;729goto fail;730}731732if (!device_has_expected_features(device)) {733result = VK_ERROR_INCOMPATIBLE_DRIVER;734goto fail;735}736737result = init_uuids(device);738if (result != VK_SUCCESS)739goto fail;740741device->compiler = v3d_compiler_init(&device->devinfo);742device->next_program_id = 0;743744ASSERTED int len =745asprintf(&device->name, "V3D %d.%d",746device->devinfo.ver / 10, device->devinfo.ver % 10);747assert(len != -1);748749v3dv_physical_device_init_disk_cache(device);750751/* Setup available memory heaps and types */752VkPhysicalDeviceMemoryProperties *mem = &device->memory;753mem->memoryHeapCount = 1;754mem->memoryHeaps[0].size = compute_heap_size();755mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;756757/* This is the only combination required by the spec */758mem->memoryTypeCount = 1;759mem->memoryTypes[0].propertyFlags =760VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |761VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |762VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;763mem->memoryTypes[0].heapIndex = 0;764765device->options.merge_jobs = getenv("V3DV_NO_MERGE_JOBS") == NULL;766767result = v3dv_wsi_init(device);768if (result != VK_SUCCESS) {769vk_error(instance, result);770goto fail;771}772773get_device_extensions(device, &device->vk.supported_extensions);774775pthread_mutex_init(&device->mutex, NULL);776777return VK_SUCCESS;778779fail:780vk_physical_device_finish(&device->vk);781782if (render_fd >= 0)783close(render_fd);784if (master_fd >= 0)785close(master_fd);786787return result;788}789790static VkResult791enumerate_devices(struct v3dv_instance *instance)792{793/* TODO: Check for more devices? */794drmDevicePtr devices[8];795VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;796int max_devices;797798instance->physicalDeviceCount = 0;799800max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));801if (max_devices < 1)802return VK_ERROR_INCOMPATIBLE_DRIVER;803804#if !using_v3d_simulator805int32_t v3d_idx = -1;806int32_t vc4_idx = -1;807#endif808for (unsigned i = 0; i < (unsigned)max_devices; i++) {809#if using_v3d_simulator810/* In the simulator, we look for an Intel render node */811const int required_nodes = (1 << DRM_NODE_RENDER) | (1 << DRM_NODE_PRIMARY);812if ((devices[i]->available_nodes & required_nodes) == required_nodes &&813devices[i]->bustype == DRM_BUS_PCI &&814devices[i]->deviceinfo.pci->vendor_id == 0x8086) {815result = physical_device_init(&instance->physicalDevice, instance,816devices[i], NULL);817if (result != VK_ERROR_INCOMPATIBLE_DRIVER)818break;819}820#else821/* On actual hardware, we should have a render node (v3d)822* and a primary node (vc4). We will need to use the primary823* to allocate WSI buffers and share them with the render node824* via prime, but that is a privileged operation so we need the825* primary node to be authenticated, and for that we need the826* display server to provide the device fd (with DRI3), so we827* here we only check that the device is present but we don't828* try to open it.829*/830if (devices[i]->bustype != DRM_BUS_PLATFORM)831continue;832833if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) {834char **compat = devices[i]->deviceinfo.platform->compatible;835while (*compat) {836if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) {837v3d_idx = i;838break;839}840compat++;841}842} else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) {843char **compat = devices[i]->deviceinfo.platform->compatible;844while (*compat) {845if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 ||846strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) {847vc4_idx = i;848break;849}850compat++;851}852}853#endif854}855856#if !using_v3d_simulator857if (v3d_idx == -1 || vc4_idx == -1)858result = VK_ERROR_INCOMPATIBLE_DRIVER;859else860result = physical_device_init(&instance->physicalDevice, instance,861devices[v3d_idx], devices[vc4_idx]);862#endif863864drmFreeDevices(devices, max_devices);865866if (result == VK_SUCCESS)867instance->physicalDeviceCount = 1;868869return result;870}871872static VkResult873instance_ensure_physical_device(struct v3dv_instance *instance)874{875if (instance->physicalDeviceCount < 0) {876VkResult result = enumerate_devices(instance);877if (result != VK_SUCCESS &&878result != VK_ERROR_INCOMPATIBLE_DRIVER)879return result;880}881882return VK_SUCCESS;883}884885VKAPI_ATTR VkResult VKAPI_CALL886v3dv_EnumeratePhysicalDevices(VkInstance _instance,887uint32_t *pPhysicalDeviceCount,888VkPhysicalDevice *pPhysicalDevices)889{890V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);891VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);892893VkResult result = instance_ensure_physical_device(instance);894if (result != VK_SUCCESS)895return result;896897if (instance->physicalDeviceCount == 0)898return VK_SUCCESS;899900assert(instance->physicalDeviceCount == 1);901vk_outarray_append(&out, i) {902*i = v3dv_physical_device_to_handle(&instance->physicalDevice);903}904905return vk_outarray_status(&out);906}907908VKAPI_ATTR VkResult VKAPI_CALL909v3dv_EnumeratePhysicalDeviceGroups(910VkInstance _instance,911uint32_t *pPhysicalDeviceGroupCount,912VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)913{914V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);915VK_OUTARRAY_MAKE(out, pPhysicalDeviceGroupProperties,916pPhysicalDeviceGroupCount);917918VkResult result = instance_ensure_physical_device(instance);919if (result != VK_SUCCESS)920return result;921922assert(instance->physicalDeviceCount == 1);923924vk_outarray_append(&out, p) {925p->physicalDeviceCount = 1;926memset(p->physicalDevices, 0, sizeof(p->physicalDevices));927p->physicalDevices[0] =928v3dv_physical_device_to_handle(&instance->physicalDevice);929p->subsetAllocation = false;930931vk_foreach_struct(ext, p->pNext)932v3dv_debug_ignored_stype(ext->sType);933}934935return vk_outarray_status(&out);936}937938VKAPI_ATTR void VKAPI_CALL939v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,940VkPhysicalDeviceFeatures *pFeatures)941{942memset(pFeatures, 0, sizeof(*pFeatures));943944*pFeatures = (VkPhysicalDeviceFeatures) {945.robustBufferAccess = true, /* This feature is mandatory */946.fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */947.imageCubeArray = true,948.independentBlend = true,949.geometryShader = true,950.tessellationShader = false,951.sampleRateShading = true,952.dualSrcBlend = false,953.logicOp = true,954.multiDrawIndirect = false,955.drawIndirectFirstInstance = true,956.depthClamp = false,957.depthBiasClamp = true,958.fillModeNonSolid = true,959.depthBounds = false, /* Only available since V3D 4.3.16.2 */960.wideLines = true,961.largePoints = true,962.alphaToOne = true,963.multiViewport = false,964.samplerAnisotropy = true,965.textureCompressionETC2 = true,966.textureCompressionASTC_LDR = true,967/* Note that textureCompressionBC requires that the driver support all968* the BC formats. V3D 4.2 only support the BC1-3, so we can't claim969* that we support it.970*/971.textureCompressionBC = false,972.occlusionQueryPrecise = true,973.pipelineStatisticsQuery = false,974.vertexPipelineStoresAndAtomics = true,975.fragmentStoresAndAtomics = true,976.shaderTessellationAndGeometryPointSize = true,977.shaderImageGatherExtended = false,978.shaderStorageImageExtendedFormats = true,979.shaderStorageImageMultisample = false,980.shaderStorageImageReadWithoutFormat = false,981.shaderStorageImageWriteWithoutFormat = false,982.shaderUniformBufferArrayDynamicIndexing = false,983.shaderSampledImageArrayDynamicIndexing = false,984.shaderStorageBufferArrayDynamicIndexing = false,985.shaderStorageImageArrayDynamicIndexing = false,986.shaderClipDistance = true,987.shaderCullDistance = false,988.shaderFloat64 = false,989.shaderInt64 = false,990.shaderInt16 = false,991.shaderResourceResidency = false,992.shaderResourceMinLod = false,993.sparseBinding = false,994.sparseResidencyBuffer = false,995.sparseResidencyImage2D = false,996.sparseResidencyImage3D = false,997.sparseResidency2Samples = false,998.sparseResidency4Samples = false,999.sparseResidency8Samples = false,1000.sparseResidency16Samples = false,1001.sparseResidencyAliased = false,1002.variableMultisampleRate = false,1003.inheritedQueries = true,1004};1005}10061007VKAPI_ATTR void VKAPI_CALL1008v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,1009VkPhysicalDeviceFeatures2 *pFeatures)1010{1011v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);10121013VkPhysicalDeviceVulkan11Features vk11 = {1014.storageBuffer16BitAccess = false,1015.uniformAndStorageBuffer16BitAccess = false,1016.storagePushConstant16 = false,1017.storageInputOutput16 = false,1018.multiview = false,1019.multiviewGeometryShader = false,1020.multiviewTessellationShader = false,1021.variablePointersStorageBuffer = true,1022/* FIXME: this needs support for non-constant index on UBO/SSBO */1023.variablePointers = false,1024.protectedMemory = false,1025.samplerYcbcrConversion = false,1026.shaderDrawParameters = false,1027};10281029vk_foreach_struct(ext, pFeatures->pNext) {1030switch (ext->sType) {1031case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {1032VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *features =1033(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *)ext;1034features->uniformBufferStandardLayout = true;1035break;1036}10371038case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: {1039VkPhysicalDevicePrivateDataFeaturesEXT *features =1040(VkPhysicalDevicePrivateDataFeaturesEXT *)ext;1041features->privateData = true;1042break;1043}10441045case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: {1046VkPhysicalDeviceIndexTypeUint8FeaturesEXT *features =1047(VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)ext;1048features->indexTypeUint8 = true;1049break;1050}10511052/* Vulkan 1.1 */1053case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: {1054VkPhysicalDeviceVulkan11Features *features =1055(VkPhysicalDeviceVulkan11Features *)ext;1056memcpy(features, &vk11, sizeof(VkPhysicalDeviceVulkan11Features));1057break;1058}1059case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {1060VkPhysicalDevice16BitStorageFeatures *features = (void *) ext;1061features->storageBuffer16BitAccess = vk11.storageBuffer16BitAccess;1062features->uniformAndStorageBuffer16BitAccess =1063vk11.uniformAndStorageBuffer16BitAccess;1064features->storagePushConstant16 = vk11.storagePushConstant16;1065features->storageInputOutput16 = vk11.storageInputOutput16;1066break;1067}1068case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {1069VkPhysicalDeviceMultiviewFeatures *features = (void *) ext;1070features->multiview = vk11.multiview;1071features->multiviewGeometryShader = vk11.multiviewGeometryShader;1072features->multiviewTessellationShader = vk11.multiviewTessellationShader;1073break;1074}1075case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: {1076VkPhysicalDeviceProtectedMemoryFeatures *features = (void *) ext;1077features->protectedMemory = vk11.protectedMemory;1078break;1079}1080case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {1081VkPhysicalDeviceSamplerYcbcrConversionFeatures *features = (void *) ext;1082features->samplerYcbcrConversion = vk11.samplerYcbcrConversion;1083break;1084}1085case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: {1086VkPhysicalDeviceShaderDrawParametersFeatures *features = (void *) ext;1087features->shaderDrawParameters = vk11.shaderDrawParameters;1088break;1089}1090case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: {1091VkPhysicalDeviceVariablePointersFeatures *features = (void *) ext;1092features->variablePointersStorageBuffer =1093vk11.variablePointersStorageBuffer;1094features->variablePointers = vk11.variablePointers;1095break;1096}10971098default:1099v3dv_debug_ignored_stype(ext->sType);1100break;1101}1102}1103}11041105VKAPI_ATTR void VKAPI_CALL1106v3dv_GetDeviceGroupPeerMemoryFeatures(VkDevice device,1107uint32_t heapIndex,1108uint32_t localDeviceIndex,1109uint32_t remoteDeviceIndex,1110VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)1111{1112assert(localDeviceIndex == 0 && remoteDeviceIndex == 0);1113*pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT |1114VK_PEER_MEMORY_FEATURE_COPY_DST_BIT |1115VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT |1116VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT;1117}11181119uint32_t1120v3dv_physical_device_vendor_id(struct v3dv_physical_device *dev)1121{1122return 0x14E4; /* Broadcom */1123}112411251126#if using_v3d_simulator1127static bool1128get_i915_param(int fd, uint32_t param, int *value)1129{1130int tmp;11311132struct drm_i915_getparam gp = {1133.param = param,1134.value = &tmp,1135};11361137int ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);1138if (ret != 0)1139return false;11401141*value = tmp;1142return true;1143}1144#endif11451146uint32_t1147v3dv_physical_device_device_id(struct v3dv_physical_device *dev)1148{1149#if using_v3d_simulator1150int devid = 0;11511152if (!get_i915_param(dev->render_fd, I915_PARAM_CHIPSET_ID, &devid))1153fprintf(stderr, "Error getting device_id\n");11541155return devid;1156#else1157return dev->devinfo.ver;1158#endif1159}11601161VKAPI_ATTR void VKAPI_CALL1162v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,1163VkPhysicalDeviceProperties *pProperties)1164{1165V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);11661167STATIC_ASSERT(MAX_SAMPLED_IMAGES + MAX_STORAGE_IMAGES + MAX_INPUT_ATTACHMENTS1168<= V3D_MAX_TEXTURE_SAMPLERS);1169STATIC_ASSERT(MAX_UNIFORM_BUFFERS >= MAX_DYNAMIC_UNIFORM_BUFFERS);1170STATIC_ASSERT(MAX_STORAGE_BUFFERS >= MAX_DYNAMIC_STORAGE_BUFFERS);11711172const uint32_t page_size = 4096;1173const uint32_t mem_size = compute_heap_size();11741175const uint32_t max_varying_components = 16 * 4;11761177const uint32_t v3d_coord_shift = 6;11781179const uint32_t v3d_point_line_granularity = 2.0f / (1 << v3d_coord_shift);1180const uint32_t max_fb_size = 4096;11811182const VkSampleCountFlags supported_sample_counts =1183VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;11841185struct timespec clock_res;1186clock_getres(CLOCK_MONOTONIC, &clock_res);1187const float timestamp_period =1188clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec;11891190/* FIXME: this will probably require an in-depth review */1191VkPhysicalDeviceLimits limits = {1192.maxImageDimension1D = 4096,1193.maxImageDimension2D = 4096,1194.maxImageDimension3D = 4096,1195.maxImageDimensionCube = 4096,1196.maxImageArrayLayers = 2048,1197.maxTexelBufferElements = (1ul << 28),1198.maxUniformBufferRange = V3D_MAX_BUFFER_RANGE,1199.maxStorageBufferRange = V3D_MAX_BUFFER_RANGE,1200.maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,1201.maxMemoryAllocationCount = mem_size / page_size,1202.maxSamplerAllocationCount = 64 * 1024,1203.bufferImageGranularity = 256, /* A cache line */1204.sparseAddressSpaceSize = 0,1205.maxBoundDescriptorSets = MAX_SETS,1206.maxPerStageDescriptorSamplers = V3D_MAX_TEXTURE_SAMPLERS,1207.maxPerStageDescriptorUniformBuffers = MAX_UNIFORM_BUFFERS,1208.maxPerStageDescriptorStorageBuffers = MAX_STORAGE_BUFFERS,1209.maxPerStageDescriptorSampledImages = MAX_SAMPLED_IMAGES,1210.maxPerStageDescriptorStorageImages = MAX_STORAGE_IMAGES,1211.maxPerStageDescriptorInputAttachments = MAX_INPUT_ATTACHMENTS,1212.maxPerStageResources = 128,12131214/* Some of these limits are multiplied by 6 because they need to1215* include all possible shader stages (even if not supported). See1216* 'Required Limits' table in the Vulkan spec.1217*/1218.maxDescriptorSetSamplers = 6 * V3D_MAX_TEXTURE_SAMPLERS,1219.maxDescriptorSetUniformBuffers = 6 * MAX_UNIFORM_BUFFERS,1220.maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,1221.maxDescriptorSetStorageBuffers = 6 * MAX_STORAGE_BUFFERS,1222.maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,1223.maxDescriptorSetSampledImages = 6 * MAX_SAMPLED_IMAGES,1224.maxDescriptorSetStorageImages = 6 * MAX_STORAGE_IMAGES,1225.maxDescriptorSetInputAttachments = MAX_INPUT_ATTACHMENTS,12261227/* Vertex limits */1228.maxVertexInputAttributes = MAX_VERTEX_ATTRIBS,1229.maxVertexInputBindings = MAX_VBS,1230.maxVertexInputAttributeOffset = 0xffffffff,1231.maxVertexInputBindingStride = 0xffffffff,1232.maxVertexOutputComponents = max_varying_components,12331234/* Tessellation limits */1235.maxTessellationGenerationLevel = 0,1236.maxTessellationPatchSize = 0,1237.maxTessellationControlPerVertexInputComponents = 0,1238.maxTessellationControlPerVertexOutputComponents = 0,1239.maxTessellationControlPerPatchOutputComponents = 0,1240.maxTessellationControlTotalOutputComponents = 0,1241.maxTessellationEvaluationInputComponents = 0,1242.maxTessellationEvaluationOutputComponents = 0,12431244/* Geometry limits */1245.maxGeometryShaderInvocations = 32,1246.maxGeometryInputComponents = 64,1247.maxGeometryOutputComponents = 64,1248.maxGeometryOutputVertices = 256,1249.maxGeometryTotalOutputComponents = 1024,12501251/* Fragment limits */1252.maxFragmentInputComponents = max_varying_components,1253.maxFragmentOutputAttachments = 4,1254.maxFragmentDualSrcAttachments = 0,1255.maxFragmentCombinedOutputResources = MAX_RENDER_TARGETS +1256MAX_STORAGE_BUFFERS +1257MAX_STORAGE_IMAGES,12581259/* Compute limits */1260.maxComputeSharedMemorySize = 16384,1261.maxComputeWorkGroupCount = { 65535, 65535, 65535 },1262.maxComputeWorkGroupInvocations = 256,1263.maxComputeWorkGroupSize = { 256, 256, 256 },12641265.subPixelPrecisionBits = v3d_coord_shift,1266.subTexelPrecisionBits = 8,1267.mipmapPrecisionBits = 8,1268.maxDrawIndexedIndexValue = 0x00ffffff,1269.maxDrawIndirectCount = 0x7fffffff,1270.maxSamplerLodBias = 14.0f,1271.maxSamplerAnisotropy = 16.0f,1272.maxViewports = MAX_VIEWPORTS,1273.maxViewportDimensions = { max_fb_size, max_fb_size },1274.viewportBoundsRange = { -2.0 * max_fb_size,12752.0 * max_fb_size - 1 },1276.viewportSubPixelBits = 0,1277.minMemoryMapAlignment = page_size,1278.minTexelBufferOffsetAlignment = V3D_UIFBLOCK_SIZE,1279.minUniformBufferOffsetAlignment = 32,1280.minStorageBufferOffsetAlignment = 32,1281.minTexelOffset = -8,1282.maxTexelOffset = 7,1283.minTexelGatherOffset = -8,1284.maxTexelGatherOffset = 7,1285.minInterpolationOffset = -0.5,1286.maxInterpolationOffset = 0.5,1287.subPixelInterpolationOffsetBits = v3d_coord_shift,1288.maxFramebufferWidth = max_fb_size,1289.maxFramebufferHeight = max_fb_size,1290.maxFramebufferLayers = 256,1291.framebufferColorSampleCounts = supported_sample_counts,1292.framebufferDepthSampleCounts = supported_sample_counts,1293.framebufferStencilSampleCounts = supported_sample_counts,1294.framebufferNoAttachmentsSampleCounts = supported_sample_counts,1295.maxColorAttachments = MAX_RENDER_TARGETS,1296.sampledImageColorSampleCounts = supported_sample_counts,1297.sampledImageIntegerSampleCounts = supported_sample_counts,1298.sampledImageDepthSampleCounts = supported_sample_counts,1299.sampledImageStencilSampleCounts = supported_sample_counts,1300.storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,1301.maxSampleMaskWords = 1,1302.timestampComputeAndGraphics = true,1303.timestampPeriod = timestamp_period,1304.maxClipDistances = 8,1305.maxCullDistances = 0,1306.maxCombinedClipAndCullDistances = 8,1307.discreteQueuePriorities = 2,1308.pointSizeRange = { v3d_point_line_granularity,1309V3D_MAX_POINT_SIZE },1310.lineWidthRange = { 1.0f, V3D_MAX_LINE_WIDTH },1311.pointSizeGranularity = v3d_point_line_granularity,1312.lineWidthGranularity = v3d_point_line_granularity,1313.strictLines = true,1314.standardSampleLocations = false,1315.optimalBufferCopyOffsetAlignment = 32,1316.optimalBufferCopyRowPitchAlignment = 32,1317.nonCoherentAtomSize = 256,1318};13191320*pProperties = (VkPhysicalDeviceProperties) {1321.apiVersion = V3DV_API_VERSION,1322.driverVersion = vk_get_driver_version(),1323.vendorID = v3dv_physical_device_vendor_id(pdevice),1324.deviceID = v3dv_physical_device_device_id(pdevice),1325.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,1326.limits = limits,1327.sparseProperties = { 0 },1328};13291330snprintf(pProperties->deviceName, sizeof(pProperties->deviceName),1331"%s", pdevice->name);1332memcpy(pProperties->pipelineCacheUUID,1333pdevice->pipeline_cache_uuid, VK_UUID_SIZE);1334}13351336VKAPI_ATTR void VKAPI_CALL1337v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,1338VkPhysicalDeviceProperties2 *pProperties)1339{1340V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);13411342v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);13431344vk_foreach_struct(ext, pProperties->pNext) {1345switch (ext->sType) {1346case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {1347VkPhysicalDeviceIDProperties *id_props =1348(VkPhysicalDeviceIDProperties *)ext;1349memcpy(id_props->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);1350memcpy(id_props->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);1351/* The LUID is for Windows. */1352id_props->deviceLUIDValid = false;1353break;1354}1355case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {1356VkPhysicalDeviceMaintenance3Properties *props =1357(VkPhysicalDeviceMaintenance3Properties *)ext;1358/* We don't really have special restrictions for the maximum1359* descriptors per set, other than maybe not exceeding the limits1360* of addressable memory in a single allocation on either the host1361* or the GPU. This will be a much larger limit than any of the1362* per-stage limits already available in Vulkan though, so in practice,1363* it is not expected to limit anything beyond what is already1364* constrained through per-stage limits.1365*/1366uint32_t max_host_descriptors =1367(UINT32_MAX - sizeof(struct v3dv_descriptor_set)) /1368sizeof(struct v3dv_descriptor);1369uint32_t max_gpu_descriptors =1370(UINT32_MAX / v3dv_X(pdevice, max_descriptor_bo_size)());1371props->maxPerSetDescriptors =1372MIN2(max_host_descriptors, max_gpu_descriptors);13731374/* Minimum required by the spec */1375props->maxMemoryAllocationSize = MAX_MEMORY_ALLOCATION_SIZE;1376break;1377}1378case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: {1379VkPhysicalDeviceMultiviewProperties *props =1380(VkPhysicalDeviceMultiviewProperties *)ext;1381props->maxMultiviewViewCount = 1;1382/* This assumes that the multiview implementation uses instancing */1383props->maxMultiviewInstanceIndex =1384(UINT32_MAX / props->maxMultiviewViewCount) - 1;1385break;1386}1387case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:1388/* Do nothing, not even logging. This is a non-PCI device, so we will1389* never provide this extension.1390*/1391break;1392case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {1393VkPhysicalDevicePointClippingProperties *props =1394(VkPhysicalDevicePointClippingProperties *)ext;1395props->pointClippingBehavior =1396VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;1397break;1398}1399case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: {1400VkPhysicalDeviceProtectedMemoryProperties *props =1401(VkPhysicalDeviceProtectedMemoryProperties *)ext;1402props->protectedNoFault = false;1403break;1404}1405case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: {1406VkPhysicalDeviceSubgroupProperties *props =1407(VkPhysicalDeviceSubgroupProperties *)ext;1408props->subgroupSize = V3D_CHANNELS;1409props->supportedStages = VK_SHADER_STAGE_COMPUTE_BIT;1410props->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;1411props->quadOperationsInAllStages = false;1412break;1413}1414default:1415v3dv_debug_ignored_stype(ext->sType);1416break;1417}1418}1419}14201421/* We support exactly one queue family. */1422static const VkQueueFamilyProperties1423v3dv_queue_family_properties = {1424.queueFlags = VK_QUEUE_GRAPHICS_BIT |1425VK_QUEUE_COMPUTE_BIT |1426VK_QUEUE_TRANSFER_BIT,1427.queueCount = 1,1428.timestampValidBits = 64,1429.minImageTransferGranularity = { 1, 1, 1 },1430};14311432VKAPI_ATTR void VKAPI_CALL1433v3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,1434uint32_t *pCount,1435VkQueueFamilyProperties *pQueueFamilyProperties)1436{1437VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pCount);14381439vk_outarray_append(&out, p) {1440*p = v3dv_queue_family_properties;1441}1442}14431444VKAPI_ATTR void VKAPI_CALL1445v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,1446uint32_t *pQueueFamilyPropertyCount,1447VkQueueFamilyProperties2 *pQueueFamilyProperties)1448{1449VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);14501451vk_outarray_append(&out, p) {1452p->queueFamilyProperties = v3dv_queue_family_properties;14531454vk_foreach_struct(s, p->pNext) {1455v3dv_debug_ignored_stype(s->sType);1456}1457}1458}14591460VKAPI_ATTR void VKAPI_CALL1461v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,1462VkPhysicalDeviceMemoryProperties *pMemoryProperties)1463{1464V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);1465*pMemoryProperties = device->memory;1466}14671468VKAPI_ATTR void VKAPI_CALL1469v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,1470VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)1471{1472v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice,1473&pMemoryProperties->memoryProperties);14741475vk_foreach_struct(ext, pMemoryProperties->pNext) {1476switch (ext->sType) {1477default:1478v3dv_debug_ignored_stype(ext->sType);1479break;1480}1481}1482}14831484VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL1485v3dv_GetInstanceProcAddr(VkInstance _instance,1486const char *pName)1487{1488V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);1489return vk_instance_get_proc_addr(&instance->vk,1490&v3dv_instance_entrypoints,1491pName);1492}14931494/* With version 1+ of the loader interface the ICD should expose1495* vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.1496*/1497PUBLIC1498VKAPI_ATTR PFN_vkVoidFunction1499VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,1500const char *pName);15011502PUBLIC1503VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL1504vk_icdGetInstanceProcAddr(VkInstance instance,1505const char* pName)1506{1507return v3dv_GetInstanceProcAddr(instance, pName);1508}15091510/* With version 4+ of the loader interface the ICD should expose1511* vk_icdGetPhysicalDeviceProcAddr()1512*/1513PUBLIC1514VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL1515vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,1516const char* pName);15171518PFN_vkVoidFunction1519vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,1520const char* pName)1521{1522V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);15231524return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);1525}15261527VKAPI_ATTR VkResult VKAPI_CALL1528v3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,1529VkLayerProperties *pProperties)1530{1531if (pProperties == NULL) {1532*pPropertyCount = 0;1533return VK_SUCCESS;1534}15351536return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);1537}15381539VKAPI_ATTR VkResult VKAPI_CALL1540v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,1541uint32_t *pPropertyCount,1542VkLayerProperties *pProperties)1543{1544V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);15451546if (pProperties == NULL) {1547*pPropertyCount = 0;1548return VK_SUCCESS;1549}15501551return vk_error((struct v3dv_instance*) physical_device->vk.instance,1552VK_ERROR_LAYER_NOT_PRESENT);1553}15541555static VkResult1556queue_init(struct v3dv_device *device, struct v3dv_queue *queue)1557{1558vk_object_base_init(&device->vk, &queue->base, VK_OBJECT_TYPE_QUEUE);1559queue->device = device;1560queue->flags = 0;1561queue->noop_job = NULL;1562list_inithead(&queue->submit_wait_list);1563pthread_mutex_init(&queue->mutex, NULL);1564return VK_SUCCESS;1565}15661567static void1568queue_finish(struct v3dv_queue *queue)1569{1570vk_object_base_finish(&queue->base);1571assert(list_is_empty(&queue->submit_wait_list));1572if (queue->noop_job)1573v3dv_job_destroy(queue->noop_job);1574pthread_mutex_destroy(&queue->mutex);1575}15761577static void1578init_device_meta(struct v3dv_device *device)1579{1580mtx_init(&device->meta.mtx, mtx_plain);1581v3dv_meta_clear_init(device);1582v3dv_meta_blit_init(device);1583v3dv_meta_texel_buffer_copy_init(device);1584}15851586static void1587destroy_device_meta(struct v3dv_device *device)1588{1589mtx_destroy(&device->meta.mtx);1590v3dv_meta_clear_finish(device);1591v3dv_meta_blit_finish(device);1592v3dv_meta_texel_buffer_copy_finish(device);1593}15941595VKAPI_ATTR VkResult VKAPI_CALL1596v3dv_CreateDevice(VkPhysicalDevice physicalDevice,1597const VkDeviceCreateInfo *pCreateInfo,1598const VkAllocationCallbacks *pAllocator,1599VkDevice *pDevice)1600{1601V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);1602struct v3dv_instance *instance = (struct v3dv_instance*) physical_device->vk.instance;1603VkResult result;1604struct v3dv_device *device;16051606assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);16071608/* Check enabled features */1609if (pCreateInfo->pEnabledFeatures) {1610VkPhysicalDeviceFeatures supported_features;1611v3dv_GetPhysicalDeviceFeatures(physicalDevice, &supported_features);1612VkBool32 *supported_feature = (VkBool32 *)&supported_features;1613VkBool32 *enabled_feature = (VkBool32 *)pCreateInfo->pEnabledFeatures;1614unsigned num_features = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);1615for (uint32_t i = 0; i < num_features; i++) {1616if (enabled_feature[i] && !supported_feature[i])1617return vk_error(instance, VK_ERROR_FEATURE_NOT_PRESENT);1618}1619}16201621/* Check requested queues (we only expose one queue ) */1622assert(pCreateInfo->queueCreateInfoCount == 1);1623for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {1624assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0);1625assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1);1626if (pCreateInfo->pQueueCreateInfos[i].flags != 0)1627return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);1628}16291630device = vk_zalloc2(&physical_device->vk.instance->alloc, pAllocator,1631sizeof(*device), 8,1632VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);1633if (!device)1634return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);16351636struct vk_device_dispatch_table dispatch_table;1637vk_device_dispatch_table_from_entrypoints(&dispatch_table,1638&v3dv_device_entrypoints, true);1639result = vk_device_init(&device->vk, &physical_device->vk,1640&dispatch_table, pCreateInfo, pAllocator);1641if (result != VK_SUCCESS) {1642vk_free(&device->vk.alloc, device);1643return vk_error(instance, result);1644}16451646device->instance = instance;1647device->pdevice = physical_device;16481649if (pAllocator)1650device->vk.alloc = *pAllocator;1651else1652device->vk.alloc = physical_device->vk.instance->alloc;16531654pthread_mutex_init(&device->mutex, NULL);16551656result = queue_init(device, &device->queue);1657if (result != VK_SUCCESS)1658goto fail;16591660device->devinfo = physical_device->devinfo;16611662if (pCreateInfo->pEnabledFeatures) {1663memcpy(&device->features, pCreateInfo->pEnabledFeatures,1664sizeof(device->features));16651666if (device->features.robustBufferAccess)1667perf_debug("Device created with Robust Buffer Access enabled.\n");1668}16691670int ret = drmSyncobjCreate(physical_device->render_fd,1671DRM_SYNCOBJ_CREATE_SIGNALED,1672&device->last_job_sync);1673if (ret) {1674result = VK_ERROR_INITIALIZATION_FAILED;1675goto fail;1676}16771678#ifdef DEBUG1679v3dv_X(device, device_check_prepacked_sizes)();1680#endif1681init_device_meta(device);1682v3dv_bo_cache_init(device);1683v3dv_pipeline_cache_init(&device->default_pipeline_cache, device,1684device->instance->default_pipeline_cache_enabled);1685device->default_attribute_float =1686v3dv_pipeline_create_default_attribute_values(device, NULL);16871688*pDevice = v3dv_device_to_handle(device);16891690return VK_SUCCESS;16911692fail:1693vk_device_finish(&device->vk);1694vk_free(&device->vk.alloc, device);16951696return result;1697}16981699VKAPI_ATTR void VKAPI_CALL1700v3dv_DestroyDevice(VkDevice _device,1701const VkAllocationCallbacks *pAllocator)1702{1703V3DV_FROM_HANDLE(v3dv_device, device, _device);17041705v3dv_DeviceWaitIdle(_device);1706queue_finish(&device->queue);1707pthread_mutex_destroy(&device->mutex);1708drmSyncobjDestroy(device->pdevice->render_fd, device->last_job_sync);1709destroy_device_meta(device);1710v3dv_pipeline_cache_finish(&device->default_pipeline_cache);17111712if (device->default_attribute_float) {1713v3dv_bo_free(device, device->default_attribute_float);1714device->default_attribute_float = NULL;1715}17161717/* Bo cache should be removed the last, as any other object could be1718* freeing their private bos1719*/1720v3dv_bo_cache_destroy(device);17211722vk_device_finish(&device->vk);1723vk_free2(&device->vk.alloc, pAllocator, device);1724}17251726VKAPI_ATTR void VKAPI_CALL1727v3dv_GetDeviceQueue(VkDevice _device,1728uint32_t queueFamilyIndex,1729uint32_t queueIndex,1730VkQueue *pQueue)1731{1732V3DV_FROM_HANDLE(v3dv_device, device, _device);17331734assert(queueIndex == 0);1735assert(queueFamilyIndex == 0);17361737*pQueue = v3dv_queue_to_handle(&device->queue);1738}17391740VKAPI_ATTR VkResult VKAPI_CALL1741v3dv_DeviceWaitIdle(VkDevice _device)1742{1743V3DV_FROM_HANDLE(v3dv_device, device, _device);1744return v3dv_QueueWaitIdle(v3dv_queue_to_handle(&device->queue));1745}17461747static VkResult1748device_alloc(struct v3dv_device *device,1749struct v3dv_device_memory *mem,1750VkDeviceSize size)1751{1752/* Our kernel interface is 32-bit */1753assert(size <= UINT32_MAX);17541755mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false);1756if (!mem->bo)1757return VK_ERROR_OUT_OF_DEVICE_MEMORY;17581759return VK_SUCCESS;1760}17611762static void1763device_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle)1764{1765assert(display_fd != -1);1766if (dumb_handle < 0)1767return;17681769struct drm_mode_destroy_dumb destroy_dumb = {1770.handle = dumb_handle,1771};1772if (v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb)) {1773fprintf(stderr, "destroy dumb object %d: %s\n", dumb_handle, strerror(errno));1774}1775}17761777static void1778device_free(struct v3dv_device *device, struct v3dv_device_memory *mem)1779{1780/* If this memory allocation was for WSI, then we need to use the1781* display device to free the allocated dumb BO.1782*/1783if (mem->is_for_wsi) {1784assert(mem->has_bo_ownership);1785device_free_wsi_dumb(device->instance->physicalDevice.display_fd,1786mem->bo->dumb_handle);1787}17881789if (mem->has_bo_ownership)1790v3dv_bo_free(device, mem->bo);1791else if (mem->bo)1792vk_free(&device->vk.alloc, mem->bo);1793}17941795static void1796device_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem)1797{1798assert(mem && mem->bo->map && mem->bo->map_size > 0);1799v3dv_bo_unmap(device, mem->bo);1800}18011802static VkResult1803device_map(struct v3dv_device *device, struct v3dv_device_memory *mem)1804{1805assert(mem && mem->bo);18061807/* From the spec:1808*1809* "After a successful call to vkMapMemory the memory object memory is1810* considered to be currently host mapped. It is an application error to1811* call vkMapMemory on a memory object that is already host mapped."1812*1813* We are not concerned with this ourselves (validation layers should1814* catch these errors and warn users), however, the driver may internally1815* map things (for example for debug CLIF dumps or some CPU-side operations)1816* so by the time the user calls here the buffer might already been mapped1817* internally by the driver.1818*/1819if (mem->bo->map) {1820assert(mem->bo->map_size == mem->bo->size);1821return VK_SUCCESS;1822}18231824bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size);1825if (!ok)1826return VK_ERROR_MEMORY_MAP_FAILED;18271828return VK_SUCCESS;1829}18301831static VkResult1832device_import_bo(struct v3dv_device *device,1833const VkAllocationCallbacks *pAllocator,1834int fd, uint64_t size,1835struct v3dv_bo **bo)1836{1837VkResult result;18381839*bo = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(struct v3dv_bo), 8,1840VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);1841if (*bo == NULL) {1842result = VK_ERROR_OUT_OF_HOST_MEMORY;1843goto fail;1844}18451846off_t real_size = lseek(fd, 0, SEEK_END);1847lseek(fd, 0, SEEK_SET);1848if (real_size < 0 || (uint64_t) real_size < size) {1849result = VK_ERROR_INVALID_EXTERNAL_HANDLE;1850goto fail;1851}18521853int render_fd = device->pdevice->render_fd;1854assert(render_fd >= 0);18551856int ret;1857uint32_t handle;1858ret = drmPrimeFDToHandle(render_fd, fd, &handle);1859if (ret) {1860result = VK_ERROR_INVALID_EXTERNAL_HANDLE;1861goto fail;1862}18631864struct drm_v3d_get_bo_offset get_offset = {1865.handle = handle,1866};1867ret = v3dv_ioctl(render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset);1868if (ret) {1869result = VK_ERROR_INVALID_EXTERNAL_HANDLE;1870goto fail;1871}1872assert(get_offset.offset != 0);18731874v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false);18751876return VK_SUCCESS;18771878fail:1879if (*bo) {1880vk_free2(&device->vk.alloc, pAllocator, *bo);1881*bo = NULL;1882}1883return result;1884}18851886static VkResult1887device_alloc_for_wsi(struct v3dv_device *device,1888const VkAllocationCallbacks *pAllocator,1889struct v3dv_device_memory *mem,1890VkDeviceSize size)1891{1892/* In the simulator we can get away with a regular allocation since both1893* allocation and rendering happen in the same DRM render node. On actual1894* hardware we need to allocate our winsys BOs on the vc4 display device1895* and import them into v3d.1896*/1897#if using_v3d_simulator1898return device_alloc(device, mem, size);1899#else1900/* If we are allocating for WSI we should have a swapchain and thus,1901* we should've initialized the display device. However, Zink doesn't1902* use swapchains, so in that case we can get here without acquiring the1903* display device and we need to do it now.1904*/1905VkResult result;1906struct v3dv_instance *instance = device->instance;1907struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;1908if (unlikely(pdevice->display_fd < 0)) {1909result = v3dv_physical_device_acquire_display(instance, pdevice, NULL);1910if (result != VK_SUCCESS)1911return result;1912}1913assert(pdevice->display_fd != -1);19141915mem->is_for_wsi = true;19161917int display_fd = pdevice->display_fd;1918struct drm_mode_create_dumb create_dumb = {1919.width = 1024, /* one page */1920.height = align(size, 4096) / 4096,1921.bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM),1922};19231924int err;1925err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);1926if (err < 0)1927goto fail_create;19281929int fd;1930err =1931drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd);1932if (err < 0)1933goto fail_export;19341935result = device_import_bo(device, pAllocator, fd, size, &mem->bo);1936close(fd);1937if (result != VK_SUCCESS)1938goto fail_import;19391940mem->bo->dumb_handle = create_dumb.handle;1941return VK_SUCCESS;19421943fail_import:1944fail_export:1945device_free_wsi_dumb(display_fd, create_dumb.handle);19461947fail_create:1948return VK_ERROR_OUT_OF_DEVICE_MEMORY;1949#endif1950}19511952VKAPI_ATTR VkResult VKAPI_CALL1953v3dv_AllocateMemory(VkDevice _device,1954const VkMemoryAllocateInfo *pAllocateInfo,1955const VkAllocationCallbacks *pAllocator,1956VkDeviceMemory *pMem)1957{1958V3DV_FROM_HANDLE(v3dv_device, device, _device);1959struct v3dv_device_memory *mem;1960struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;19611962assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);19631964/* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */1965assert(pAllocateInfo->allocationSize > 0);19661967mem = vk_object_zalloc(&device->vk, pAllocator, sizeof(*mem),1968VK_OBJECT_TYPE_DEVICE_MEMORY);1969if (mem == NULL)1970return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);19711972assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount);1973mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];1974mem->has_bo_ownership = true;1975mem->is_for_wsi = false;19761977const struct wsi_memory_allocate_info *wsi_info = NULL;1978const VkImportMemoryFdInfoKHR *fd_info = NULL;1979vk_foreach_struct_const(ext, pAllocateInfo->pNext) {1980switch ((unsigned)ext->sType) {1981case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA:1982wsi_info = (void *)ext;1983break;1984case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:1985fd_info = (void *)ext;1986break;1987case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO:1988/* We don't support VK_KHR_buffer_device_address or multiple1989* devices per device group, so we can ignore this.1990*/1991break;1992case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR:1993/* We don't have particular optimizations associated with memory1994* allocations that won't be suballocated to multiple resources.1995*/1996break;1997case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR:1998/* The mask of handle types specified here must be supported1999* according to VkExternalImageFormatProperties, so it must be2000* fd or dmabuf, which don't have special requirements for us.2001*/2002break;2003default:2004v3dv_debug_ignored_stype(ext->sType);2005break;2006}2007}20082009VkResult result = VK_SUCCESS;20102011/* We always allocate device memory in multiples of a page, so round up2012* requested size to that.2013*/2014VkDeviceSize alloc_size = ALIGN(pAllocateInfo->allocationSize, 4096);20152016if (unlikely(alloc_size > MAX_MEMORY_ALLOCATION_SIZE)) {2017result = VK_ERROR_OUT_OF_DEVICE_MEMORY;2018} else {2019if (wsi_info) {2020result = device_alloc_for_wsi(device, pAllocator, mem, alloc_size);2021} else if (fd_info && fd_info->handleType) {2022assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||2023fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);2024result = device_import_bo(device, pAllocator,2025fd_info->fd, alloc_size, &mem->bo);2026mem->has_bo_ownership = false;2027if (result == VK_SUCCESS)2028close(fd_info->fd);2029} else {2030result = device_alloc(device, mem, alloc_size);2031}2032}20332034if (result != VK_SUCCESS) {2035vk_object_free(&device->vk, pAllocator, mem);2036return vk_error(device->instance, result);2037}20382039*pMem = v3dv_device_memory_to_handle(mem);2040return result;2041}20422043VKAPI_ATTR void VKAPI_CALL2044v3dv_FreeMemory(VkDevice _device,2045VkDeviceMemory _mem,2046const VkAllocationCallbacks *pAllocator)2047{2048V3DV_FROM_HANDLE(v3dv_device, device, _device);2049V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem);20502051if (mem == NULL)2052return;20532054if (mem->bo->map)2055v3dv_UnmapMemory(_device, _mem);20562057device_free(device, mem);20582059vk_object_free(&device->vk, pAllocator, mem);2060}20612062VKAPI_ATTR VkResult VKAPI_CALL2063v3dv_MapMemory(VkDevice _device,2064VkDeviceMemory _memory,2065VkDeviceSize offset,2066VkDeviceSize size,2067VkMemoryMapFlags flags,2068void **ppData)2069{2070V3DV_FROM_HANDLE(v3dv_device, device, _device);2071V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);20722073if (mem == NULL) {2074*ppData = NULL;2075return VK_SUCCESS;2076}20772078assert(offset < mem->bo->size);20792080/* Since the driver can map BOs internally as well and the mapped range2081* required by the user or the driver might not be the same, we always map2082* the entire BO and then add the requested offset to the start address2083* of the mapped region.2084*/2085VkResult result = device_map(device, mem);2086if (result != VK_SUCCESS)2087return vk_error(device->instance, result);20882089*ppData = ((uint8_t *) mem->bo->map) + offset;2090return VK_SUCCESS;2091}20922093VKAPI_ATTR void VKAPI_CALL2094v3dv_UnmapMemory(VkDevice _device,2095VkDeviceMemory _memory)2096{2097V3DV_FROM_HANDLE(v3dv_device, device, _device);2098V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);20992100if (mem == NULL)2101return;21022103device_unmap(device, mem);2104}21052106VKAPI_ATTR VkResult VKAPI_CALL2107v3dv_FlushMappedMemoryRanges(VkDevice _device,2108uint32_t memoryRangeCount,2109const VkMappedMemoryRange *pMemoryRanges)2110{2111return VK_SUCCESS;2112}21132114VKAPI_ATTR VkResult VKAPI_CALL2115v3dv_InvalidateMappedMemoryRanges(VkDevice _device,2116uint32_t memoryRangeCount,2117const VkMappedMemoryRange *pMemoryRanges)2118{2119return VK_SUCCESS;2120}21212122VKAPI_ATTR void VKAPI_CALL2123v3dv_GetImageMemoryRequirements2(VkDevice device,2124const VkImageMemoryRequirementsInfo2 *pInfo,2125VkMemoryRequirements2 *pMemoryRequirements)2126{2127V3DV_FROM_HANDLE(v3dv_image, image, pInfo->image);21282129pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {2130.memoryTypeBits = 0x1,2131.alignment = image->alignment,2132.size = image->size2133};21342135vk_foreach_struct(ext, pMemoryRequirements->pNext) {2136switch (ext->sType) {2137case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {2138VkMemoryDedicatedRequirements *req =2139(VkMemoryDedicatedRequirements *) ext;2140req->requiresDedicatedAllocation = image->external;2141req->prefersDedicatedAllocation = image->external;2142break;2143}2144default:2145v3dv_debug_ignored_stype(ext->sType);2146break;2147}2148}2149}21502151static void2152bind_image_memory(const VkBindImageMemoryInfo *info)2153{2154V3DV_FROM_HANDLE(v3dv_image, image, info->image);2155V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);21562157/* Valid usage:2158*2159* "memoryOffset must be an integer multiple of the alignment member of2160* the VkMemoryRequirements structure returned from a call to2161* vkGetImageMemoryRequirements with image"2162*/2163assert(info->memoryOffset % image->alignment == 0);2164assert(info->memoryOffset < mem->bo->size);21652166image->mem = mem;2167image->mem_offset = info->memoryOffset;2168}21692170VKAPI_ATTR VkResult VKAPI_CALL2171v3dv_BindImageMemory2(VkDevice _device,2172uint32_t bindInfoCount,2173const VkBindImageMemoryInfo *pBindInfos)2174{2175for (uint32_t i = 0; i < bindInfoCount; i++) {2176const VkBindImageMemorySwapchainInfoKHR *swapchain_info =2177vk_find_struct_const(pBindInfos->pNext,2178BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);2179if (swapchain_info && swapchain_info->swapchain) {2180struct v3dv_image *swapchain_image =2181v3dv_wsi_get_image_from_swapchain(swapchain_info->swapchain,2182swapchain_info->imageIndex);2183VkBindImageMemoryInfo swapchain_bind = {2184.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,2185.image = pBindInfos[i].image,2186.memory = v3dv_device_memory_to_handle(swapchain_image->mem),2187.memoryOffset = swapchain_image->mem_offset,2188};2189bind_image_memory(&swapchain_bind);2190} else {2191bind_image_memory(&pBindInfos[i]);2192}2193}21942195return VK_SUCCESS;2196}21972198VKAPI_ATTR void VKAPI_CALL2199v3dv_GetBufferMemoryRequirements2(VkDevice device,2200const VkBufferMemoryRequirementsInfo2 *pInfo,2201VkMemoryRequirements2 *pMemoryRequirements)2202{2203V3DV_FROM_HANDLE(v3dv_buffer, buffer, pInfo->buffer);22042205pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {2206.memoryTypeBits = 0x1,2207.alignment = buffer->alignment,2208.size = align64(buffer->size, buffer->alignment),2209};22102211vk_foreach_struct(ext, pMemoryRequirements->pNext) {2212switch (ext->sType) {2213case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {2214VkMemoryDedicatedRequirements *req =2215(VkMemoryDedicatedRequirements *) ext;2216req->requiresDedicatedAllocation = false;2217req->prefersDedicatedAllocation = false;2218break;2219}2220default:2221v3dv_debug_ignored_stype(ext->sType);2222break;2223}2224}2225}22262227static void2228bind_buffer_memory(const VkBindBufferMemoryInfo *info)2229{2230V3DV_FROM_HANDLE(v3dv_buffer, buffer, info->buffer);2231V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);22322233/* Valid usage:2234*2235* "memoryOffset must be an integer multiple of the alignment member of2236* the VkMemoryRequirements structure returned from a call to2237* vkGetBufferMemoryRequirements with buffer"2238*/2239assert(info->memoryOffset % buffer->alignment == 0);2240assert(info->memoryOffset < mem->bo->size);22412242buffer->mem = mem;2243buffer->mem_offset = info->memoryOffset;2244}224522462247VKAPI_ATTR VkResult VKAPI_CALL2248v3dv_BindBufferMemory2(VkDevice device,2249uint32_t bindInfoCount,2250const VkBindBufferMemoryInfo *pBindInfos)2251{2252for (uint32_t i = 0; i < bindInfoCount; i++)2253bind_buffer_memory(&pBindInfos[i]);22542255return VK_SUCCESS;2256}22572258VKAPI_ATTR VkResult VKAPI_CALL2259v3dv_CreateBuffer(VkDevice _device,2260const VkBufferCreateInfo *pCreateInfo,2261const VkAllocationCallbacks *pAllocator,2262VkBuffer *pBuffer)2263{2264V3DV_FROM_HANDLE(v3dv_device, device, _device);2265struct v3dv_buffer *buffer;22662267assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);2268assert(pCreateInfo->usage != 0);22692270/* We don't support any flags for now */2271assert(pCreateInfo->flags == 0);22722273buffer = vk_object_zalloc(&device->vk, pAllocator, sizeof(*buffer),2274VK_OBJECT_TYPE_BUFFER);2275if (buffer == NULL)2276return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);22772278buffer->size = pCreateInfo->size;2279buffer->usage = pCreateInfo->usage;2280buffer->alignment = 256; /* nonCoherentAtomSize */22812282/* Limit allocations to 32-bit */2283const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment);2284if (aligned_size > UINT32_MAX || aligned_size < buffer->size)2285return VK_ERROR_OUT_OF_DEVICE_MEMORY;22862287*pBuffer = v3dv_buffer_to_handle(buffer);22882289return VK_SUCCESS;2290}22912292VKAPI_ATTR void VKAPI_CALL2293v3dv_DestroyBuffer(VkDevice _device,2294VkBuffer _buffer,2295const VkAllocationCallbacks *pAllocator)2296{2297V3DV_FROM_HANDLE(v3dv_device, device, _device);2298V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);22992300if (!buffer)2301return;23022303vk_object_free(&device->vk, pAllocator, buffer);2304}23052306VKAPI_ATTR VkResult VKAPI_CALL2307v3dv_CreateFramebuffer(VkDevice _device,2308const VkFramebufferCreateInfo *pCreateInfo,2309const VkAllocationCallbacks *pAllocator,2310VkFramebuffer *pFramebuffer)2311{2312V3DV_FROM_HANDLE(v3dv_device, device, _device);2313struct v3dv_framebuffer *framebuffer;23142315assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);23162317size_t size = sizeof(*framebuffer) +2318sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount;2319framebuffer = vk_object_zalloc(&device->vk, pAllocator, size,2320VK_OBJECT_TYPE_FRAMEBUFFER);2321if (framebuffer == NULL)2322return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);23232324framebuffer->width = pCreateInfo->width;2325framebuffer->height = pCreateInfo->height;2326framebuffer->layers = pCreateInfo->layers;2327framebuffer->has_edge_padding = true;23282329framebuffer->attachment_count = pCreateInfo->attachmentCount;2330framebuffer->color_attachment_count = 0;2331for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {2332framebuffer->attachments[i] =2333v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]);2334if (framebuffer->attachments[i]->aspects & VK_IMAGE_ASPECT_COLOR_BIT)2335framebuffer->color_attachment_count++;2336}23372338*pFramebuffer = v3dv_framebuffer_to_handle(framebuffer);23392340return VK_SUCCESS;2341}23422343VKAPI_ATTR void VKAPI_CALL2344v3dv_DestroyFramebuffer(VkDevice _device,2345VkFramebuffer _fb,2346const VkAllocationCallbacks *pAllocator)2347{2348V3DV_FROM_HANDLE(v3dv_device, device, _device);2349V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb);23502351if (!fb)2352return;23532354vk_object_free(&device->vk, pAllocator, fb);2355}23562357VKAPI_ATTR VkResult VKAPI_CALL2358v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,2359VkExternalMemoryHandleTypeFlagBits handleType,2360int fd,2361VkMemoryFdPropertiesKHR *pMemoryFdProperties)2362{2363V3DV_FROM_HANDLE(v3dv_device, device, _device);2364struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;23652366switch (handleType) {2367case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:2368pMemoryFdProperties->memoryTypeBits =2369(1 << pdevice->memory.memoryTypeCount) - 1;2370return VK_SUCCESS;2371default:2372return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);2373}2374}23752376VKAPI_ATTR VkResult VKAPI_CALL2377v3dv_GetMemoryFdKHR(VkDevice _device,2378const VkMemoryGetFdInfoKHR *pGetFdInfo,2379int *pFd)2380{2381V3DV_FROM_HANDLE(v3dv_device, device, _device);2382V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory);23832384assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);2385assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||2386pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);23872388int fd, ret;2389ret = drmPrimeHandleToFD(device->pdevice->render_fd,2390mem->bo->handle,2391DRM_CLOEXEC, &fd);2392if (ret)2393return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);23942395*pFd = fd;23962397return VK_SUCCESS;2398}23992400VKAPI_ATTR VkResult VKAPI_CALL2401v3dv_CreateEvent(VkDevice _device,2402const VkEventCreateInfo *pCreateInfo,2403const VkAllocationCallbacks *pAllocator,2404VkEvent *pEvent)2405{2406V3DV_FROM_HANDLE(v3dv_device, device, _device);2407struct v3dv_event *event =2408vk_object_zalloc(&device->vk, pAllocator, sizeof(*event),2409VK_OBJECT_TYPE_EVENT);2410if (!event)2411return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);24122413/* Events are created in the unsignaled state */2414event->state = false;2415*pEvent = v3dv_event_to_handle(event);24162417return VK_SUCCESS;2418}24192420VKAPI_ATTR void VKAPI_CALL2421v3dv_DestroyEvent(VkDevice _device,2422VkEvent _event,2423const VkAllocationCallbacks *pAllocator)2424{2425V3DV_FROM_HANDLE(v3dv_device, device, _device);2426V3DV_FROM_HANDLE(v3dv_event, event, _event);24272428if (!event)2429return;24302431vk_object_free(&device->vk, pAllocator, event);2432}24332434VKAPI_ATTR VkResult VKAPI_CALL2435v3dv_GetEventStatus(VkDevice _device, VkEvent _event)2436{2437V3DV_FROM_HANDLE(v3dv_event, event, _event);2438return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET;2439}24402441VKAPI_ATTR VkResult VKAPI_CALL2442v3dv_SetEvent(VkDevice _device, VkEvent _event)2443{2444V3DV_FROM_HANDLE(v3dv_event, event, _event);2445p_atomic_set(&event->state, 1);2446return VK_SUCCESS;2447}24482449VKAPI_ATTR VkResult VKAPI_CALL2450v3dv_ResetEvent(VkDevice _device, VkEvent _event)2451{2452V3DV_FROM_HANDLE(v3dv_event, event, _event);2453p_atomic_set(&event->state, 0);2454return VK_SUCCESS;2455}24562457VKAPI_ATTR VkResult VKAPI_CALL2458v3dv_CreateSampler(VkDevice _device,2459const VkSamplerCreateInfo *pCreateInfo,2460const VkAllocationCallbacks *pAllocator,2461VkSampler *pSampler)2462{2463V3DV_FROM_HANDLE(v3dv_device, device, _device);2464struct v3dv_sampler *sampler;24652466assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);24672468sampler = vk_object_zalloc(&device->vk, pAllocator, sizeof(*sampler),2469VK_OBJECT_TYPE_SAMPLER);2470if (!sampler)2471return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);24722473sampler->compare_enable = pCreateInfo->compareEnable;2474sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates;2475v3dv_X(device, pack_sampler_state)(sampler, pCreateInfo);24762477*pSampler = v3dv_sampler_to_handle(sampler);24782479return VK_SUCCESS;2480}24812482VKAPI_ATTR void VKAPI_CALL2483v3dv_DestroySampler(VkDevice _device,2484VkSampler _sampler,2485const VkAllocationCallbacks *pAllocator)2486{2487V3DV_FROM_HANDLE(v3dv_device, device, _device);2488V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler);24892490if (!sampler)2491return;24922493vk_object_free(&device->vk, pAllocator, sampler);2494}24952496VKAPI_ATTR void VKAPI_CALL2497v3dv_GetDeviceMemoryCommitment(VkDevice device,2498VkDeviceMemory memory,2499VkDeviceSize *pCommittedMemoryInBytes)2500{2501*pCommittedMemoryInBytes = 0;2502}25032504VKAPI_ATTR void VKAPI_CALL2505v3dv_GetImageSparseMemoryRequirements(2506VkDevice device,2507VkImage image,2508uint32_t *pSparseMemoryRequirementCount,2509VkSparseImageMemoryRequirements *pSparseMemoryRequirements)2510{2511*pSparseMemoryRequirementCount = 0;2512}25132514VKAPI_ATTR void VKAPI_CALL2515v3dv_GetImageSparseMemoryRequirements2(2516VkDevice device,2517const VkImageSparseMemoryRequirementsInfo2 *pInfo,2518uint32_t *pSparseMemoryRequirementCount,2519VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)2520{2521*pSparseMemoryRequirementCount = 0;2522}25232524/* vk_icd.h does not declare this function, so we declare it here to2525* suppress Wmissing-prototypes.2526*/2527PUBLIC VKAPI_ATTR VkResult VKAPI_CALL2528vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);25292530PUBLIC VKAPI_ATTR VkResult VKAPI_CALL2531vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)2532{2533/* For the full details on loader interface versioning, see2534* <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.2535* What follows is a condensed summary, to help you navigate the large and2536* confusing official doc.2537*2538* - Loader interface v0 is incompatible with later versions. We don't2539* support it.2540*2541* - In loader interface v1:2542* - The first ICD entrypoint called by the loader is2543* vk_icdGetInstanceProcAddr(). The ICD must statically expose this2544* entrypoint.2545* - The ICD must statically expose no other Vulkan symbol unless it is2546* linked with -Bsymbolic.2547* - Each dispatchable Vulkan handle created by the ICD must be2548* a pointer to a struct whose first member is VK_LOADER_DATA. The2549* ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.2550* - The loader implements vkCreate{PLATFORM}SurfaceKHR() and2551* vkDestroySurfaceKHR(). The ICD must be capable of working with2552* such loader-managed surfaces.2553*2554* - Loader interface v2 differs from v1 in:2555* - The first ICD entrypoint called by the loader is2556* vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must2557* statically expose this entrypoint.2558*2559* - Loader interface v3 differs from v2 in:2560* - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),2561* vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,2562* because the loader no longer does so.2563*2564* - Loader interface v4 differs from v3 in:2565* - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().2566*/2567*pSupportedVersion = MIN2(*pSupportedVersion, 3u);2568return VK_SUCCESS;2569}257025712572