1 /*
2  * Copyright 2019 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #ifndef VN_RENDERER_H
7 #define VN_RENDERER_H
8 
9 #include "vn_common.h"
10 
11 struct vn_renderer_shmem {
12    struct vn_refcount refcount;
13 
14    uint32_t res_id;
15    size_t mmap_size; /* for internal use only (i.e., munmap) */
16    void *mmap_ptr;
17 };
18 
19 struct vn_renderer_bo {
20    struct vn_refcount refcount;
21 
22    uint32_t res_id;
23    /* for internal use only */
24    size_t mmap_size;
25    void *mmap_ptr;
26 };
27 
28 /*
29  * A sync consists of a uint64_t counter.  The counter can be updated by CPU
30  * or by GPU.  It can also be waited on by CPU or by GPU until it reaches
31  * certain values.
32  *
33  * This models after timeline VkSemaphore rather than timeline drm_syncobj.
34  * The main difference is that drm_syncobj can have unsignaled value 0.
35  */
36 struct vn_renderer_sync {
37    uint32_t sync_id;
38 };
39 
40 struct vn_renderer_info {
41    struct {
42       uint16_t vendor_id;
43       uint16_t device_id;
44 
45       bool has_bus_info;
46       uint16_t domain;
47       uint8_t bus;
48       uint8_t device;
49       uint8_t function;
50    } pci;
51 
52    bool has_dma_buf_import;
53    bool has_cache_management;
54    bool has_external_sync;
55    bool has_implicit_fencing;
56 
57    uint32_t max_sync_queue_count;
58 
59    /* hw capset */
60    uint32_t wire_format_version;
61    uint32_t vk_xml_version;
62    uint32_t vk_ext_command_serialization_spec_version;
63    uint32_t vk_mesa_venus_protocol_spec_version;
64 };
65 
66 struct vn_renderer_submit_batch {
67    const void *cs_data;
68    size_t cs_size;
69 
70    /*
71     * Submit cs to the virtual sync queue identified by sync_queue_index.  The
72     * virtual queue is assumed to be associated with the physical VkQueue
73     * identified by vk_queue_id.  After the execution completes on the
74     * VkQueue, the virtual sync queue is signaled.
75     *
76     * sync_queue_index must be less than max_sync_queue_count.
77     *
78     * vk_queue_id specifies the object id of a VkQueue.
79     *
80     * When sync_queue_cpu is true, it specifies the special CPU sync queue,
81     * and sync_queue_index/vk_queue_id are ignored.  TODO revisit this later
82     */
83    uint32_t sync_queue_index;
84    bool sync_queue_cpu;
85    vn_object_id vk_queue_id;
86 
87    /* syncs to update when the virtual sync queue is signaled */
88    struct vn_renderer_sync *const *syncs;
89    /* TODO allow NULL when syncs are all binary? */
90    const uint64_t *sync_values;
91    uint32_t sync_count;
92 };
93 
94 struct vn_renderer_submit {
95    /* BOs to pin and to fence implicitly
96     *
97     * TODO track all bos and automatically pin them.  We don't do it yet
98     * because each vn_command_buffer owns a bo.  We can probably make do by
99     * returning the bos to a bo cache and exclude bo cache from pinning.
100     */
101    struct vn_renderer_bo *const *bos;
102    uint32_t bo_count;
103 
104    const struct vn_renderer_submit_batch *batches;
105    uint32_t batch_count;
106 };
107 
108 struct vn_renderer_wait {
109    bool wait_any;
110    uint64_t timeout;
111 
112    struct vn_renderer_sync *const *syncs;
113    /* TODO allow NULL when syncs are all binary? */
114    const uint64_t *sync_values;
115    uint32_t sync_count;
116 };
117 
118 struct vn_renderer_ops {
119    void (*destroy)(struct vn_renderer *renderer,
120                    const VkAllocationCallbacks *alloc);
121 
122    void (*get_info)(struct vn_renderer *renderer,
123                     struct vn_renderer_info *info);
124 
125    VkResult (*submit)(struct vn_renderer *renderer,
126                       const struct vn_renderer_submit *submit);
127 
128    /*
129     * On success, returns VK_SUCCESS or VK_TIMEOUT.  On failure, returns
130     * VK_ERROR_DEVICE_LOST or out of device/host memory.
131     */
132    VkResult (*wait)(struct vn_renderer *renderer,
133                     const struct vn_renderer_wait *wait);
134 };
135 
136 struct vn_renderer_shmem_ops {
137    struct vn_renderer_shmem *(*create)(struct vn_renderer *renderer,
138                                        size_t size);
139    void (*destroy)(struct vn_renderer *renderer,
140                    struct vn_renderer_shmem *shmem);
141 };
142 
143 struct vn_renderer_bo_ops {
144    VkResult (*create_from_device_memory)(
145       struct vn_renderer *renderer,
146       VkDeviceSize size,
147       vn_object_id mem_id,
148       VkMemoryPropertyFlags flags,
149       VkExternalMemoryHandleTypeFlags external_handles,
150       struct vn_renderer_bo **out_bo);
151 
152    VkResult (*create_from_dma_buf)(struct vn_renderer *renderer,
153                                    VkDeviceSize size,
154                                    int fd,
155                                    VkMemoryPropertyFlags flags,
156                                    struct vn_renderer_bo **out_bo);
157 
158    bool (*destroy)(struct vn_renderer *renderer, struct vn_renderer_bo *bo);
159 
160    int (*export_dma_buf)(struct vn_renderer *renderer,
161                          struct vn_renderer_bo *bo);
162 
163    /* map is not thread-safe */
164    void *(*map)(struct vn_renderer *renderer, struct vn_renderer_bo *bo);
165 
166    void (*flush)(struct vn_renderer *renderer,
167                  struct vn_renderer_bo *bo,
168                  VkDeviceSize offset,
169                  VkDeviceSize size);
170    void (*invalidate)(struct vn_renderer *renderer,
171                       struct vn_renderer_bo *bo,
172                       VkDeviceSize offset,
173                       VkDeviceSize size);
174 };
175 
176 enum vn_renderer_sync_flags {
177    VN_RENDERER_SYNC_SHAREABLE = 1u << 0,
178    VN_RENDERER_SYNC_BINARY = 1u << 1,
179 };
180 
181 struct vn_renderer_sync_ops {
182    VkResult (*create)(struct vn_renderer *renderer,
183                       uint64_t initial_val,
184                       uint32_t flags,
185                       struct vn_renderer_sync **out_sync);
186 
187    VkResult (*create_from_syncobj)(struct vn_renderer *renderer,
188                                    int fd,
189                                    bool sync_file,
190                                    struct vn_renderer_sync **out_sync);
191    void (*destroy)(struct vn_renderer *renderer,
192                    struct vn_renderer_sync *sync);
193 
194    int (*export_syncobj)(struct vn_renderer *renderer,
195                          struct vn_renderer_sync *sync,
196                          bool sync_file);
197 
198    /* reset the counter */
199    VkResult (*reset)(struct vn_renderer *renderer,
200                      struct vn_renderer_sync *sync,
201                      uint64_t initial_val);
202 
203    /* read the current value from the counter */
204    VkResult (*read)(struct vn_renderer *renderer,
205                     struct vn_renderer_sync *sync,
206                     uint64_t *val);
207 
208    /* write a new value (larger than the current one) to the counter */
209    VkResult (*write)(struct vn_renderer *renderer,
210                      struct vn_renderer_sync *sync,
211                      uint64_t val);
212 };
213 
214 struct vn_renderer {
215    struct vn_renderer_ops ops;
216    struct vn_renderer_shmem_ops shmem_ops;
217    struct vn_renderer_bo_ops bo_ops;
218    struct vn_renderer_sync_ops sync_ops;
219 };
220 
221 VkResult
222 vn_renderer_create_virtgpu(struct vn_instance *instance,
223                            const VkAllocationCallbacks *alloc,
224                            struct vn_renderer **renderer);
225 
226 VkResult
227 vn_renderer_create_vtest(struct vn_instance *instance,
228                          const VkAllocationCallbacks *alloc,
229                          struct vn_renderer **renderer);
230 
231 static inline VkResult
vn_renderer_create(struct vn_instance * instance,const VkAllocationCallbacks * alloc,struct vn_renderer ** renderer)232 vn_renderer_create(struct vn_instance *instance,
233                    const VkAllocationCallbacks *alloc,
234                    struct vn_renderer **renderer)
235 {
236    if (VN_DEBUG(VTEST)) {
237       VkResult result = vn_renderer_create_vtest(instance, alloc, renderer);
238       if (result == VK_SUCCESS)
239          return VK_SUCCESS;
240    }
241 
242    return vn_renderer_create_virtgpu(instance, alloc, renderer);
243 }
244 
245 static inline void
vn_renderer_destroy(struct vn_renderer * renderer,const VkAllocationCallbacks * alloc)246 vn_renderer_destroy(struct vn_renderer *renderer,
247                     const VkAllocationCallbacks *alloc)
248 {
249    renderer->ops.destroy(renderer, alloc);
250 }
251 
252 static inline void
vn_renderer_get_info(struct vn_renderer * renderer,struct vn_renderer_info * info)253 vn_renderer_get_info(struct vn_renderer *renderer,
254                      struct vn_renderer_info *info)
255 {
256    renderer->ops.get_info(renderer, info);
257 }
258 
259 static inline VkResult
vn_renderer_submit(struct vn_renderer * renderer,const struct vn_renderer_submit * submit)260 vn_renderer_submit(struct vn_renderer *renderer,
261                    const struct vn_renderer_submit *submit)
262 {
263    return renderer->ops.submit(renderer, submit);
264 }
265 
266 static inline VkResult
vn_renderer_submit_simple(struct vn_renderer * renderer,const void * cs_data,size_t cs_size)267 vn_renderer_submit_simple(struct vn_renderer *renderer,
268                           const void *cs_data,
269                           size_t cs_size)
270 {
271    const struct vn_renderer_submit submit = {
272       .batches =
273          &(const struct vn_renderer_submit_batch){
274             .cs_data = cs_data,
275             .cs_size = cs_size,
276          },
277       .batch_count = 1,
278    };
279    return vn_renderer_submit(renderer, &submit);
280 }
281 
282 static inline VkResult
vn_renderer_wait(struct vn_renderer * renderer,const struct vn_renderer_wait * wait)283 vn_renderer_wait(struct vn_renderer *renderer,
284                  const struct vn_renderer_wait *wait)
285 {
286    return renderer->ops.wait(renderer, wait);
287 }
288 
289 static inline struct vn_renderer_shmem *
vn_renderer_shmem_create(struct vn_renderer * renderer,size_t size)290 vn_renderer_shmem_create(struct vn_renderer *renderer, size_t size)
291 {
292    struct vn_renderer_shmem *shmem =
293       renderer->shmem_ops.create(renderer, size);
294    if (shmem) {
295       assert(vn_refcount_is_valid(&shmem->refcount));
296       assert(shmem->res_id);
297       assert(shmem->mmap_size >= size);
298       assert(shmem->mmap_ptr);
299    }
300 
301    return shmem;
302 }
303 
304 static inline struct vn_renderer_shmem *
vn_renderer_shmem_ref(struct vn_renderer * renderer,struct vn_renderer_shmem * shmem)305 vn_renderer_shmem_ref(struct vn_renderer *renderer,
306                       struct vn_renderer_shmem *shmem)
307 {
308    vn_refcount_inc(&shmem->refcount);
309    return shmem;
310 }
311 
312 static inline void
vn_renderer_shmem_unref(struct vn_renderer * renderer,struct vn_renderer_shmem * shmem)313 vn_renderer_shmem_unref(struct vn_renderer *renderer,
314                         struct vn_renderer_shmem *shmem)
315 {
316    if (vn_refcount_dec(&shmem->refcount))
317       renderer->shmem_ops.destroy(renderer, shmem);
318 }
319 
320 static inline VkResult
vn_renderer_bo_create_from_device_memory(struct vn_renderer * renderer,VkDeviceSize size,vn_object_id mem_id,VkMemoryPropertyFlags flags,VkExternalMemoryHandleTypeFlags external_handles,struct vn_renderer_bo ** out_bo)321 vn_renderer_bo_create_from_device_memory(
322    struct vn_renderer *renderer,
323    VkDeviceSize size,
324    vn_object_id mem_id,
325    VkMemoryPropertyFlags flags,
326    VkExternalMemoryHandleTypeFlags external_handles,
327    struct vn_renderer_bo **out_bo)
328 {
329    struct vn_renderer_bo *bo;
330    VkResult result = renderer->bo_ops.create_from_device_memory(
331       renderer, size, mem_id, flags, external_handles, &bo);
332    if (result != VK_SUCCESS)
333       return result;
334 
335    assert(vn_refcount_is_valid(&bo->refcount));
336    assert(bo->res_id);
337    assert(!bo->mmap_size || bo->mmap_size >= size);
338 
339    *out_bo = bo;
340    return VK_SUCCESS;
341 }
342 
343 static inline VkResult
vn_renderer_bo_create_from_dma_buf(struct vn_renderer * renderer,VkDeviceSize size,int fd,VkMemoryPropertyFlags flags,struct vn_renderer_bo ** out_bo)344 vn_renderer_bo_create_from_dma_buf(struct vn_renderer *renderer,
345                                    VkDeviceSize size,
346                                    int fd,
347                                    VkMemoryPropertyFlags flags,
348                                    struct vn_renderer_bo **out_bo)
349 {
350    struct vn_renderer_bo *bo;
351    VkResult result =
352       renderer->bo_ops.create_from_dma_buf(renderer, size, fd, flags, &bo);
353    if (result != VK_SUCCESS)
354       return result;
355 
356    assert(vn_refcount_is_valid(&bo->refcount));
357    assert(bo->res_id);
358    assert(!bo->mmap_size || bo->mmap_size >= size);
359 
360    *out_bo = bo;
361    return VK_SUCCESS;
362 }
363 
364 static inline struct vn_renderer_bo *
vn_renderer_bo_ref(struct vn_renderer * renderer,struct vn_renderer_bo * bo)365 vn_renderer_bo_ref(struct vn_renderer *renderer, struct vn_renderer_bo *bo)
366 {
367    vn_refcount_inc(&bo->refcount);
368    return bo;
369 }
370 
371 static inline bool
vn_renderer_bo_unref(struct vn_renderer * renderer,struct vn_renderer_bo * bo)372 vn_renderer_bo_unref(struct vn_renderer *renderer, struct vn_renderer_bo *bo)
373 {
374    if (vn_refcount_dec(&bo->refcount))
375       return renderer->bo_ops.destroy(renderer, bo);
376    return false;
377 }
378 
379 static inline int
vn_renderer_bo_export_dma_buf(struct vn_renderer * renderer,struct vn_renderer_bo * bo)380 vn_renderer_bo_export_dma_buf(struct vn_renderer *renderer,
381                               struct vn_renderer_bo *bo)
382 {
383    return renderer->bo_ops.export_dma_buf(renderer, bo);
384 }
385 
386 static inline void *
vn_renderer_bo_map(struct vn_renderer * renderer,struct vn_renderer_bo * bo)387 vn_renderer_bo_map(struct vn_renderer *renderer, struct vn_renderer_bo *bo)
388 {
389    return renderer->bo_ops.map(renderer, bo);
390 }
391 
392 static inline void
vn_renderer_bo_flush(struct vn_renderer * renderer,struct vn_renderer_bo * bo,VkDeviceSize offset,VkDeviceSize end)393 vn_renderer_bo_flush(struct vn_renderer *renderer,
394                      struct vn_renderer_bo *bo,
395                      VkDeviceSize offset,
396                      VkDeviceSize end)
397 {
398    renderer->bo_ops.flush(renderer, bo, offset, end);
399 }
400 
401 static inline void
vn_renderer_bo_invalidate(struct vn_renderer * renderer,struct vn_renderer_bo * bo,VkDeviceSize offset,VkDeviceSize size)402 vn_renderer_bo_invalidate(struct vn_renderer *renderer,
403                           struct vn_renderer_bo *bo,
404                           VkDeviceSize offset,
405                           VkDeviceSize size)
406 {
407    renderer->bo_ops.invalidate(renderer, bo, offset, size);
408 }
409 
410 static inline VkResult
vn_renderer_sync_create(struct vn_renderer * renderer,uint64_t initial_val,uint32_t flags,struct vn_renderer_sync ** out_sync)411 vn_renderer_sync_create(struct vn_renderer *renderer,
412                         uint64_t initial_val,
413                         uint32_t flags,
414                         struct vn_renderer_sync **out_sync)
415 {
416    return renderer->sync_ops.create(renderer, initial_val, flags, out_sync);
417 }
418 
419 static inline VkResult
vn_renderer_sync_create_from_syncobj(struct vn_renderer * renderer,int fd,bool sync_file,struct vn_renderer_sync ** out_sync)420 vn_renderer_sync_create_from_syncobj(struct vn_renderer *renderer,
421                                      int fd,
422                                      bool sync_file,
423                                      struct vn_renderer_sync **out_sync)
424 {
425    return renderer->sync_ops.create_from_syncobj(renderer, fd, sync_file,
426                                                  out_sync);
427 }
428 
429 static inline void
vn_renderer_sync_destroy(struct vn_renderer * renderer,struct vn_renderer_sync * sync)430 vn_renderer_sync_destroy(struct vn_renderer *renderer,
431                          struct vn_renderer_sync *sync)
432 {
433    renderer->sync_ops.destroy(renderer, sync);
434 }
435 
436 static inline int
vn_renderer_sync_export_syncobj(struct vn_renderer * renderer,struct vn_renderer_sync * sync,bool sync_file)437 vn_renderer_sync_export_syncobj(struct vn_renderer *renderer,
438                                 struct vn_renderer_sync *sync,
439                                 bool sync_file)
440 {
441    return renderer->sync_ops.export_syncobj(renderer, sync, sync_file);
442 }
443 
444 static inline VkResult
vn_renderer_sync_reset(struct vn_renderer * renderer,struct vn_renderer_sync * sync,uint64_t initial_val)445 vn_renderer_sync_reset(struct vn_renderer *renderer,
446                        struct vn_renderer_sync *sync,
447                        uint64_t initial_val)
448 {
449    return renderer->sync_ops.reset(renderer, sync, initial_val);
450 }
451 
452 static inline VkResult
vn_renderer_sync_read(struct vn_renderer * renderer,struct vn_renderer_sync * sync,uint64_t * val)453 vn_renderer_sync_read(struct vn_renderer *renderer,
454                       struct vn_renderer_sync *sync,
455                       uint64_t *val)
456 {
457    return renderer->sync_ops.read(renderer, sync, val);
458 }
459 
460 static inline VkResult
vn_renderer_sync_write(struct vn_renderer * renderer,struct vn_renderer_sync * sync,uint64_t val)461 vn_renderer_sync_write(struct vn_renderer *renderer,
462                        struct vn_renderer_sync *sync,
463                        uint64_t val)
464 {
465    return renderer->sync_ops.write(renderer, sync, val);
466 }
467 
468 static inline VkResult
vn_renderer_submit_simple_sync(struct vn_renderer * renderer,const void * cs_data,size_t cs_size)469 vn_renderer_submit_simple_sync(struct vn_renderer *renderer,
470                                const void *cs_data,
471                                size_t cs_size)
472 {
473    struct vn_renderer_sync *sync;
474    VkResult result =
475       vn_renderer_sync_create(renderer, 0, VN_RENDERER_SYNC_BINARY, &sync);
476    if (result != VK_SUCCESS)
477       return result;
478 
479    const struct vn_renderer_submit submit = {
480       .batches =
481          &(const struct vn_renderer_submit_batch){
482             .cs_data = cs_data,
483             .cs_size = cs_size,
484             .sync_queue_cpu = true,
485             .syncs = &sync,
486             .sync_values = &(const uint64_t){ 1 },
487             .sync_count = 1,
488          },
489       .batch_count = 1,
490    };
491    const struct vn_renderer_wait wait = {
492       .timeout = UINT64_MAX,
493       .syncs = &sync,
494       .sync_values = &(const uint64_t){ 1 },
495       .sync_count = 1,
496    };
497 
498    result = vn_renderer_submit(renderer, &submit);
499    if (result == VK_SUCCESS)
500       result = vn_renderer_wait(renderer, &wait);
501 
502    vn_renderer_sync_destroy(renderer, sync);
503 
504    return result;
505 }
506 
507 #endif /* VN_RENDERER_H */
508