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