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