1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2020 Google LLC 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci */ 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_ci#include <errno.h> 7bf215546Sopenharmony_ci#include <fcntl.h> 8bf215546Sopenharmony_ci#include <poll.h> 9bf215546Sopenharmony_ci#include <sys/mman.h> 10bf215546Sopenharmony_ci#include <sys/stat.h> 11bf215546Sopenharmony_ci#include <sys/types.h> 12bf215546Sopenharmony_ci#include <unistd.h> 13bf215546Sopenharmony_ci#include <xf86drm.h> 14bf215546Sopenharmony_ci 15bf215546Sopenharmony_ci#ifdef MAJOR_IN_MKDEV 16bf215546Sopenharmony_ci#include <sys/mkdev.h> 17bf215546Sopenharmony_ci#endif 18bf215546Sopenharmony_ci#ifdef MAJOR_IN_SYSMACROS 19bf215546Sopenharmony_ci#include <sys/sysmacros.h> 20bf215546Sopenharmony_ci#endif 21bf215546Sopenharmony_ci 22bf215546Sopenharmony_ci#include "drm-uapi/virtgpu_drm.h" 23bf215546Sopenharmony_ci#include "util/sparse_array.h" 24bf215546Sopenharmony_ci#define VIRGL_RENDERER_UNSTABLE_APIS 25bf215546Sopenharmony_ci#include "virtio-gpu/virglrenderer_hw.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "vn_renderer_internal.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci/* XXX WIP kernel uapi */ 30bf215546Sopenharmony_ci#ifndef VIRTGPU_PARAM_CONTEXT_INIT 31bf215546Sopenharmony_ci#define VIRTGPU_PARAM_CONTEXT_INIT 6 32bf215546Sopenharmony_ci#define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 33bf215546Sopenharmony_cistruct drm_virtgpu_context_set_param { 34bf215546Sopenharmony_ci __u64 param; 35bf215546Sopenharmony_ci __u64 value; 36bf215546Sopenharmony_ci}; 37bf215546Sopenharmony_cistruct drm_virtgpu_context_init { 38bf215546Sopenharmony_ci __u32 num_params; 39bf215546Sopenharmony_ci __u32 pad; 40bf215546Sopenharmony_ci __u64 ctx_set_params; 41bf215546Sopenharmony_ci}; 42bf215546Sopenharmony_ci#define DRM_VIRTGPU_CONTEXT_INIT 0xb 43bf215546Sopenharmony_ci#define DRM_IOCTL_VIRTGPU_CONTEXT_INIT \ 44bf215546Sopenharmony_ci DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_CONTEXT_INIT, \ 45bf215546Sopenharmony_ci struct drm_virtgpu_context_init) 46bf215546Sopenharmony_ci#endif /* VIRTGPU_PARAM_CONTEXT_INIT */ 47bf215546Sopenharmony_ci#ifndef VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT 48bf215546Sopenharmony_ci#define VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT 100 49bf215546Sopenharmony_ci#endif /* VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT */ 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci#ifndef VIRTGPU_PARAM_GUEST_VRAM 52bf215546Sopenharmony_ci/* All guest allocations happen via virtgpu dedicated heap. */ 53bf215546Sopenharmony_ci#define VIRTGPU_PARAM_GUEST_VRAM 9 54bf215546Sopenharmony_ci#endif 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci#ifndef VIRTGPU_BLOB_MEM_GUEST_VRAM 57bf215546Sopenharmony_ci#define VIRTGPU_BLOB_MEM_GUEST_VRAM 0x0004 58bf215546Sopenharmony_ci#endif 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci/* XXX comment these out to really use kernel uapi */ 61bf215546Sopenharmony_ci#define SIMULATE_BO_SIZE_FIX 1 62bf215546Sopenharmony_ci//#define SIMULATE_CONTEXT_INIT 1 63bf215546Sopenharmony_ci#define SIMULATE_SYNCOBJ 1 64bf215546Sopenharmony_ci#define SIMULATE_SUBMIT 1 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci#define VIRTGPU_PCI_VENDOR_ID 0x1af4 67bf215546Sopenharmony_ci#define VIRTGPU_PCI_DEVICE_ID 0x1050 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cistruct virtgpu; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistruct virtgpu_shmem { 72bf215546Sopenharmony_ci struct vn_renderer_shmem base; 73bf215546Sopenharmony_ci uint32_t gem_handle; 74bf215546Sopenharmony_ci}; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistruct virtgpu_bo { 77bf215546Sopenharmony_ci struct vn_renderer_bo base; 78bf215546Sopenharmony_ci uint32_t gem_handle; 79bf215546Sopenharmony_ci uint32_t blob_flags; 80bf215546Sopenharmony_ci}; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_cistruct virtgpu_sync { 83bf215546Sopenharmony_ci struct vn_renderer_sync base; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci /* 86bf215546Sopenharmony_ci * drm_syncobj is in one of these states 87bf215546Sopenharmony_ci * 88bf215546Sopenharmony_ci * - value N: drm_syncobj has a signaled fence chain with seqno N 89bf215546Sopenharmony_ci * - pending N->M: drm_syncobj has an unsignaled fence chain with seqno M 90bf215546Sopenharmony_ci * (which may point to another unsignaled fence chain with 91bf215546Sopenharmony_ci * seqno between N and M, and so on) 92bf215546Sopenharmony_ci * 93bf215546Sopenharmony_ci * TODO Do we want to use binary drm_syncobjs? They would be 94bf215546Sopenharmony_ci * 95bf215546Sopenharmony_ci * - value 0: drm_syncobj has no fence 96bf215546Sopenharmony_ci * - value 1: drm_syncobj has a signaled fence with seqno 0 97bf215546Sopenharmony_ci * 98bf215546Sopenharmony_ci * They are cheaper but require special care. 99bf215546Sopenharmony_ci */ 100bf215546Sopenharmony_ci uint32_t syncobj_handle; 101bf215546Sopenharmony_ci}; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_cistruct virtgpu { 104bf215546Sopenharmony_ci struct vn_renderer base; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci struct vn_instance *instance; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci int fd; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci bool has_primary; 111bf215546Sopenharmony_ci int primary_major; 112bf215546Sopenharmony_ci int primary_minor; 113bf215546Sopenharmony_ci int render_major; 114bf215546Sopenharmony_ci int render_minor; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci int bustype; 117bf215546Sopenharmony_ci drmPciBusInfo pci_bus_info; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci uint32_t max_sync_queue_count; 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci struct { 122bf215546Sopenharmony_ci enum virgl_renderer_capset id; 123bf215546Sopenharmony_ci uint32_t version; 124bf215546Sopenharmony_ci struct virgl_renderer_capset_venus data; 125bf215546Sopenharmony_ci } capset; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci uint32_t shmem_blob_mem; 128bf215546Sopenharmony_ci uint32_t bo_blob_mem; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci /* note that we use gem_handle instead of res_id to index because 131bf215546Sopenharmony_ci * res_id is monotonically increasing by default (see 132bf215546Sopenharmony_ci * virtio_gpu_resource_id_get) 133bf215546Sopenharmony_ci */ 134bf215546Sopenharmony_ci struct util_sparse_array shmem_array; 135bf215546Sopenharmony_ci struct util_sparse_array bo_array; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci mtx_t dma_buf_import_mutex; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci struct vn_renderer_shmem_cache shmem_cache; 140bf215546Sopenharmony_ci}; 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci#include "util/hash_table.h" 145bf215546Sopenharmony_ci#include "util/u_idalloc.h" 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_cistatic struct { 148bf215546Sopenharmony_ci mtx_t mutex; 149bf215546Sopenharmony_ci struct hash_table *syncobjs; 150bf215546Sopenharmony_ci struct util_idalloc ida; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci int signaled_fd; 153bf215546Sopenharmony_ci} sim; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_cistruct sim_syncobj { 156bf215546Sopenharmony_ci mtx_t mutex; 157bf215546Sopenharmony_ci uint64_t point; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci int pending_fd; 160bf215546Sopenharmony_ci uint64_t pending_point; 161bf215546Sopenharmony_ci bool pending_cpu; 162bf215546Sopenharmony_ci}; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_cistatic uint32_t 165bf215546Sopenharmony_cisim_syncobj_create(struct virtgpu *gpu, bool signaled) 166bf215546Sopenharmony_ci{ 167bf215546Sopenharmony_ci struct sim_syncobj *syncobj = calloc(1, sizeof(*syncobj)); 168bf215546Sopenharmony_ci if (!syncobj) 169bf215546Sopenharmony_ci return 0; 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci mtx_init(&syncobj->mutex, mtx_plain); 172bf215546Sopenharmony_ci syncobj->pending_fd = -1; 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci mtx_lock(&sim.mutex); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci /* initialize lazily */ 177bf215546Sopenharmony_ci if (!sim.syncobjs) { 178bf215546Sopenharmony_ci sim.syncobjs = _mesa_pointer_hash_table_create(NULL); 179bf215546Sopenharmony_ci if (!sim.syncobjs) { 180bf215546Sopenharmony_ci mtx_unlock(&sim.mutex); 181bf215546Sopenharmony_ci return 0; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci util_idalloc_init(&sim.ida, 32); 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci struct drm_virtgpu_execbuffer args = { 187bf215546Sopenharmony_ci .flags = VIRTGPU_EXECBUF_FENCE_FD_OUT, 188bf215546Sopenharmony_ci }; 189bf215546Sopenharmony_ci int ret = drmIoctl(gpu->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &args); 190bf215546Sopenharmony_ci if (ret || args.fence_fd < 0) { 191bf215546Sopenharmony_ci _mesa_hash_table_destroy(sim.syncobjs, NULL); 192bf215546Sopenharmony_ci sim.syncobjs = NULL; 193bf215546Sopenharmony_ci mtx_unlock(&sim.mutex); 194bf215546Sopenharmony_ci return 0; 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci sim.signaled_fd = args.fence_fd; 198bf215546Sopenharmony_ci } 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci const unsigned syncobj_handle = util_idalloc_alloc(&sim.ida) + 1; 201bf215546Sopenharmony_ci _mesa_hash_table_insert(sim.syncobjs, 202bf215546Sopenharmony_ci (const void *)(uintptr_t)syncobj_handle, syncobj); 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci mtx_unlock(&sim.mutex); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci return syncobj_handle; 207bf215546Sopenharmony_ci} 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_cistatic void 210bf215546Sopenharmony_cisim_syncobj_destroy(struct virtgpu *gpu, uint32_t syncobj_handle) 211bf215546Sopenharmony_ci{ 212bf215546Sopenharmony_ci struct sim_syncobj *syncobj = NULL; 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci mtx_lock(&sim.mutex); 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search( 217bf215546Sopenharmony_ci sim.syncobjs, (const void *)(uintptr_t)syncobj_handle); 218bf215546Sopenharmony_ci if (entry) { 219bf215546Sopenharmony_ci syncobj = entry->data; 220bf215546Sopenharmony_ci _mesa_hash_table_remove(sim.syncobjs, entry); 221bf215546Sopenharmony_ci util_idalloc_free(&sim.ida, syncobj_handle - 1); 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci mtx_unlock(&sim.mutex); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (syncobj) { 227bf215546Sopenharmony_ci if (syncobj->pending_fd >= 0) 228bf215546Sopenharmony_ci close(syncobj->pending_fd); 229bf215546Sopenharmony_ci mtx_destroy(&syncobj->mutex); 230bf215546Sopenharmony_ci free(syncobj); 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci} 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_cistatic VkResult 235bf215546Sopenharmony_cisim_syncobj_poll(int fd, int poll_timeout) 236bf215546Sopenharmony_ci{ 237bf215546Sopenharmony_ci struct pollfd pollfd = { 238bf215546Sopenharmony_ci .fd = fd, 239bf215546Sopenharmony_ci .events = POLLIN, 240bf215546Sopenharmony_ci }; 241bf215546Sopenharmony_ci int ret; 242bf215546Sopenharmony_ci do { 243bf215546Sopenharmony_ci ret = poll(&pollfd, 1, poll_timeout); 244bf215546Sopenharmony_ci } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci if (ret < 0 || (ret > 0 && !(pollfd.revents & POLLIN))) { 247bf215546Sopenharmony_ci return (ret < 0 && errno == ENOMEM) ? VK_ERROR_OUT_OF_HOST_MEMORY 248bf215546Sopenharmony_ci : VK_ERROR_DEVICE_LOST; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci return ret ? VK_SUCCESS : VK_TIMEOUT; 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_cistatic void 255bf215546Sopenharmony_cisim_syncobj_set_point_locked(struct sim_syncobj *syncobj, uint64_t point) 256bf215546Sopenharmony_ci{ 257bf215546Sopenharmony_ci syncobj->point = point; 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci if (syncobj->pending_fd >= 0) { 260bf215546Sopenharmony_ci close(syncobj->pending_fd); 261bf215546Sopenharmony_ci syncobj->pending_fd = -1; 262bf215546Sopenharmony_ci syncobj->pending_point = point; 263bf215546Sopenharmony_ci } 264bf215546Sopenharmony_ci} 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_cistatic void 267bf215546Sopenharmony_cisim_syncobj_update_point_locked(struct sim_syncobj *syncobj, int poll_timeout) 268bf215546Sopenharmony_ci{ 269bf215546Sopenharmony_ci if (syncobj->pending_fd >= 0) { 270bf215546Sopenharmony_ci VkResult result; 271bf215546Sopenharmony_ci if (syncobj->pending_cpu) { 272bf215546Sopenharmony_ci if (poll_timeout == -1) { 273bf215546Sopenharmony_ci const int max_cpu_timeout = 2000; 274bf215546Sopenharmony_ci poll_timeout = max_cpu_timeout; 275bf215546Sopenharmony_ci result = sim_syncobj_poll(syncobj->pending_fd, poll_timeout); 276bf215546Sopenharmony_ci if (result == VK_TIMEOUT) { 277bf215546Sopenharmony_ci vn_log(NULL, "cpu sync timed out after %dms; ignoring", 278bf215546Sopenharmony_ci poll_timeout); 279bf215546Sopenharmony_ci result = VK_SUCCESS; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci } else { 282bf215546Sopenharmony_ci result = sim_syncobj_poll(syncobj->pending_fd, poll_timeout); 283bf215546Sopenharmony_ci } 284bf215546Sopenharmony_ci } else { 285bf215546Sopenharmony_ci result = sim_syncobj_poll(syncobj->pending_fd, poll_timeout); 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci if (result == VK_SUCCESS) { 288bf215546Sopenharmony_ci close(syncobj->pending_fd); 289bf215546Sopenharmony_ci syncobj->pending_fd = -1; 290bf215546Sopenharmony_ci syncobj->point = syncobj->pending_point; 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci} 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_cistatic struct sim_syncobj * 296bf215546Sopenharmony_cisim_syncobj_lookup(struct virtgpu *gpu, uint32_t syncobj_handle) 297bf215546Sopenharmony_ci{ 298bf215546Sopenharmony_ci struct sim_syncobj *syncobj = NULL; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci mtx_lock(&sim.mutex); 301bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search( 302bf215546Sopenharmony_ci sim.syncobjs, (const void *)(uintptr_t)syncobj_handle); 303bf215546Sopenharmony_ci if (entry) 304bf215546Sopenharmony_ci syncobj = entry->data; 305bf215546Sopenharmony_ci mtx_unlock(&sim.mutex); 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci return syncobj; 308bf215546Sopenharmony_ci} 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_cistatic int 311bf215546Sopenharmony_cisim_syncobj_reset(struct virtgpu *gpu, uint32_t syncobj_handle) 312bf215546Sopenharmony_ci{ 313bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 314bf215546Sopenharmony_ci if (!syncobj) 315bf215546Sopenharmony_ci return -1; 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 318bf215546Sopenharmony_ci sim_syncobj_set_point_locked(syncobj, 0); 319bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci return 0; 322bf215546Sopenharmony_ci} 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_cistatic int 325bf215546Sopenharmony_cisim_syncobj_query(struct virtgpu *gpu, 326bf215546Sopenharmony_ci uint32_t syncobj_handle, 327bf215546Sopenharmony_ci uint64_t *point) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 330bf215546Sopenharmony_ci if (!syncobj) 331bf215546Sopenharmony_ci return -1; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 334bf215546Sopenharmony_ci sim_syncobj_update_point_locked(syncobj, 0); 335bf215546Sopenharmony_ci *point = syncobj->point; 336bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci return 0; 339bf215546Sopenharmony_ci} 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_cistatic int 342bf215546Sopenharmony_cisim_syncobj_signal(struct virtgpu *gpu, 343bf215546Sopenharmony_ci uint32_t syncobj_handle, 344bf215546Sopenharmony_ci uint64_t point) 345bf215546Sopenharmony_ci{ 346bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 347bf215546Sopenharmony_ci if (!syncobj) 348bf215546Sopenharmony_ci return -1; 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 351bf215546Sopenharmony_ci sim_syncobj_set_point_locked(syncobj, point); 352bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci return 0; 355bf215546Sopenharmony_ci} 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_cistatic int 358bf215546Sopenharmony_cisim_syncobj_submit(struct virtgpu *gpu, 359bf215546Sopenharmony_ci uint32_t syncobj_handle, 360bf215546Sopenharmony_ci int sync_fd, 361bf215546Sopenharmony_ci uint64_t point, 362bf215546Sopenharmony_ci bool cpu) 363bf215546Sopenharmony_ci{ 364bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 365bf215546Sopenharmony_ci if (!syncobj) 366bf215546Sopenharmony_ci return -1; 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci int pending_fd = dup(sync_fd); 369bf215546Sopenharmony_ci if (pending_fd < 0) { 370bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to dup sync fd"); 371bf215546Sopenharmony_ci return -1; 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci if (syncobj->pending_fd >= 0) { 377bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci /* TODO */ 380bf215546Sopenharmony_ci vn_log(gpu->instance, "sorry, no simulated timeline semaphore"); 381bf215546Sopenharmony_ci close(pending_fd); 382bf215546Sopenharmony_ci return -1; 383bf215546Sopenharmony_ci } 384bf215546Sopenharmony_ci if (syncobj->point >= point) 385bf215546Sopenharmony_ci vn_log(gpu->instance, "non-monotonic signaling"); 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci syncobj->pending_fd = pending_fd; 388bf215546Sopenharmony_ci syncobj->pending_point = point; 389bf215546Sopenharmony_ci syncobj->pending_cpu = cpu; 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci return 0; 394bf215546Sopenharmony_ci} 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_cistatic int 397bf215546Sopenharmony_citimeout_to_poll_timeout(uint64_t timeout) 398bf215546Sopenharmony_ci{ 399bf215546Sopenharmony_ci const uint64_t ns_per_ms = 1000000; 400bf215546Sopenharmony_ci const uint64_t ms = (timeout + ns_per_ms - 1) / ns_per_ms; 401bf215546Sopenharmony_ci if (!ms && timeout) 402bf215546Sopenharmony_ci return -1; 403bf215546Sopenharmony_ci return ms <= INT_MAX ? ms : -1; 404bf215546Sopenharmony_ci} 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_cistatic int 407bf215546Sopenharmony_cisim_syncobj_wait(struct virtgpu *gpu, 408bf215546Sopenharmony_ci const struct vn_renderer_wait *wait, 409bf215546Sopenharmony_ci bool wait_avail) 410bf215546Sopenharmony_ci{ 411bf215546Sopenharmony_ci if (wait_avail) 412bf215546Sopenharmony_ci return -1; 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci const int poll_timeout = timeout_to_poll_timeout(wait->timeout); 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci /* TODO poll all fds at the same time */ 417bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait->sync_count; i++) { 418bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)wait->syncs[i]; 419bf215546Sopenharmony_ci const uint64_t point = wait->sync_values[i]; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci struct sim_syncobj *syncobj = 422bf215546Sopenharmony_ci sim_syncobj_lookup(gpu, sync->syncobj_handle); 423bf215546Sopenharmony_ci if (!syncobj) 424bf215546Sopenharmony_ci return -1; 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci if (syncobj->point < point) 429bf215546Sopenharmony_ci sim_syncobj_update_point_locked(syncobj, poll_timeout); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci if (syncobj->point < point) { 432bf215546Sopenharmony_ci if (wait->wait_any && i < wait->sync_count - 1 && 433bf215546Sopenharmony_ci syncobj->pending_fd < 0) { 434bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 435bf215546Sopenharmony_ci continue; 436bf215546Sopenharmony_ci } 437bf215546Sopenharmony_ci errno = ETIME; 438bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 439bf215546Sopenharmony_ci return -1; 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci if (wait->wait_any) 445bf215546Sopenharmony_ci break; 446bf215546Sopenharmony_ci 447bf215546Sopenharmony_ci /* TODO adjust poll_timeout */ 448bf215546Sopenharmony_ci } 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci return 0; 451bf215546Sopenharmony_ci} 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_cistatic int 454bf215546Sopenharmony_cisim_syncobj_export(struct virtgpu *gpu, uint32_t syncobj_handle) 455bf215546Sopenharmony_ci{ 456bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 457bf215546Sopenharmony_ci if (!syncobj) 458bf215546Sopenharmony_ci return -1; 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci int fd = -1; 461bf215546Sopenharmony_ci mtx_lock(&syncobj->mutex); 462bf215546Sopenharmony_ci if (syncobj->pending_fd >= 0) 463bf215546Sopenharmony_ci fd = dup(syncobj->pending_fd); 464bf215546Sopenharmony_ci else 465bf215546Sopenharmony_ci fd = dup(sim.signaled_fd); 466bf215546Sopenharmony_ci mtx_unlock(&syncobj->mutex); 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci return fd; 469bf215546Sopenharmony_ci} 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_cistatic uint32_t 472bf215546Sopenharmony_cisim_syncobj_import(struct virtgpu *gpu, uint32_t syncobj_handle, int fd) 473bf215546Sopenharmony_ci{ 474bf215546Sopenharmony_ci struct sim_syncobj *syncobj = sim_syncobj_lookup(gpu, syncobj_handle); 475bf215546Sopenharmony_ci if (!syncobj) 476bf215546Sopenharmony_ci return 0; 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci if (sim_syncobj_submit(gpu, syncobj_handle, fd, 1, false)) 479bf215546Sopenharmony_ci return 0; 480bf215546Sopenharmony_ci 481bf215546Sopenharmony_ci return syncobj_handle; 482bf215546Sopenharmony_ci} 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci#endif /* SIMULATE_SYNCOBJ */ 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci#ifdef SIMULATE_SUBMIT 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_cistatic int 489bf215546Sopenharmony_cisim_submit_signal_syncs(struct virtgpu *gpu, 490bf215546Sopenharmony_ci int sync_fd, 491bf215546Sopenharmony_ci struct vn_renderer_sync *const *syncs, 492bf215546Sopenharmony_ci const uint64_t *sync_values, 493bf215546Sopenharmony_ci uint32_t sync_count, 494bf215546Sopenharmony_ci bool cpu) 495bf215546Sopenharmony_ci{ 496bf215546Sopenharmony_ci for (uint32_t i = 0; i < sync_count; i++) { 497bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)syncs[i]; 498bf215546Sopenharmony_ci const uint64_t pending_point = sync_values[i]; 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 501bf215546Sopenharmony_ci int ret = sim_syncobj_submit(gpu, sync->syncobj_handle, sync_fd, 502bf215546Sopenharmony_ci pending_point, cpu); 503bf215546Sopenharmony_ci if (ret) 504bf215546Sopenharmony_ci return ret; 505bf215546Sopenharmony_ci#else 506bf215546Sopenharmony_ci /* we can in theory do a DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE followed by a 507bf215546Sopenharmony_ci * DRM_IOCTL_SYNCOBJ_TRANSFER 508bf215546Sopenharmony_ci */ 509bf215546Sopenharmony_ci return -1; 510bf215546Sopenharmony_ci#endif 511bf215546Sopenharmony_ci } 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci return 0; 514bf215546Sopenharmony_ci} 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_cistatic uint32_t * 517bf215546Sopenharmony_cisim_submit_alloc_gem_handles(struct vn_renderer_bo *const *bos, 518bf215546Sopenharmony_ci uint32_t bo_count) 519bf215546Sopenharmony_ci{ 520bf215546Sopenharmony_ci uint32_t *gem_handles = malloc(sizeof(*gem_handles) * bo_count); 521bf215546Sopenharmony_ci if (!gem_handles) 522bf215546Sopenharmony_ci return NULL; 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci for (uint32_t i = 0; i < bo_count; i++) { 525bf215546Sopenharmony_ci struct virtgpu_bo *bo = (struct virtgpu_bo *)bos[i]; 526bf215546Sopenharmony_ci gem_handles[i] = bo->gem_handle; 527bf215546Sopenharmony_ci } 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci return gem_handles; 530bf215546Sopenharmony_ci} 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_cistatic int 533bf215546Sopenharmony_cisim_submit(struct virtgpu *gpu, const struct vn_renderer_submit *submit) 534bf215546Sopenharmony_ci{ 535bf215546Sopenharmony_ci /* TODO replace submit->bos by submit->gem_handles to avoid malloc/loop */ 536bf215546Sopenharmony_ci uint32_t *gem_handles = NULL; 537bf215546Sopenharmony_ci if (submit->bo_count) { 538bf215546Sopenharmony_ci gem_handles = 539bf215546Sopenharmony_ci sim_submit_alloc_gem_handles(submit->bos, submit->bo_count); 540bf215546Sopenharmony_ci if (!gem_handles) 541bf215546Sopenharmony_ci return -1; 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci int ret = 0; 545bf215546Sopenharmony_ci for (uint32_t i = 0; i < submit->batch_count; i++) { 546bf215546Sopenharmony_ci const struct vn_renderer_submit_batch *batch = &submit->batches[i]; 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci struct drm_virtgpu_execbuffer args = { 549bf215546Sopenharmony_ci .flags = batch->sync_count ? VIRTGPU_EXECBUF_FENCE_FD_OUT : 0, 550bf215546Sopenharmony_ci .size = batch->cs_size, 551bf215546Sopenharmony_ci .command = (uintptr_t)batch->cs_data, 552bf215546Sopenharmony_ci .bo_handles = (uintptr_t)gem_handles, 553bf215546Sopenharmony_ci .num_bo_handles = submit->bo_count, 554bf215546Sopenharmony_ci }; 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci ret = drmIoctl(gpu->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &args); 557bf215546Sopenharmony_ci if (ret) { 558bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to execbuffer: %s", strerror(errno)); 559bf215546Sopenharmony_ci break; 560bf215546Sopenharmony_ci } 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci if (batch->sync_count) { 563bf215546Sopenharmony_ci ret = sim_submit_signal_syncs(gpu, args.fence_fd, batch->syncs, 564bf215546Sopenharmony_ci batch->sync_values, batch->sync_count, 565bf215546Sopenharmony_ci batch->sync_queue_cpu); 566bf215546Sopenharmony_ci close(args.fence_fd); 567bf215546Sopenharmony_ci if (ret) 568bf215546Sopenharmony_ci break; 569bf215546Sopenharmony_ci } 570bf215546Sopenharmony_ci } 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci if (!submit->batch_count && submit->bo_count) { 573bf215546Sopenharmony_ci struct drm_virtgpu_execbuffer args = { 574bf215546Sopenharmony_ci .bo_handles = (uintptr_t)gem_handles, 575bf215546Sopenharmony_ci .num_bo_handles = submit->bo_count, 576bf215546Sopenharmony_ci }; 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci ret = drmIoctl(gpu->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &args); 579bf215546Sopenharmony_ci if (ret) 580bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to execbuffer: %s", strerror(errno)); 581bf215546Sopenharmony_ci } 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci free(gem_handles); 584bf215546Sopenharmony_ci 585bf215546Sopenharmony_ci return ret; 586bf215546Sopenharmony_ci} 587bf215546Sopenharmony_ci 588bf215546Sopenharmony_ci#endif /* SIMULATE_SUBMIT */ 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_cistatic int 591bf215546Sopenharmony_civirtgpu_ioctl(struct virtgpu *gpu, unsigned long request, void *args) 592bf215546Sopenharmony_ci{ 593bf215546Sopenharmony_ci return drmIoctl(gpu->fd, request, args); 594bf215546Sopenharmony_ci} 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_cistatic uint64_t 597bf215546Sopenharmony_civirtgpu_ioctl_getparam(struct virtgpu *gpu, uint64_t param) 598bf215546Sopenharmony_ci{ 599bf215546Sopenharmony_ci#ifdef SIMULATE_CONTEXT_INIT 600bf215546Sopenharmony_ci if (param == VIRTGPU_PARAM_CONTEXT_INIT) 601bf215546Sopenharmony_ci return 1; 602bf215546Sopenharmony_ci#endif 603bf215546Sopenharmony_ci#ifdef SIMULATE_SUBMIT 604bf215546Sopenharmony_ci if (param == VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT) 605bf215546Sopenharmony_ci return 16; 606bf215546Sopenharmony_ci#endif 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci /* val must be zeroed because kernel only writes the lower 32 bits */ 609bf215546Sopenharmony_ci uint64_t val = 0; 610bf215546Sopenharmony_ci struct drm_virtgpu_getparam args = { 611bf215546Sopenharmony_ci .param = param, 612bf215546Sopenharmony_ci .value = (uintptr_t)&val, 613bf215546Sopenharmony_ci }; 614bf215546Sopenharmony_ci 615bf215546Sopenharmony_ci const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_GETPARAM, &args); 616bf215546Sopenharmony_ci return ret ? 0 : val; 617bf215546Sopenharmony_ci} 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_cistatic int 620bf215546Sopenharmony_civirtgpu_ioctl_get_caps(struct virtgpu *gpu, 621bf215546Sopenharmony_ci enum virgl_renderer_capset id, 622bf215546Sopenharmony_ci uint32_t version, 623bf215546Sopenharmony_ci void *capset, 624bf215546Sopenharmony_ci size_t capset_size) 625bf215546Sopenharmony_ci{ 626bf215546Sopenharmony_ci#ifdef SIMULATE_CONTEXT_INIT 627bf215546Sopenharmony_ci if (id == VIRGL_RENDERER_CAPSET_VENUS && version == 0) 628bf215546Sopenharmony_ci return 0; 629bf215546Sopenharmony_ci#endif 630bf215546Sopenharmony_ci 631bf215546Sopenharmony_ci struct drm_virtgpu_get_caps args = { 632bf215546Sopenharmony_ci .cap_set_id = id, 633bf215546Sopenharmony_ci .cap_set_ver = version, 634bf215546Sopenharmony_ci .addr = (uintptr_t)capset, 635bf215546Sopenharmony_ci .size = capset_size, 636bf215546Sopenharmony_ci }; 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_GET_CAPS, &args); 639bf215546Sopenharmony_ci} 640bf215546Sopenharmony_ci 641bf215546Sopenharmony_cistatic int 642bf215546Sopenharmony_civirtgpu_ioctl_context_init(struct virtgpu *gpu, 643bf215546Sopenharmony_ci enum virgl_renderer_capset capset_id) 644bf215546Sopenharmony_ci{ 645bf215546Sopenharmony_ci#ifdef SIMULATE_CONTEXT_INIT 646bf215546Sopenharmony_ci if (capset_id == VIRGL_RENDERER_CAPSET_VENUS) 647bf215546Sopenharmony_ci return 0; 648bf215546Sopenharmony_ci#endif 649bf215546Sopenharmony_ci 650bf215546Sopenharmony_ci struct drm_virtgpu_context_init args = { 651bf215546Sopenharmony_ci .num_params = 1, 652bf215546Sopenharmony_ci .ctx_set_params = (uintptr_t) & 653bf215546Sopenharmony_ci (struct drm_virtgpu_context_set_param){ 654bf215546Sopenharmony_ci .param = VIRTGPU_CONTEXT_PARAM_CAPSET_ID, 655bf215546Sopenharmony_ci .value = capset_id, 656bf215546Sopenharmony_ci }, 657bf215546Sopenharmony_ci }; 658bf215546Sopenharmony_ci 659bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_CONTEXT_INIT, &args); 660bf215546Sopenharmony_ci} 661bf215546Sopenharmony_ci 662bf215546Sopenharmony_cistatic uint32_t 663bf215546Sopenharmony_civirtgpu_ioctl_resource_create_blob(struct virtgpu *gpu, 664bf215546Sopenharmony_ci uint32_t blob_mem, 665bf215546Sopenharmony_ci uint32_t blob_flags, 666bf215546Sopenharmony_ci size_t blob_size, 667bf215546Sopenharmony_ci uint64_t blob_id, 668bf215546Sopenharmony_ci uint32_t *res_id) 669bf215546Sopenharmony_ci{ 670bf215546Sopenharmony_ci#ifdef SIMULATE_BO_SIZE_FIX 671bf215546Sopenharmony_ci blob_size = align64(blob_size, 4096); 672bf215546Sopenharmony_ci#endif 673bf215546Sopenharmony_ci 674bf215546Sopenharmony_ci struct drm_virtgpu_resource_create_blob args = { 675bf215546Sopenharmony_ci .blob_mem = blob_mem, 676bf215546Sopenharmony_ci .blob_flags = blob_flags, 677bf215546Sopenharmony_ci .size = blob_size, 678bf215546Sopenharmony_ci .blob_id = blob_id, 679bf215546Sopenharmony_ci }; 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci if (virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &args)) 682bf215546Sopenharmony_ci return 0; 683bf215546Sopenharmony_ci 684bf215546Sopenharmony_ci *res_id = args.res_handle; 685bf215546Sopenharmony_ci return args.bo_handle; 686bf215546Sopenharmony_ci} 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_cistatic int 689bf215546Sopenharmony_civirtgpu_ioctl_resource_info(struct virtgpu *gpu, 690bf215546Sopenharmony_ci uint32_t gem_handle, 691bf215546Sopenharmony_ci struct drm_virtgpu_resource_info *info) 692bf215546Sopenharmony_ci{ 693bf215546Sopenharmony_ci *info = (struct drm_virtgpu_resource_info){ 694bf215546Sopenharmony_ci .bo_handle = gem_handle, 695bf215546Sopenharmony_ci }; 696bf215546Sopenharmony_ci 697bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_RESOURCE_INFO, info); 698bf215546Sopenharmony_ci} 699bf215546Sopenharmony_ci 700bf215546Sopenharmony_cistatic void 701bf215546Sopenharmony_civirtgpu_ioctl_gem_close(struct virtgpu *gpu, uint32_t gem_handle) 702bf215546Sopenharmony_ci{ 703bf215546Sopenharmony_ci struct drm_gem_close args = { 704bf215546Sopenharmony_ci .handle = gem_handle, 705bf215546Sopenharmony_ci }; 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci ASSERTED const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_GEM_CLOSE, &args); 708bf215546Sopenharmony_ci assert(!ret); 709bf215546Sopenharmony_ci} 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_cistatic int 712bf215546Sopenharmony_civirtgpu_ioctl_prime_handle_to_fd(struct virtgpu *gpu, 713bf215546Sopenharmony_ci uint32_t gem_handle, 714bf215546Sopenharmony_ci bool mappable) 715bf215546Sopenharmony_ci{ 716bf215546Sopenharmony_ci struct drm_prime_handle args = { 717bf215546Sopenharmony_ci .handle = gem_handle, 718bf215546Sopenharmony_ci .flags = DRM_CLOEXEC | (mappable ? DRM_RDWR : 0), 719bf215546Sopenharmony_ci }; 720bf215546Sopenharmony_ci 721bf215546Sopenharmony_ci const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 722bf215546Sopenharmony_ci return ret ? -1 : args.fd; 723bf215546Sopenharmony_ci} 724bf215546Sopenharmony_ci 725bf215546Sopenharmony_cistatic uint32_t 726bf215546Sopenharmony_civirtgpu_ioctl_prime_fd_to_handle(struct virtgpu *gpu, int fd) 727bf215546Sopenharmony_ci{ 728bf215546Sopenharmony_ci struct drm_prime_handle args = { 729bf215546Sopenharmony_ci .fd = fd, 730bf215546Sopenharmony_ci }; 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_ci const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 733bf215546Sopenharmony_ci return ret ? 0 : args.handle; 734bf215546Sopenharmony_ci} 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_cistatic void * 737bf215546Sopenharmony_civirtgpu_ioctl_map(struct virtgpu *gpu, uint32_t gem_handle, size_t size) 738bf215546Sopenharmony_ci{ 739bf215546Sopenharmony_ci struct drm_virtgpu_map args = { 740bf215546Sopenharmony_ci .handle = gem_handle, 741bf215546Sopenharmony_ci }; 742bf215546Sopenharmony_ci 743bf215546Sopenharmony_ci if (virtgpu_ioctl(gpu, DRM_IOCTL_VIRTGPU_MAP, &args)) 744bf215546Sopenharmony_ci return NULL; 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, gpu->fd, 747bf215546Sopenharmony_ci args.offset); 748bf215546Sopenharmony_ci if (ptr == MAP_FAILED) 749bf215546Sopenharmony_ci return NULL; 750bf215546Sopenharmony_ci 751bf215546Sopenharmony_ci return ptr; 752bf215546Sopenharmony_ci} 753bf215546Sopenharmony_ci 754bf215546Sopenharmony_cistatic uint32_t 755bf215546Sopenharmony_civirtgpu_ioctl_syncobj_create(struct virtgpu *gpu, bool signaled) 756bf215546Sopenharmony_ci{ 757bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 758bf215546Sopenharmony_ci return sim_syncobj_create(gpu, signaled); 759bf215546Sopenharmony_ci#endif 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci struct drm_syncobj_create args = { 762bf215546Sopenharmony_ci .flags = signaled ? DRM_SYNCOBJ_CREATE_SIGNALED : 0, 763bf215546Sopenharmony_ci }; 764bf215546Sopenharmony_ci 765bf215546Sopenharmony_ci const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_CREATE, &args); 766bf215546Sopenharmony_ci return ret ? 0 : args.handle; 767bf215546Sopenharmony_ci} 768bf215546Sopenharmony_ci 769bf215546Sopenharmony_cistatic void 770bf215546Sopenharmony_civirtgpu_ioctl_syncobj_destroy(struct virtgpu *gpu, uint32_t syncobj_handle) 771bf215546Sopenharmony_ci{ 772bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 773bf215546Sopenharmony_ci sim_syncobj_destroy(gpu, syncobj_handle); 774bf215546Sopenharmony_ci return; 775bf215546Sopenharmony_ci#endif 776bf215546Sopenharmony_ci 777bf215546Sopenharmony_ci struct drm_syncobj_destroy args = { 778bf215546Sopenharmony_ci .handle = syncobj_handle, 779bf215546Sopenharmony_ci }; 780bf215546Sopenharmony_ci 781bf215546Sopenharmony_ci ASSERTED const int ret = 782bf215546Sopenharmony_ci virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 783bf215546Sopenharmony_ci assert(!ret); 784bf215546Sopenharmony_ci} 785bf215546Sopenharmony_ci 786bf215546Sopenharmony_cistatic int 787bf215546Sopenharmony_civirtgpu_ioctl_syncobj_handle_to_fd(struct virtgpu *gpu, 788bf215546Sopenharmony_ci uint32_t syncobj_handle, 789bf215546Sopenharmony_ci bool sync_file) 790bf215546Sopenharmony_ci{ 791bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 792bf215546Sopenharmony_ci return sync_file ? sim_syncobj_export(gpu, syncobj_handle) : -1; 793bf215546Sopenharmony_ci#endif 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_ci struct drm_syncobj_handle args = { 796bf215546Sopenharmony_ci .handle = syncobj_handle, 797bf215546Sopenharmony_ci .flags = 798bf215546Sopenharmony_ci sync_file ? DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE : 0, 799bf215546Sopenharmony_ci }; 800bf215546Sopenharmony_ci 801bf215546Sopenharmony_ci int ret = virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 802bf215546Sopenharmony_ci if (ret) 803bf215546Sopenharmony_ci return -1; 804bf215546Sopenharmony_ci 805bf215546Sopenharmony_ci return args.fd; 806bf215546Sopenharmony_ci} 807bf215546Sopenharmony_ci 808bf215546Sopenharmony_cistatic uint32_t 809bf215546Sopenharmony_civirtgpu_ioctl_syncobj_fd_to_handle(struct virtgpu *gpu, 810bf215546Sopenharmony_ci int fd, 811bf215546Sopenharmony_ci uint32_t syncobj_handle) 812bf215546Sopenharmony_ci{ 813bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 814bf215546Sopenharmony_ci return syncobj_handle ? sim_syncobj_import(gpu, syncobj_handle, fd) : 0; 815bf215546Sopenharmony_ci#endif 816bf215546Sopenharmony_ci 817bf215546Sopenharmony_ci struct drm_syncobj_handle args = { 818bf215546Sopenharmony_ci .handle = syncobj_handle, 819bf215546Sopenharmony_ci .flags = 820bf215546Sopenharmony_ci syncobj_handle ? DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE : 0, 821bf215546Sopenharmony_ci .fd = fd, 822bf215546Sopenharmony_ci }; 823bf215546Sopenharmony_ci 824bf215546Sopenharmony_ci int ret = virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 825bf215546Sopenharmony_ci if (ret) 826bf215546Sopenharmony_ci return 0; 827bf215546Sopenharmony_ci 828bf215546Sopenharmony_ci return args.handle; 829bf215546Sopenharmony_ci} 830bf215546Sopenharmony_ci 831bf215546Sopenharmony_cistatic int 832bf215546Sopenharmony_civirtgpu_ioctl_syncobj_reset(struct virtgpu *gpu, uint32_t syncobj_handle) 833bf215546Sopenharmony_ci{ 834bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 835bf215546Sopenharmony_ci return sim_syncobj_reset(gpu, syncobj_handle); 836bf215546Sopenharmony_ci#endif 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_ci struct drm_syncobj_array args = { 839bf215546Sopenharmony_ci .handles = (uintptr_t)&syncobj_handle, 840bf215546Sopenharmony_ci .count_handles = 1, 841bf215546Sopenharmony_ci }; 842bf215546Sopenharmony_ci 843bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_RESET, &args); 844bf215546Sopenharmony_ci} 845bf215546Sopenharmony_ci 846bf215546Sopenharmony_cistatic int 847bf215546Sopenharmony_civirtgpu_ioctl_syncobj_query(struct virtgpu *gpu, 848bf215546Sopenharmony_ci uint32_t syncobj_handle, 849bf215546Sopenharmony_ci uint64_t *point) 850bf215546Sopenharmony_ci{ 851bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 852bf215546Sopenharmony_ci return sim_syncobj_query(gpu, syncobj_handle, point); 853bf215546Sopenharmony_ci#endif 854bf215546Sopenharmony_ci 855bf215546Sopenharmony_ci struct drm_syncobj_timeline_array args = { 856bf215546Sopenharmony_ci .handles = (uintptr_t)&syncobj_handle, 857bf215546Sopenharmony_ci .points = (uintptr_t)point, 858bf215546Sopenharmony_ci .count_handles = 1, 859bf215546Sopenharmony_ci }; 860bf215546Sopenharmony_ci 861bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_QUERY, &args); 862bf215546Sopenharmony_ci} 863bf215546Sopenharmony_ci 864bf215546Sopenharmony_cistatic int 865bf215546Sopenharmony_civirtgpu_ioctl_syncobj_timeline_signal(struct virtgpu *gpu, 866bf215546Sopenharmony_ci uint32_t syncobj_handle, 867bf215546Sopenharmony_ci uint64_t point) 868bf215546Sopenharmony_ci{ 869bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 870bf215546Sopenharmony_ci return sim_syncobj_signal(gpu, syncobj_handle, point); 871bf215546Sopenharmony_ci#endif 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci struct drm_syncobj_timeline_array args = { 874bf215546Sopenharmony_ci .handles = (uintptr_t)&syncobj_handle, 875bf215546Sopenharmony_ci .points = (uintptr_t)&point, 876bf215546Sopenharmony_ci .count_handles = 1, 877bf215546Sopenharmony_ci }; 878bf215546Sopenharmony_ci 879bf215546Sopenharmony_ci return virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 880bf215546Sopenharmony_ci} 881bf215546Sopenharmony_ci 882bf215546Sopenharmony_cistatic int 883bf215546Sopenharmony_civirtgpu_ioctl_syncobj_timeline_wait(struct virtgpu *gpu, 884bf215546Sopenharmony_ci const struct vn_renderer_wait *wait, 885bf215546Sopenharmony_ci bool wait_avail) 886bf215546Sopenharmony_ci{ 887bf215546Sopenharmony_ci#ifdef SIMULATE_SYNCOBJ 888bf215546Sopenharmony_ci return sim_syncobj_wait(gpu, wait, wait_avail); 889bf215546Sopenharmony_ci#endif 890bf215546Sopenharmony_ci 891bf215546Sopenharmony_ci /* always enable wait-before-submit */ 892bf215546Sopenharmony_ci uint32_t flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT; 893bf215546Sopenharmony_ci if (!wait->wait_any) 894bf215546Sopenharmony_ci flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; 895bf215546Sopenharmony_ci /* wait for fences to appear instead of signaling */ 896bf215546Sopenharmony_ci if (wait_avail) 897bf215546Sopenharmony_ci flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE; 898bf215546Sopenharmony_ci 899bf215546Sopenharmony_ci /* TODO replace wait->syncs by wait->sync_handles to avoid malloc/loop */ 900bf215546Sopenharmony_ci uint32_t *syncobj_handles = 901bf215546Sopenharmony_ci malloc(sizeof(*syncobj_handles) * wait->sync_count); 902bf215546Sopenharmony_ci if (!syncobj_handles) 903bf215546Sopenharmony_ci return -1; 904bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait->sync_count; i++) { 905bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)wait->syncs[i]; 906bf215546Sopenharmony_ci syncobj_handles[i] = sync->syncobj_handle; 907bf215546Sopenharmony_ci } 908bf215546Sopenharmony_ci 909bf215546Sopenharmony_ci struct drm_syncobj_timeline_wait args = { 910bf215546Sopenharmony_ci .handles = (uintptr_t)syncobj_handles, 911bf215546Sopenharmony_ci .points = (uintptr_t)wait->sync_values, 912bf215546Sopenharmony_ci .timeout_nsec = os_time_get_absolute_timeout(wait->timeout), 913bf215546Sopenharmony_ci .count_handles = wait->sync_count, 914bf215546Sopenharmony_ci .flags = flags, 915bf215546Sopenharmony_ci }; 916bf215546Sopenharmony_ci 917bf215546Sopenharmony_ci const int ret = virtgpu_ioctl(gpu, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 918bf215546Sopenharmony_ci 919bf215546Sopenharmony_ci free(syncobj_handles); 920bf215546Sopenharmony_ci 921bf215546Sopenharmony_ci return ret; 922bf215546Sopenharmony_ci} 923bf215546Sopenharmony_ci 924bf215546Sopenharmony_cistatic int 925bf215546Sopenharmony_civirtgpu_ioctl_submit(struct virtgpu *gpu, 926bf215546Sopenharmony_ci const struct vn_renderer_submit *submit) 927bf215546Sopenharmony_ci{ 928bf215546Sopenharmony_ci#ifdef SIMULATE_SUBMIT 929bf215546Sopenharmony_ci return sim_submit(gpu, submit); 930bf215546Sopenharmony_ci#endif 931bf215546Sopenharmony_ci return -1; 932bf215546Sopenharmony_ci} 933bf215546Sopenharmony_ci 934bf215546Sopenharmony_cistatic VkResult 935bf215546Sopenharmony_civirtgpu_sync_write(struct vn_renderer *renderer, 936bf215546Sopenharmony_ci struct vn_renderer_sync *_sync, 937bf215546Sopenharmony_ci uint64_t val) 938bf215546Sopenharmony_ci{ 939bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 940bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)_sync; 941bf215546Sopenharmony_ci 942bf215546Sopenharmony_ci const int ret = 943bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_timeline_signal(gpu, sync->syncobj_handle, val); 944bf215546Sopenharmony_ci 945bf215546Sopenharmony_ci return ret ? VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_SUCCESS; 946bf215546Sopenharmony_ci} 947bf215546Sopenharmony_ci 948bf215546Sopenharmony_cistatic VkResult 949bf215546Sopenharmony_civirtgpu_sync_read(struct vn_renderer *renderer, 950bf215546Sopenharmony_ci struct vn_renderer_sync *_sync, 951bf215546Sopenharmony_ci uint64_t *val) 952bf215546Sopenharmony_ci{ 953bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 954bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)_sync; 955bf215546Sopenharmony_ci 956bf215546Sopenharmony_ci const int ret = 957bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_query(gpu, sync->syncobj_handle, val); 958bf215546Sopenharmony_ci 959bf215546Sopenharmony_ci return ret ? VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_SUCCESS; 960bf215546Sopenharmony_ci} 961bf215546Sopenharmony_ci 962bf215546Sopenharmony_cistatic VkResult 963bf215546Sopenharmony_civirtgpu_sync_reset(struct vn_renderer *renderer, 964bf215546Sopenharmony_ci struct vn_renderer_sync *_sync, 965bf215546Sopenharmony_ci uint64_t initial_val) 966bf215546Sopenharmony_ci{ 967bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 968bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)_sync; 969bf215546Sopenharmony_ci 970bf215546Sopenharmony_ci int ret = virtgpu_ioctl_syncobj_reset(gpu, sync->syncobj_handle); 971bf215546Sopenharmony_ci if (!ret) { 972bf215546Sopenharmony_ci ret = virtgpu_ioctl_syncobj_timeline_signal(gpu, sync->syncobj_handle, 973bf215546Sopenharmony_ci initial_val); 974bf215546Sopenharmony_ci } 975bf215546Sopenharmony_ci 976bf215546Sopenharmony_ci return ret ? VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_SUCCESS; 977bf215546Sopenharmony_ci} 978bf215546Sopenharmony_ci 979bf215546Sopenharmony_cistatic int 980bf215546Sopenharmony_civirtgpu_sync_export_syncobj(struct vn_renderer *renderer, 981bf215546Sopenharmony_ci struct vn_renderer_sync *_sync, 982bf215546Sopenharmony_ci bool sync_file) 983bf215546Sopenharmony_ci{ 984bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 985bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)_sync; 986bf215546Sopenharmony_ci 987bf215546Sopenharmony_ci return virtgpu_ioctl_syncobj_handle_to_fd(gpu, sync->syncobj_handle, 988bf215546Sopenharmony_ci sync_file); 989bf215546Sopenharmony_ci} 990bf215546Sopenharmony_ci 991bf215546Sopenharmony_cistatic void 992bf215546Sopenharmony_civirtgpu_sync_destroy(struct vn_renderer *renderer, 993bf215546Sopenharmony_ci struct vn_renderer_sync *_sync) 994bf215546Sopenharmony_ci{ 995bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 996bf215546Sopenharmony_ci struct virtgpu_sync *sync = (struct virtgpu_sync *)_sync; 997bf215546Sopenharmony_ci 998bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_destroy(gpu, sync->syncobj_handle); 999bf215546Sopenharmony_ci 1000bf215546Sopenharmony_ci free(sync); 1001bf215546Sopenharmony_ci} 1002bf215546Sopenharmony_ci 1003bf215546Sopenharmony_cistatic VkResult 1004bf215546Sopenharmony_civirtgpu_sync_create_from_syncobj(struct vn_renderer *renderer, 1005bf215546Sopenharmony_ci int fd, 1006bf215546Sopenharmony_ci bool sync_file, 1007bf215546Sopenharmony_ci struct vn_renderer_sync **out_sync) 1008bf215546Sopenharmony_ci{ 1009bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci uint32_t syncobj_handle; 1012bf215546Sopenharmony_ci if (sync_file) { 1013bf215546Sopenharmony_ci syncobj_handle = virtgpu_ioctl_syncobj_create(gpu, false); 1014bf215546Sopenharmony_ci if (!syncobj_handle) 1015bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 1016bf215546Sopenharmony_ci if (!virtgpu_ioctl_syncobj_fd_to_handle(gpu, fd, syncobj_handle)) { 1017bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_destroy(gpu, syncobj_handle); 1018bf215546Sopenharmony_ci return VK_ERROR_INVALID_EXTERNAL_HANDLE; 1019bf215546Sopenharmony_ci } 1020bf215546Sopenharmony_ci } else { 1021bf215546Sopenharmony_ci syncobj_handle = virtgpu_ioctl_syncobj_fd_to_handle(gpu, fd, 0); 1022bf215546Sopenharmony_ci if (!syncobj_handle) 1023bf215546Sopenharmony_ci return VK_ERROR_INVALID_EXTERNAL_HANDLE; 1024bf215546Sopenharmony_ci } 1025bf215546Sopenharmony_ci 1026bf215546Sopenharmony_ci struct virtgpu_sync *sync = calloc(1, sizeof(*sync)); 1027bf215546Sopenharmony_ci if (!sync) { 1028bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_destroy(gpu, syncobj_handle); 1029bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 1030bf215546Sopenharmony_ci } 1031bf215546Sopenharmony_ci 1032bf215546Sopenharmony_ci sync->syncobj_handle = syncobj_handle; 1033bf215546Sopenharmony_ci sync->base.sync_id = 0; /* TODO */ 1034bf215546Sopenharmony_ci 1035bf215546Sopenharmony_ci *out_sync = &sync->base; 1036bf215546Sopenharmony_ci 1037bf215546Sopenharmony_ci return VK_SUCCESS; 1038bf215546Sopenharmony_ci} 1039bf215546Sopenharmony_ci 1040bf215546Sopenharmony_cistatic VkResult 1041bf215546Sopenharmony_civirtgpu_sync_create(struct vn_renderer *renderer, 1042bf215546Sopenharmony_ci uint64_t initial_val, 1043bf215546Sopenharmony_ci uint32_t flags, 1044bf215546Sopenharmony_ci struct vn_renderer_sync **out_sync) 1045bf215546Sopenharmony_ci{ 1046bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci /* TODO */ 1049bf215546Sopenharmony_ci if (flags & VN_RENDERER_SYNC_SHAREABLE) 1050bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_DEVICE_MEMORY; 1051bf215546Sopenharmony_ci 1052bf215546Sopenharmony_ci /* always false because we don't use binary drm_syncobjs */ 1053bf215546Sopenharmony_ci const bool signaled = false; 1054bf215546Sopenharmony_ci const uint32_t syncobj_handle = 1055bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_create(gpu, signaled); 1056bf215546Sopenharmony_ci if (!syncobj_handle) 1057bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_DEVICE_MEMORY; 1058bf215546Sopenharmony_ci 1059bf215546Sopenharmony_ci /* add a signaled fence chain with seqno initial_val */ 1060bf215546Sopenharmony_ci const int ret = 1061bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_timeline_signal(gpu, syncobj_handle, initial_val); 1062bf215546Sopenharmony_ci if (ret) { 1063bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_destroy(gpu, syncobj_handle); 1064bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_DEVICE_MEMORY; 1065bf215546Sopenharmony_ci } 1066bf215546Sopenharmony_ci 1067bf215546Sopenharmony_ci struct virtgpu_sync *sync = calloc(1, sizeof(*sync)); 1068bf215546Sopenharmony_ci if (!sync) { 1069bf215546Sopenharmony_ci virtgpu_ioctl_syncobj_destroy(gpu, syncobj_handle); 1070bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 1071bf215546Sopenharmony_ci } 1072bf215546Sopenharmony_ci 1073bf215546Sopenharmony_ci sync->syncobj_handle = syncobj_handle; 1074bf215546Sopenharmony_ci /* we will have a sync_id when shareable is true and virtio-gpu associates 1075bf215546Sopenharmony_ci * a host sync object with guest drm_syncobj 1076bf215546Sopenharmony_ci */ 1077bf215546Sopenharmony_ci sync->base.sync_id = 0; 1078bf215546Sopenharmony_ci 1079bf215546Sopenharmony_ci *out_sync = &sync->base; 1080bf215546Sopenharmony_ci 1081bf215546Sopenharmony_ci return VK_SUCCESS; 1082bf215546Sopenharmony_ci} 1083bf215546Sopenharmony_ci 1084bf215546Sopenharmony_cistatic void 1085bf215546Sopenharmony_civirtgpu_bo_invalidate(struct vn_renderer *renderer, 1086bf215546Sopenharmony_ci struct vn_renderer_bo *bo, 1087bf215546Sopenharmony_ci VkDeviceSize offset, 1088bf215546Sopenharmony_ci VkDeviceSize size) 1089bf215546Sopenharmony_ci{ 1090bf215546Sopenharmony_ci /* nop because kernel makes every mapping coherent */ 1091bf215546Sopenharmony_ci} 1092bf215546Sopenharmony_ci 1093bf215546Sopenharmony_cistatic void 1094bf215546Sopenharmony_civirtgpu_bo_flush(struct vn_renderer *renderer, 1095bf215546Sopenharmony_ci struct vn_renderer_bo *bo, 1096bf215546Sopenharmony_ci VkDeviceSize offset, 1097bf215546Sopenharmony_ci VkDeviceSize size) 1098bf215546Sopenharmony_ci{ 1099bf215546Sopenharmony_ci /* nop because kernel makes every mapping coherent */ 1100bf215546Sopenharmony_ci} 1101bf215546Sopenharmony_ci 1102bf215546Sopenharmony_cistatic void * 1103bf215546Sopenharmony_civirtgpu_bo_map(struct vn_renderer *renderer, struct vn_renderer_bo *_bo) 1104bf215546Sopenharmony_ci{ 1105bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1106bf215546Sopenharmony_ci struct virtgpu_bo *bo = (struct virtgpu_bo *)_bo; 1107bf215546Sopenharmony_ci const bool mappable = bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE; 1108bf215546Sopenharmony_ci 1109bf215546Sopenharmony_ci /* not thread-safe but is fine */ 1110bf215546Sopenharmony_ci if (!bo->base.mmap_ptr && mappable) { 1111bf215546Sopenharmony_ci bo->base.mmap_ptr = 1112bf215546Sopenharmony_ci virtgpu_ioctl_map(gpu, bo->gem_handle, bo->base.mmap_size); 1113bf215546Sopenharmony_ci } 1114bf215546Sopenharmony_ci 1115bf215546Sopenharmony_ci return bo->base.mmap_ptr; 1116bf215546Sopenharmony_ci} 1117bf215546Sopenharmony_ci 1118bf215546Sopenharmony_cistatic int 1119bf215546Sopenharmony_civirtgpu_bo_export_dma_buf(struct vn_renderer *renderer, 1120bf215546Sopenharmony_ci struct vn_renderer_bo *_bo) 1121bf215546Sopenharmony_ci{ 1122bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1123bf215546Sopenharmony_ci struct virtgpu_bo *bo = (struct virtgpu_bo *)_bo; 1124bf215546Sopenharmony_ci const bool mappable = bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE; 1125bf215546Sopenharmony_ci const bool shareable = bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_SHAREABLE; 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci return shareable 1128bf215546Sopenharmony_ci ? virtgpu_ioctl_prime_handle_to_fd(gpu, bo->gem_handle, mappable) 1129bf215546Sopenharmony_ci : -1; 1130bf215546Sopenharmony_ci} 1131bf215546Sopenharmony_ci 1132bf215546Sopenharmony_cistatic bool 1133bf215546Sopenharmony_civirtgpu_bo_destroy(struct vn_renderer *renderer, struct vn_renderer_bo *_bo) 1134bf215546Sopenharmony_ci{ 1135bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1136bf215546Sopenharmony_ci struct virtgpu_bo *bo = (struct virtgpu_bo *)_bo; 1137bf215546Sopenharmony_ci 1138bf215546Sopenharmony_ci mtx_lock(&gpu->dma_buf_import_mutex); 1139bf215546Sopenharmony_ci 1140bf215546Sopenharmony_ci /* Check the refcount again after the import lock is grabbed. Yes, we use 1141bf215546Sopenharmony_ci * the double-checked locking anti-pattern. 1142bf215546Sopenharmony_ci */ 1143bf215546Sopenharmony_ci if (vn_refcount_is_valid(&bo->base.refcount)) { 1144bf215546Sopenharmony_ci mtx_unlock(&gpu->dma_buf_import_mutex); 1145bf215546Sopenharmony_ci return false; 1146bf215546Sopenharmony_ci } 1147bf215546Sopenharmony_ci 1148bf215546Sopenharmony_ci if (bo->base.mmap_ptr) 1149bf215546Sopenharmony_ci munmap(bo->base.mmap_ptr, bo->base.mmap_size); 1150bf215546Sopenharmony_ci virtgpu_ioctl_gem_close(gpu, bo->gem_handle); 1151bf215546Sopenharmony_ci 1152bf215546Sopenharmony_ci /* set gem_handle to 0 to indicate that the bo is invalid */ 1153bf215546Sopenharmony_ci bo->gem_handle = 0; 1154bf215546Sopenharmony_ci 1155bf215546Sopenharmony_ci mtx_unlock(&gpu->dma_buf_import_mutex); 1156bf215546Sopenharmony_ci 1157bf215546Sopenharmony_ci return true; 1158bf215546Sopenharmony_ci} 1159bf215546Sopenharmony_ci 1160bf215546Sopenharmony_cistatic uint32_t 1161bf215546Sopenharmony_civirtgpu_bo_blob_flags(VkMemoryPropertyFlags flags, 1162bf215546Sopenharmony_ci VkExternalMemoryHandleTypeFlags external_handles) 1163bf215546Sopenharmony_ci{ 1164bf215546Sopenharmony_ci uint32_t blob_flags = 0; 1165bf215546Sopenharmony_ci if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) 1166bf215546Sopenharmony_ci blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE; 1167bf215546Sopenharmony_ci if (external_handles) 1168bf215546Sopenharmony_ci blob_flags |= VIRTGPU_BLOB_FLAG_USE_SHAREABLE; 1169bf215546Sopenharmony_ci if (external_handles & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) 1170bf215546Sopenharmony_ci blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE; 1171bf215546Sopenharmony_ci 1172bf215546Sopenharmony_ci return blob_flags; 1173bf215546Sopenharmony_ci} 1174bf215546Sopenharmony_ci 1175bf215546Sopenharmony_cistatic VkResult 1176bf215546Sopenharmony_civirtgpu_bo_create_from_dma_buf(struct vn_renderer *renderer, 1177bf215546Sopenharmony_ci VkDeviceSize size, 1178bf215546Sopenharmony_ci int fd, 1179bf215546Sopenharmony_ci VkMemoryPropertyFlags flags, 1180bf215546Sopenharmony_ci struct vn_renderer_bo **out_bo) 1181bf215546Sopenharmony_ci{ 1182bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1183bf215546Sopenharmony_ci struct drm_virtgpu_resource_info info; 1184bf215546Sopenharmony_ci uint32_t gem_handle = 0; 1185bf215546Sopenharmony_ci struct virtgpu_bo *bo = NULL; 1186bf215546Sopenharmony_ci 1187bf215546Sopenharmony_ci mtx_lock(&gpu->dma_buf_import_mutex); 1188bf215546Sopenharmony_ci 1189bf215546Sopenharmony_ci gem_handle = virtgpu_ioctl_prime_fd_to_handle(gpu, fd); 1190bf215546Sopenharmony_ci if (!gem_handle) 1191bf215546Sopenharmony_ci goto fail; 1192bf215546Sopenharmony_ci bo = util_sparse_array_get(&gpu->bo_array, gem_handle); 1193bf215546Sopenharmony_ci 1194bf215546Sopenharmony_ci if (virtgpu_ioctl_resource_info(gpu, gem_handle, &info)) 1195bf215546Sopenharmony_ci goto fail; 1196bf215546Sopenharmony_ci 1197bf215546Sopenharmony_ci uint32_t blob_flags; 1198bf215546Sopenharmony_ci size_t mmap_size; 1199bf215546Sopenharmony_ci if (info.blob_mem) { 1200bf215546Sopenharmony_ci /* must be VIRTGPU_BLOB_MEM_HOST3D or VIRTGPU_BLOB_MEM_GUEST_VRAM */ 1201bf215546Sopenharmony_ci if (info.blob_mem != gpu->bo_blob_mem) 1202bf215546Sopenharmony_ci goto fail; 1203bf215546Sopenharmony_ci 1204bf215546Sopenharmony_ci /* blob_flags is not passed to the kernel and is only for internal use 1205bf215546Sopenharmony_ci * on imports. Set it to what works best for us. 1206bf215546Sopenharmony_ci */ 1207bf215546Sopenharmony_ci blob_flags = virtgpu_bo_blob_flags(flags, 0); 1208bf215546Sopenharmony_ci blob_flags |= VIRTGPU_BLOB_FLAG_USE_SHAREABLE; 1209bf215546Sopenharmony_ci 1210bf215546Sopenharmony_ci /* mmap_size is only used when mappable */ 1211bf215546Sopenharmony_ci mmap_size = 0; 1212bf215546Sopenharmony_ci if (blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) { 1213bf215546Sopenharmony_ci if (info.size < size) 1214bf215546Sopenharmony_ci goto fail; 1215bf215546Sopenharmony_ci 1216bf215546Sopenharmony_ci mmap_size = size; 1217bf215546Sopenharmony_ci } 1218bf215546Sopenharmony_ci } else { 1219bf215546Sopenharmony_ci /* must be classic resource here 1220bf215546Sopenharmony_ci * set blob_flags to 0 to fail virtgpu_bo_map 1221bf215546Sopenharmony_ci * set mmap_size to 0 since mapping is not allowed 1222bf215546Sopenharmony_ci */ 1223bf215546Sopenharmony_ci blob_flags = 0; 1224bf215546Sopenharmony_ci mmap_size = 0; 1225bf215546Sopenharmony_ci } 1226bf215546Sopenharmony_ci 1227bf215546Sopenharmony_ci /* we check bo->gem_handle instead of bo->refcount because bo->refcount 1228bf215546Sopenharmony_ci * might only be memset to 0 and is not considered initialized in theory 1229bf215546Sopenharmony_ci */ 1230bf215546Sopenharmony_ci if (bo->gem_handle == gem_handle) { 1231bf215546Sopenharmony_ci if (bo->base.mmap_size < mmap_size) 1232bf215546Sopenharmony_ci goto fail; 1233bf215546Sopenharmony_ci if (blob_flags & ~bo->blob_flags) 1234bf215546Sopenharmony_ci goto fail; 1235bf215546Sopenharmony_ci 1236bf215546Sopenharmony_ci /* we can't use vn_renderer_bo_ref as the refcount may drop to 0 1237bf215546Sopenharmony_ci * temporarily before virtgpu_bo_destroy grabs the lock 1238bf215546Sopenharmony_ci */ 1239bf215546Sopenharmony_ci vn_refcount_fetch_add_relaxed(&bo->base.refcount, 1); 1240bf215546Sopenharmony_ci } else { 1241bf215546Sopenharmony_ci *bo = (struct virtgpu_bo){ 1242bf215546Sopenharmony_ci .base = { 1243bf215546Sopenharmony_ci .refcount = VN_REFCOUNT_INIT(1), 1244bf215546Sopenharmony_ci .res_id = info.res_handle, 1245bf215546Sopenharmony_ci .mmap_size = mmap_size, 1246bf215546Sopenharmony_ci }, 1247bf215546Sopenharmony_ci .gem_handle = gem_handle, 1248bf215546Sopenharmony_ci .blob_flags = blob_flags, 1249bf215546Sopenharmony_ci }; 1250bf215546Sopenharmony_ci } 1251bf215546Sopenharmony_ci 1252bf215546Sopenharmony_ci mtx_unlock(&gpu->dma_buf_import_mutex); 1253bf215546Sopenharmony_ci 1254bf215546Sopenharmony_ci *out_bo = &bo->base; 1255bf215546Sopenharmony_ci 1256bf215546Sopenharmony_ci return VK_SUCCESS; 1257bf215546Sopenharmony_ci 1258bf215546Sopenharmony_cifail: 1259bf215546Sopenharmony_ci if (gem_handle && bo->gem_handle != gem_handle) 1260bf215546Sopenharmony_ci virtgpu_ioctl_gem_close(gpu, gem_handle); 1261bf215546Sopenharmony_ci mtx_unlock(&gpu->dma_buf_import_mutex); 1262bf215546Sopenharmony_ci return VK_ERROR_INVALID_EXTERNAL_HANDLE; 1263bf215546Sopenharmony_ci} 1264bf215546Sopenharmony_ci 1265bf215546Sopenharmony_cistatic VkResult 1266bf215546Sopenharmony_civirtgpu_bo_create_from_device_memory( 1267bf215546Sopenharmony_ci struct vn_renderer *renderer, 1268bf215546Sopenharmony_ci VkDeviceSize size, 1269bf215546Sopenharmony_ci vn_object_id mem_id, 1270bf215546Sopenharmony_ci VkMemoryPropertyFlags flags, 1271bf215546Sopenharmony_ci VkExternalMemoryHandleTypeFlags external_handles, 1272bf215546Sopenharmony_ci struct vn_renderer_bo **out_bo) 1273bf215546Sopenharmony_ci{ 1274bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1275bf215546Sopenharmony_ci const uint32_t blob_flags = virtgpu_bo_blob_flags(flags, external_handles); 1276bf215546Sopenharmony_ci 1277bf215546Sopenharmony_ci uint32_t res_id; 1278bf215546Sopenharmony_ci uint32_t gem_handle = virtgpu_ioctl_resource_create_blob( 1279bf215546Sopenharmony_ci gpu, gpu->bo_blob_mem, blob_flags, size, mem_id, &res_id); 1280bf215546Sopenharmony_ci if (!gem_handle) 1281bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_DEVICE_MEMORY; 1282bf215546Sopenharmony_ci 1283bf215546Sopenharmony_ci struct virtgpu_bo *bo = util_sparse_array_get(&gpu->bo_array, gem_handle); 1284bf215546Sopenharmony_ci *bo = (struct virtgpu_bo){ 1285bf215546Sopenharmony_ci .base = { 1286bf215546Sopenharmony_ci .refcount = VN_REFCOUNT_INIT(1), 1287bf215546Sopenharmony_ci .res_id = res_id, 1288bf215546Sopenharmony_ci .mmap_size = size, 1289bf215546Sopenharmony_ci }, 1290bf215546Sopenharmony_ci .gem_handle = gem_handle, 1291bf215546Sopenharmony_ci .blob_flags = blob_flags, 1292bf215546Sopenharmony_ci }; 1293bf215546Sopenharmony_ci 1294bf215546Sopenharmony_ci *out_bo = &bo->base; 1295bf215546Sopenharmony_ci 1296bf215546Sopenharmony_ci return VK_SUCCESS; 1297bf215546Sopenharmony_ci} 1298bf215546Sopenharmony_ci 1299bf215546Sopenharmony_cistatic void 1300bf215546Sopenharmony_civirtgpu_shmem_destroy_now(struct vn_renderer *renderer, 1301bf215546Sopenharmony_ci struct vn_renderer_shmem *_shmem) 1302bf215546Sopenharmony_ci{ 1303bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1304bf215546Sopenharmony_ci struct virtgpu_shmem *shmem = (struct virtgpu_shmem *)_shmem; 1305bf215546Sopenharmony_ci 1306bf215546Sopenharmony_ci munmap(shmem->base.mmap_ptr, shmem->base.mmap_size); 1307bf215546Sopenharmony_ci virtgpu_ioctl_gem_close(gpu, shmem->gem_handle); 1308bf215546Sopenharmony_ci} 1309bf215546Sopenharmony_ci 1310bf215546Sopenharmony_cistatic void 1311bf215546Sopenharmony_civirtgpu_shmem_destroy(struct vn_renderer *renderer, 1312bf215546Sopenharmony_ci struct vn_renderer_shmem *shmem) 1313bf215546Sopenharmony_ci{ 1314bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1315bf215546Sopenharmony_ci 1316bf215546Sopenharmony_ci if (vn_renderer_shmem_cache_add(&gpu->shmem_cache, shmem)) 1317bf215546Sopenharmony_ci return; 1318bf215546Sopenharmony_ci 1319bf215546Sopenharmony_ci virtgpu_shmem_destroy_now(&gpu->base, shmem); 1320bf215546Sopenharmony_ci} 1321bf215546Sopenharmony_ci 1322bf215546Sopenharmony_cistatic struct vn_renderer_shmem * 1323bf215546Sopenharmony_civirtgpu_shmem_create(struct vn_renderer *renderer, size_t size) 1324bf215546Sopenharmony_ci{ 1325bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1326bf215546Sopenharmony_ci 1327bf215546Sopenharmony_ci struct vn_renderer_shmem *cached_shmem = 1328bf215546Sopenharmony_ci vn_renderer_shmem_cache_get(&gpu->shmem_cache, size); 1329bf215546Sopenharmony_ci if (cached_shmem) { 1330bf215546Sopenharmony_ci cached_shmem->refcount = VN_REFCOUNT_INIT(1); 1331bf215546Sopenharmony_ci return cached_shmem; 1332bf215546Sopenharmony_ci } 1333bf215546Sopenharmony_ci 1334bf215546Sopenharmony_ci uint32_t res_id; 1335bf215546Sopenharmony_ci uint32_t gem_handle = virtgpu_ioctl_resource_create_blob( 1336bf215546Sopenharmony_ci gpu, gpu->shmem_blob_mem, VIRTGPU_BLOB_FLAG_USE_MAPPABLE, size, 0, 1337bf215546Sopenharmony_ci &res_id); 1338bf215546Sopenharmony_ci if (!gem_handle) 1339bf215546Sopenharmony_ci return NULL; 1340bf215546Sopenharmony_ci 1341bf215546Sopenharmony_ci void *ptr = virtgpu_ioctl_map(gpu, gem_handle, size); 1342bf215546Sopenharmony_ci if (!ptr) { 1343bf215546Sopenharmony_ci virtgpu_ioctl_gem_close(gpu, gem_handle); 1344bf215546Sopenharmony_ci return NULL; 1345bf215546Sopenharmony_ci } 1346bf215546Sopenharmony_ci 1347bf215546Sopenharmony_ci struct virtgpu_shmem *shmem = 1348bf215546Sopenharmony_ci util_sparse_array_get(&gpu->shmem_array, gem_handle); 1349bf215546Sopenharmony_ci *shmem = (struct virtgpu_shmem){ 1350bf215546Sopenharmony_ci .base = { 1351bf215546Sopenharmony_ci .refcount = VN_REFCOUNT_INIT(1), 1352bf215546Sopenharmony_ci .res_id = res_id, 1353bf215546Sopenharmony_ci .mmap_size = size, 1354bf215546Sopenharmony_ci .mmap_ptr = ptr, 1355bf215546Sopenharmony_ci }, 1356bf215546Sopenharmony_ci .gem_handle = gem_handle, 1357bf215546Sopenharmony_ci }; 1358bf215546Sopenharmony_ci 1359bf215546Sopenharmony_ci return &shmem->base; 1360bf215546Sopenharmony_ci} 1361bf215546Sopenharmony_ci 1362bf215546Sopenharmony_cistatic VkResult 1363bf215546Sopenharmony_civirtgpu_wait(struct vn_renderer *renderer, 1364bf215546Sopenharmony_ci const struct vn_renderer_wait *wait) 1365bf215546Sopenharmony_ci{ 1366bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1367bf215546Sopenharmony_ci 1368bf215546Sopenharmony_ci const int ret = virtgpu_ioctl_syncobj_timeline_wait(gpu, wait, false); 1369bf215546Sopenharmony_ci if (ret && errno != ETIME) 1370bf215546Sopenharmony_ci return VK_ERROR_DEVICE_LOST; 1371bf215546Sopenharmony_ci 1372bf215546Sopenharmony_ci return ret ? VK_TIMEOUT : VK_SUCCESS; 1373bf215546Sopenharmony_ci} 1374bf215546Sopenharmony_ci 1375bf215546Sopenharmony_cistatic VkResult 1376bf215546Sopenharmony_civirtgpu_submit(struct vn_renderer *renderer, 1377bf215546Sopenharmony_ci const struct vn_renderer_submit *submit) 1378bf215546Sopenharmony_ci{ 1379bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1380bf215546Sopenharmony_ci 1381bf215546Sopenharmony_ci const int ret = virtgpu_ioctl_submit(gpu, submit); 1382bf215546Sopenharmony_ci return ret ? VK_ERROR_DEVICE_LOST : VK_SUCCESS; 1383bf215546Sopenharmony_ci} 1384bf215546Sopenharmony_ci 1385bf215546Sopenharmony_cistatic void 1386bf215546Sopenharmony_civirtgpu_init_renderer_info(struct virtgpu *gpu) 1387bf215546Sopenharmony_ci{ 1388bf215546Sopenharmony_ci struct vn_renderer_info *info = &gpu->base.info; 1389bf215546Sopenharmony_ci 1390bf215546Sopenharmony_ci info->drm.has_primary = gpu->has_primary; 1391bf215546Sopenharmony_ci info->drm.primary_major = gpu->primary_major; 1392bf215546Sopenharmony_ci info->drm.primary_minor = gpu->primary_minor; 1393bf215546Sopenharmony_ci info->drm.has_render = true; 1394bf215546Sopenharmony_ci info->drm.render_major = gpu->render_major; 1395bf215546Sopenharmony_ci info->drm.render_minor = gpu->render_minor; 1396bf215546Sopenharmony_ci 1397bf215546Sopenharmony_ci info->pci.vendor_id = VIRTGPU_PCI_VENDOR_ID; 1398bf215546Sopenharmony_ci info->pci.device_id = VIRTGPU_PCI_DEVICE_ID; 1399bf215546Sopenharmony_ci 1400bf215546Sopenharmony_ci if (gpu->bustype == DRM_BUS_PCI) { 1401bf215546Sopenharmony_ci info->pci.has_bus_info = true; 1402bf215546Sopenharmony_ci info->pci.domain = gpu->pci_bus_info.domain; 1403bf215546Sopenharmony_ci info->pci.bus = gpu->pci_bus_info.bus; 1404bf215546Sopenharmony_ci info->pci.device = gpu->pci_bus_info.dev; 1405bf215546Sopenharmony_ci info->pci.function = gpu->pci_bus_info.func; 1406bf215546Sopenharmony_ci } else { 1407bf215546Sopenharmony_ci info->pci.has_bus_info = false; 1408bf215546Sopenharmony_ci } 1409bf215546Sopenharmony_ci 1410bf215546Sopenharmony_ci info->has_dma_buf_import = true; 1411bf215546Sopenharmony_ci /* Kernel makes every mapping coherent. We are better off filtering 1412bf215546Sopenharmony_ci * incoherent memory types out than silently making them coherent. 1413bf215546Sopenharmony_ci */ 1414bf215546Sopenharmony_ci info->has_cache_management = false; 1415bf215546Sopenharmony_ci /* TODO drm_syncobj */ 1416bf215546Sopenharmony_ci info->has_external_sync = false; 1417bf215546Sopenharmony_ci 1418bf215546Sopenharmony_ci info->has_implicit_fencing = false; 1419bf215546Sopenharmony_ci 1420bf215546Sopenharmony_ci info->max_sync_queue_count = gpu->max_sync_queue_count; 1421bf215546Sopenharmony_ci 1422bf215546Sopenharmony_ci const struct virgl_renderer_capset_venus *capset = &gpu->capset.data; 1423bf215546Sopenharmony_ci info->wire_format_version = capset->wire_format_version; 1424bf215546Sopenharmony_ci info->vk_xml_version = capset->vk_xml_version; 1425bf215546Sopenharmony_ci info->vk_ext_command_serialization_spec_version = 1426bf215546Sopenharmony_ci capset->vk_ext_command_serialization_spec_version; 1427bf215546Sopenharmony_ci info->vk_mesa_venus_protocol_spec_version = 1428bf215546Sopenharmony_ci capset->vk_mesa_venus_protocol_spec_version; 1429bf215546Sopenharmony_ci info->supports_blob_id_0 = capset->supports_blob_id_0; 1430bf215546Sopenharmony_ci 1431bf215546Sopenharmony_ci /* ensure vk_extension_mask is large enough to hold all capset masks */ 1432bf215546Sopenharmony_ci STATIC_ASSERT(sizeof(info->vk_extension_mask) >= 1433bf215546Sopenharmony_ci sizeof(capset->vk_extension_mask1)); 1434bf215546Sopenharmony_ci memcpy(info->vk_extension_mask, capset->vk_extension_mask1, 1435bf215546Sopenharmony_ci sizeof(capset->vk_extension_mask1)); 1436bf215546Sopenharmony_ci 1437bf215546Sopenharmony_ci info->allow_vk_wait_syncs = capset->allow_vk_wait_syncs; 1438bf215546Sopenharmony_ci 1439bf215546Sopenharmony_ci if (gpu->bo_blob_mem == VIRTGPU_BLOB_MEM_GUEST_VRAM) 1440bf215546Sopenharmony_ci info->has_guest_vram = true; 1441bf215546Sopenharmony_ci} 1442bf215546Sopenharmony_ci 1443bf215546Sopenharmony_cistatic void 1444bf215546Sopenharmony_civirtgpu_destroy(struct vn_renderer *renderer, 1445bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc) 1446bf215546Sopenharmony_ci{ 1447bf215546Sopenharmony_ci struct virtgpu *gpu = (struct virtgpu *)renderer; 1448bf215546Sopenharmony_ci 1449bf215546Sopenharmony_ci vn_renderer_shmem_cache_fini(&gpu->shmem_cache); 1450bf215546Sopenharmony_ci 1451bf215546Sopenharmony_ci if (gpu->fd >= 0) 1452bf215546Sopenharmony_ci close(gpu->fd); 1453bf215546Sopenharmony_ci 1454bf215546Sopenharmony_ci mtx_destroy(&gpu->dma_buf_import_mutex); 1455bf215546Sopenharmony_ci 1456bf215546Sopenharmony_ci util_sparse_array_finish(&gpu->shmem_array); 1457bf215546Sopenharmony_ci util_sparse_array_finish(&gpu->bo_array); 1458bf215546Sopenharmony_ci 1459bf215546Sopenharmony_ci vk_free(alloc, gpu); 1460bf215546Sopenharmony_ci} 1461bf215546Sopenharmony_ci 1462bf215546Sopenharmony_cistatic void 1463bf215546Sopenharmony_civirtgpu_init_shmem_blob_mem(struct virtgpu *gpu) 1464bf215546Sopenharmony_ci{ 1465bf215546Sopenharmony_ci /* VIRTGPU_BLOB_MEM_GUEST allocates from the guest system memory. They are 1466bf215546Sopenharmony_ci * logically contiguous in the guest but are sglists (iovecs) in the host. 1467bf215546Sopenharmony_ci * That makes them slower to process in the host. With host process 1468bf215546Sopenharmony_ci * isolation, it also becomes impossible for the host to access sglists 1469bf215546Sopenharmony_ci * directly. 1470bf215546Sopenharmony_ci * 1471bf215546Sopenharmony_ci * While there are ideas (and shipped code in some cases) such as creating 1472bf215546Sopenharmony_ci * udmabufs from sglists, or having a dedicated guest heap, it seems the 1473bf215546Sopenharmony_ci * easiest way is to reuse VIRTGPU_BLOB_MEM_HOST3D. That is, when the 1474bf215546Sopenharmony_ci * renderer sees a request to export a blob where 1475bf215546Sopenharmony_ci * 1476bf215546Sopenharmony_ci * - blob_mem is VIRTGPU_BLOB_MEM_HOST3D 1477bf215546Sopenharmony_ci * - blob_flags is VIRTGPU_BLOB_FLAG_USE_MAPPABLE 1478bf215546Sopenharmony_ci * - blob_id is 0 1479bf215546Sopenharmony_ci * 1480bf215546Sopenharmony_ci * it allocates a host shmem. 1481bf215546Sopenharmony_ci * 1482bf215546Sopenharmony_ci * TODO cache shmems as they are costly to set up and usually require syncs 1483bf215546Sopenharmony_ci */ 1484bf215546Sopenharmony_ci gpu->shmem_blob_mem = gpu->capset.data.supports_blob_id_0 1485bf215546Sopenharmony_ci ? VIRTGPU_BLOB_MEM_HOST3D 1486bf215546Sopenharmony_ci : VIRTGPU_BLOB_MEM_GUEST; 1487bf215546Sopenharmony_ci} 1488bf215546Sopenharmony_ci 1489bf215546Sopenharmony_cistatic VkResult 1490bf215546Sopenharmony_civirtgpu_init_context(struct virtgpu *gpu) 1491bf215546Sopenharmony_ci{ 1492bf215546Sopenharmony_ci assert(!gpu->capset.version); 1493bf215546Sopenharmony_ci const int ret = virtgpu_ioctl_context_init(gpu, gpu->capset.id); 1494bf215546Sopenharmony_ci if (ret) { 1495bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) { 1496bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to initialize context: %s", 1497bf215546Sopenharmony_ci strerror(errno)); 1498bf215546Sopenharmony_ci } 1499bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1500bf215546Sopenharmony_ci } 1501bf215546Sopenharmony_ci 1502bf215546Sopenharmony_ci return VK_SUCCESS; 1503bf215546Sopenharmony_ci} 1504bf215546Sopenharmony_ci 1505bf215546Sopenharmony_cistatic VkResult 1506bf215546Sopenharmony_civirtgpu_init_capset(struct virtgpu *gpu) 1507bf215546Sopenharmony_ci{ 1508bf215546Sopenharmony_ci gpu->capset.id = VIRGL_RENDERER_CAPSET_VENUS; 1509bf215546Sopenharmony_ci gpu->capset.version = 0; 1510bf215546Sopenharmony_ci 1511bf215546Sopenharmony_ci const int ret = 1512bf215546Sopenharmony_ci virtgpu_ioctl_get_caps(gpu, gpu->capset.id, gpu->capset.version, 1513bf215546Sopenharmony_ci &gpu->capset.data, sizeof(gpu->capset.data)); 1514bf215546Sopenharmony_ci if (ret) { 1515bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) { 1516bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to get venus v%d capset: %s", 1517bf215546Sopenharmony_ci gpu->capset.version, strerror(errno)); 1518bf215546Sopenharmony_ci } 1519bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1520bf215546Sopenharmony_ci } 1521bf215546Sopenharmony_ci 1522bf215546Sopenharmony_ci return VK_SUCCESS; 1523bf215546Sopenharmony_ci} 1524bf215546Sopenharmony_ci 1525bf215546Sopenharmony_cistatic VkResult 1526bf215546Sopenharmony_civirtgpu_init_params(struct virtgpu *gpu) 1527bf215546Sopenharmony_ci{ 1528bf215546Sopenharmony_ci const uint64_t required_params[] = { 1529bf215546Sopenharmony_ci VIRTGPU_PARAM_3D_FEATURES, VIRTGPU_PARAM_CAPSET_QUERY_FIX, 1530bf215546Sopenharmony_ci VIRTGPU_PARAM_RESOURCE_BLOB, VIRTGPU_PARAM_CROSS_DEVICE, 1531bf215546Sopenharmony_ci VIRTGPU_PARAM_CONTEXT_INIT, 1532bf215546Sopenharmony_ci }; 1533bf215546Sopenharmony_ci uint64_t val; 1534bf215546Sopenharmony_ci for (uint32_t i = 0; i < ARRAY_SIZE(required_params); i++) { 1535bf215546Sopenharmony_ci val = virtgpu_ioctl_getparam(gpu, required_params[i]); 1536bf215546Sopenharmony_ci if (!val) { 1537bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) { 1538bf215546Sopenharmony_ci vn_log(gpu->instance, "required kernel param %d is missing", 1539bf215546Sopenharmony_ci (int)required_params[i]); 1540bf215546Sopenharmony_ci } 1541bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1542bf215546Sopenharmony_ci } 1543bf215546Sopenharmony_ci } 1544bf215546Sopenharmony_ci 1545bf215546Sopenharmony_ci val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_HOST_VISIBLE); 1546bf215546Sopenharmony_ci if (val) { 1547bf215546Sopenharmony_ci gpu->bo_blob_mem = VIRTGPU_BLOB_MEM_HOST3D; 1548bf215546Sopenharmony_ci } else { 1549bf215546Sopenharmony_ci val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_GUEST_VRAM); 1550bf215546Sopenharmony_ci if (val) { 1551bf215546Sopenharmony_ci gpu->bo_blob_mem = VIRTGPU_BLOB_MEM_GUEST_VRAM; 1552bf215546Sopenharmony_ci } 1553bf215546Sopenharmony_ci } 1554bf215546Sopenharmony_ci 1555bf215546Sopenharmony_ci if (!val) { 1556bf215546Sopenharmony_ci vn_log(gpu->instance, 1557bf215546Sopenharmony_ci "one of required kernel params (%d or %d) is missing", 1558bf215546Sopenharmony_ci (int)VIRTGPU_PARAM_HOST_VISIBLE, (int)VIRTGPU_PARAM_GUEST_VRAM); 1559bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1560bf215546Sopenharmony_ci } 1561bf215546Sopenharmony_ci 1562bf215546Sopenharmony_ci val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT); 1563bf215546Sopenharmony_ci if (!val) { 1564bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) 1565bf215546Sopenharmony_ci vn_log(gpu->instance, "no sync queue support"); 1566bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1567bf215546Sopenharmony_ci } 1568bf215546Sopenharmony_ci gpu->max_sync_queue_count = val; 1569bf215546Sopenharmony_ci 1570bf215546Sopenharmony_ci return VK_SUCCESS; 1571bf215546Sopenharmony_ci} 1572bf215546Sopenharmony_ci 1573bf215546Sopenharmony_cistatic VkResult 1574bf215546Sopenharmony_civirtgpu_open_device(struct virtgpu *gpu, const drmDevicePtr dev) 1575bf215546Sopenharmony_ci{ 1576bf215546Sopenharmony_ci bool supported_bus = false; 1577bf215546Sopenharmony_ci 1578bf215546Sopenharmony_ci switch (dev->bustype) { 1579bf215546Sopenharmony_ci case DRM_BUS_PCI: 1580bf215546Sopenharmony_ci if (dev->deviceinfo.pci->vendor_id == VIRTGPU_PCI_VENDOR_ID && 1581bf215546Sopenharmony_ci dev->deviceinfo.pci->device_id == VIRTGPU_PCI_DEVICE_ID) 1582bf215546Sopenharmony_ci supported_bus = true; 1583bf215546Sopenharmony_ci break; 1584bf215546Sopenharmony_ci case DRM_BUS_PLATFORM: 1585bf215546Sopenharmony_ci supported_bus = true; 1586bf215546Sopenharmony_ci break; 1587bf215546Sopenharmony_ci default: 1588bf215546Sopenharmony_ci break; 1589bf215546Sopenharmony_ci } 1590bf215546Sopenharmony_ci 1591bf215546Sopenharmony_ci if (!supported_bus || !(dev->available_nodes & (1 << DRM_NODE_RENDER))) { 1592bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) { 1593bf215546Sopenharmony_ci const char *name = "unknown"; 1594bf215546Sopenharmony_ci for (uint32_t i = 0; i < DRM_NODE_MAX; i++) { 1595bf215546Sopenharmony_ci if (dev->available_nodes & (1 << i)) { 1596bf215546Sopenharmony_ci name = dev->nodes[i]; 1597bf215546Sopenharmony_ci break; 1598bf215546Sopenharmony_ci } 1599bf215546Sopenharmony_ci } 1600bf215546Sopenharmony_ci vn_log(gpu->instance, "skipping DRM device %s", name); 1601bf215546Sopenharmony_ci } 1602bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1603bf215546Sopenharmony_ci } 1604bf215546Sopenharmony_ci 1605bf215546Sopenharmony_ci const char *primary_path = dev->nodes[DRM_NODE_PRIMARY]; 1606bf215546Sopenharmony_ci const char *node_path = dev->nodes[DRM_NODE_RENDER]; 1607bf215546Sopenharmony_ci 1608bf215546Sopenharmony_ci int fd = open(node_path, O_RDWR | O_CLOEXEC); 1609bf215546Sopenharmony_ci if (fd < 0) { 1610bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) 1611bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to open %s", node_path); 1612bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1613bf215546Sopenharmony_ci } 1614bf215546Sopenharmony_ci 1615bf215546Sopenharmony_ci drmVersionPtr version = drmGetVersion(fd); 1616bf215546Sopenharmony_ci if (!version || strcmp(version->name, "virtio_gpu") || 1617bf215546Sopenharmony_ci version->version_major != 0) { 1618bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) { 1619bf215546Sopenharmony_ci if (version) { 1620bf215546Sopenharmony_ci vn_log(gpu->instance, "unknown DRM driver %s version %d", 1621bf215546Sopenharmony_ci version->name, version->version_major); 1622bf215546Sopenharmony_ci } else { 1623bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to get DRM driver version"); 1624bf215546Sopenharmony_ci } 1625bf215546Sopenharmony_ci } 1626bf215546Sopenharmony_ci if (version) 1627bf215546Sopenharmony_ci drmFreeVersion(version); 1628bf215546Sopenharmony_ci close(fd); 1629bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1630bf215546Sopenharmony_ci } 1631bf215546Sopenharmony_ci 1632bf215546Sopenharmony_ci gpu->fd = fd; 1633bf215546Sopenharmony_ci 1634bf215546Sopenharmony_ci struct stat st; 1635bf215546Sopenharmony_ci if (stat(primary_path, &st) == 0) { 1636bf215546Sopenharmony_ci gpu->has_primary = true; 1637bf215546Sopenharmony_ci gpu->primary_major = major(st.st_rdev); 1638bf215546Sopenharmony_ci gpu->primary_minor = minor(st.st_rdev); 1639bf215546Sopenharmony_ci } else { 1640bf215546Sopenharmony_ci gpu->has_primary = false; 1641bf215546Sopenharmony_ci gpu->primary_major = 0; 1642bf215546Sopenharmony_ci gpu->primary_minor = 0; 1643bf215546Sopenharmony_ci } 1644bf215546Sopenharmony_ci stat(node_path, &st); 1645bf215546Sopenharmony_ci gpu->render_major = major(st.st_rdev); 1646bf215546Sopenharmony_ci gpu->render_minor = minor(st.st_rdev); 1647bf215546Sopenharmony_ci 1648bf215546Sopenharmony_ci gpu->bustype = dev->bustype; 1649bf215546Sopenharmony_ci if (dev->bustype == DRM_BUS_PCI) 1650bf215546Sopenharmony_ci gpu->pci_bus_info = *dev->businfo.pci; 1651bf215546Sopenharmony_ci 1652bf215546Sopenharmony_ci drmFreeVersion(version); 1653bf215546Sopenharmony_ci 1654bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) 1655bf215546Sopenharmony_ci vn_log(gpu->instance, "using DRM device %s", node_path); 1656bf215546Sopenharmony_ci 1657bf215546Sopenharmony_ci return VK_SUCCESS; 1658bf215546Sopenharmony_ci} 1659bf215546Sopenharmony_ci 1660bf215546Sopenharmony_cistatic VkResult 1661bf215546Sopenharmony_civirtgpu_open(struct virtgpu *gpu) 1662bf215546Sopenharmony_ci{ 1663bf215546Sopenharmony_ci drmDevicePtr devs[8]; 1664bf215546Sopenharmony_ci int count = drmGetDevices2(0, devs, ARRAY_SIZE(devs)); 1665bf215546Sopenharmony_ci if (count < 0) { 1666bf215546Sopenharmony_ci if (VN_DEBUG(INIT)) 1667bf215546Sopenharmony_ci vn_log(gpu->instance, "failed to enumerate DRM devices"); 1668bf215546Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 1669bf215546Sopenharmony_ci } 1670bf215546Sopenharmony_ci 1671bf215546Sopenharmony_ci VkResult result = VK_ERROR_INITIALIZATION_FAILED; 1672bf215546Sopenharmony_ci for (int i = 0; i < count; i++) { 1673bf215546Sopenharmony_ci result = virtgpu_open_device(gpu, devs[i]); 1674bf215546Sopenharmony_ci if (result == VK_SUCCESS) 1675bf215546Sopenharmony_ci break; 1676bf215546Sopenharmony_ci } 1677bf215546Sopenharmony_ci 1678bf215546Sopenharmony_ci drmFreeDevices(devs, count); 1679bf215546Sopenharmony_ci 1680bf215546Sopenharmony_ci return result; 1681bf215546Sopenharmony_ci} 1682bf215546Sopenharmony_ci 1683bf215546Sopenharmony_cistatic VkResult 1684bf215546Sopenharmony_civirtgpu_init(struct virtgpu *gpu) 1685bf215546Sopenharmony_ci{ 1686bf215546Sopenharmony_ci util_sparse_array_init(&gpu->shmem_array, sizeof(struct virtgpu_shmem), 1687bf215546Sopenharmony_ci 1024); 1688bf215546Sopenharmony_ci util_sparse_array_init(&gpu->bo_array, sizeof(struct virtgpu_bo), 1024); 1689bf215546Sopenharmony_ci 1690bf215546Sopenharmony_ci mtx_init(&gpu->dma_buf_import_mutex, mtx_plain); 1691bf215546Sopenharmony_ci 1692bf215546Sopenharmony_ci VkResult result = virtgpu_open(gpu); 1693bf215546Sopenharmony_ci if (result == VK_SUCCESS) 1694bf215546Sopenharmony_ci result = virtgpu_init_params(gpu); 1695bf215546Sopenharmony_ci if (result == VK_SUCCESS) 1696bf215546Sopenharmony_ci result = virtgpu_init_capset(gpu); 1697bf215546Sopenharmony_ci if (result == VK_SUCCESS) 1698bf215546Sopenharmony_ci result = virtgpu_init_context(gpu); 1699bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1700bf215546Sopenharmony_ci return result; 1701bf215546Sopenharmony_ci 1702bf215546Sopenharmony_ci virtgpu_init_shmem_blob_mem(gpu); 1703bf215546Sopenharmony_ci 1704bf215546Sopenharmony_ci vn_renderer_shmem_cache_init(&gpu->shmem_cache, &gpu->base, 1705bf215546Sopenharmony_ci virtgpu_shmem_destroy_now); 1706bf215546Sopenharmony_ci 1707bf215546Sopenharmony_ci virtgpu_init_renderer_info(gpu); 1708bf215546Sopenharmony_ci 1709bf215546Sopenharmony_ci gpu->base.ops.destroy = virtgpu_destroy; 1710bf215546Sopenharmony_ci gpu->base.ops.submit = virtgpu_submit; 1711bf215546Sopenharmony_ci gpu->base.ops.wait = virtgpu_wait; 1712bf215546Sopenharmony_ci 1713bf215546Sopenharmony_ci gpu->base.shmem_ops.create = virtgpu_shmem_create; 1714bf215546Sopenharmony_ci gpu->base.shmem_ops.destroy = virtgpu_shmem_destroy; 1715bf215546Sopenharmony_ci 1716bf215546Sopenharmony_ci gpu->base.bo_ops.create_from_device_memory = 1717bf215546Sopenharmony_ci virtgpu_bo_create_from_device_memory; 1718bf215546Sopenharmony_ci gpu->base.bo_ops.create_from_dma_buf = virtgpu_bo_create_from_dma_buf; 1719bf215546Sopenharmony_ci gpu->base.bo_ops.destroy = virtgpu_bo_destroy; 1720bf215546Sopenharmony_ci gpu->base.bo_ops.export_dma_buf = virtgpu_bo_export_dma_buf; 1721bf215546Sopenharmony_ci gpu->base.bo_ops.map = virtgpu_bo_map; 1722bf215546Sopenharmony_ci gpu->base.bo_ops.flush = virtgpu_bo_flush; 1723bf215546Sopenharmony_ci gpu->base.bo_ops.invalidate = virtgpu_bo_invalidate; 1724bf215546Sopenharmony_ci 1725bf215546Sopenharmony_ci gpu->base.sync_ops.create = virtgpu_sync_create; 1726bf215546Sopenharmony_ci gpu->base.sync_ops.create_from_syncobj = virtgpu_sync_create_from_syncobj; 1727bf215546Sopenharmony_ci gpu->base.sync_ops.destroy = virtgpu_sync_destroy; 1728bf215546Sopenharmony_ci gpu->base.sync_ops.export_syncobj = virtgpu_sync_export_syncobj; 1729bf215546Sopenharmony_ci gpu->base.sync_ops.reset = virtgpu_sync_reset; 1730bf215546Sopenharmony_ci gpu->base.sync_ops.read = virtgpu_sync_read; 1731bf215546Sopenharmony_ci gpu->base.sync_ops.write = virtgpu_sync_write; 1732bf215546Sopenharmony_ci 1733bf215546Sopenharmony_ci return VK_SUCCESS; 1734bf215546Sopenharmony_ci} 1735bf215546Sopenharmony_ci 1736bf215546Sopenharmony_ciVkResult 1737bf215546Sopenharmony_civn_renderer_create_virtgpu(struct vn_instance *instance, 1738bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc, 1739bf215546Sopenharmony_ci struct vn_renderer **renderer) 1740bf215546Sopenharmony_ci{ 1741bf215546Sopenharmony_ci struct virtgpu *gpu = vk_zalloc(alloc, sizeof(*gpu), VN_DEFAULT_ALIGN, 1742bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1743bf215546Sopenharmony_ci if (!gpu) 1744bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 1745bf215546Sopenharmony_ci 1746bf215546Sopenharmony_ci gpu->instance = instance; 1747bf215546Sopenharmony_ci gpu->fd = -1; 1748bf215546Sopenharmony_ci 1749bf215546Sopenharmony_ci VkResult result = virtgpu_init(gpu); 1750bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1751bf215546Sopenharmony_ci virtgpu_destroy(&gpu->base, alloc); 1752bf215546Sopenharmony_ci return result; 1753bf215546Sopenharmony_ci } 1754bf215546Sopenharmony_ci 1755bf215546Sopenharmony_ci *renderer = &gpu->base; 1756bf215546Sopenharmony_ci 1757bf215546Sopenharmony_ci return VK_SUCCESS; 1758bf215546Sopenharmony_ci} 1759