xref: /aosp_15_r20/external/virglrenderer/src/venus/vkr_ring.h (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1 /*
2  * Copyright 2021 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #ifndef VKR_RING_H
7 #define VKR_RING_H
8 
9 #include "vkr_common.h"
10 
11 /* We read from the ring buffer to a temporary buffer for
12  * virgl_context::submit_cmd.  Until that is changed, we want to put a limit
13  * on the size of the temporary buffer.  It also makes no sense to have huge
14  * rings.
15  *
16  * This must not exceed UINT32_MAX because the ring head and tail are 32-bit.
17  */
18 #define VKR_RING_BUFFER_MAX_SIZE (16u * 1024 * 1024)
19 
20 /* The layout of a ring in a virgl_resource.  This is parsed and discarded by
21  * vkr_ring_create.
22  */
23 struct vkr_ring_layout {
24    const struct vkr_resource_attachment *attachment;
25 
26    struct vkr_region head;
27    struct vkr_region tail;
28    struct vkr_region status;
29    struct vkr_region buffer;
30    struct vkr_region extra;
31 };
32 
33 static_assert(ATOMIC_INT_LOCK_FREE == 2 && sizeof(atomic_uint) == 4,
34               "vkr_ring_control requires lock-free 32-bit atomic_uint");
35 
36 /* the control region of a ring */
37 struct vkr_ring_control {
38    /* Pointers to ring head, tail, and status.
39     *
40     * Clients increment the tail after commands are added.  We increment the
41     * head after commands are executed.  The status is updated when there is a
42     * status change to the ring thread.
43     */
44    volatile atomic_uint *head;
45    const volatile atomic_uint *tail;
46    volatile atomic_uint *status;
47 };
48 
49 /* the buffer region of a ring */
50 struct vkr_ring_buffer {
51    /* the base of the region in the resource */
52    int base_iov_index;
53    size_t base_iov_offset;
54 
55    uint32_t size;
56    uint32_t mask;
57 
58    /* The current offset in the buffer region.  It is free-running and must be
59     * masked to be between [0, size).
60     */
61    uint32_t cur;
62 
63    /* The current iov and iov offset in the resource. */
64    const struct iovec *cur_iov;
65    int cur_iov_index;
66    size_t cur_iov_offset;
67 };
68 
69 /* the extra region of a ring */
70 struct vkr_ring_extra {
71    /* the base of the region in the resource */
72    int base_iov_index;
73    size_t base_iov_offset;
74 
75    /* used for offset validation */
76    struct vkr_region region;
77 
78    /* cache the latest offset->pointer result */
79    size_t cached_offset;
80    volatile atomic_uint *cached_data;
81 };
82 
83 struct vkr_ring {
84    /* used by the caller */
85    vkr_object_id id;
86    struct list_head head;
87 
88    /* ring regions */
89    const struct vkr_resource_attachment *attachment;
90    struct vkr_ring_control control;
91    struct vkr_ring_buffer buffer;
92    struct vkr_ring_extra extra;
93 
94    /* ring thread */
95    struct virgl_context *context;
96    uint64_t idle_timeout;
97    void *cmd;
98 
99    mtx_t mutex;
100    cnd_t cond;
101    thrd_t thread;
102    atomic_bool started;
103    atomic_bool pending_notify;
104 };
105 
106 struct vkr_ring *
107 vkr_ring_create(const struct vkr_ring_layout *layout,
108                 struct virgl_context *ctx,
109                 uint64_t idle_timeout);
110 
111 void
112 vkr_ring_destroy(struct vkr_ring *ring);
113 
114 void
115 vkr_ring_start(struct vkr_ring *ring);
116 
117 bool
118 vkr_ring_stop(struct vkr_ring *ring);
119 
120 void
121 vkr_ring_notify(struct vkr_ring *ring);
122 
123 bool
124 vkr_ring_write_extra(struct vkr_ring *ring, size_t offset, uint32_t val);
125 
126 #endif /* VKR_RING_H */
127