xref: /aosp_15_r20/external/virglrenderer/src/venus/vkr_ring.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*bbecb9d1SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*bbecb9d1SAndroid Build Coastguard Worker  */
5*bbecb9d1SAndroid Build Coastguard Worker 
6*bbecb9d1SAndroid Build Coastguard Worker #include "vkr_ring.h"
7*bbecb9d1SAndroid Build Coastguard Worker 
8*bbecb9d1SAndroid Build Coastguard Worker #include <stdio.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <time.h>
10*bbecb9d1SAndroid Build Coastguard Worker 
11*bbecb9d1SAndroid Build Coastguard Worker #include "vrend_iov.h"
12*bbecb9d1SAndroid Build Coastguard Worker 
13*bbecb9d1SAndroid Build Coastguard Worker #include "vkr_context.h"
14*bbecb9d1SAndroid Build Coastguard Worker 
15*bbecb9d1SAndroid Build Coastguard Worker enum vkr_ring_status_flag {
16*bbecb9d1SAndroid Build Coastguard Worker    VKR_RING_STATUS_IDLE = 1u << 0,
17*bbecb9d1SAndroid Build Coastguard Worker };
18*bbecb9d1SAndroid Build Coastguard Worker 
19*bbecb9d1SAndroid Build Coastguard Worker /* callers must make sure they do not seek to end-of-resource or beyond */
20*bbecb9d1SAndroid Build Coastguard Worker static const struct iovec *
seek_resource(const struct vkr_resource_attachment * att,int base_iov_index,size_t offset,int * out_iov_index,size_t * out_iov_offset)21*bbecb9d1SAndroid Build Coastguard Worker seek_resource(const struct vkr_resource_attachment *att,
22*bbecb9d1SAndroid Build Coastguard Worker               int base_iov_index,
23*bbecb9d1SAndroid Build Coastguard Worker               size_t offset,
24*bbecb9d1SAndroid Build Coastguard Worker               int *out_iov_index,
25*bbecb9d1SAndroid Build Coastguard Worker               size_t *out_iov_offset)
26*bbecb9d1SAndroid Build Coastguard Worker {
27*bbecb9d1SAndroid Build Coastguard Worker    const struct iovec *iov = &att->iov[base_iov_index];
28*bbecb9d1SAndroid Build Coastguard Worker    assert(iov - att->iov < att->iov_count);
29*bbecb9d1SAndroid Build Coastguard Worker    while (offset >= iov->iov_len) {
30*bbecb9d1SAndroid Build Coastguard Worker       offset -= iov->iov_len;
31*bbecb9d1SAndroid Build Coastguard Worker       iov++;
32*bbecb9d1SAndroid Build Coastguard Worker       assert(iov - att->iov < att->iov_count);
33*bbecb9d1SAndroid Build Coastguard Worker    }
34*bbecb9d1SAndroid Build Coastguard Worker 
35*bbecb9d1SAndroid Build Coastguard Worker    *out_iov_index = iov - att->iov;
36*bbecb9d1SAndroid Build Coastguard Worker    *out_iov_offset = offset;
37*bbecb9d1SAndroid Build Coastguard Worker 
38*bbecb9d1SAndroid Build Coastguard Worker    return iov;
39*bbecb9d1SAndroid Build Coastguard Worker }
40*bbecb9d1SAndroid Build Coastguard Worker 
41*bbecb9d1SAndroid Build Coastguard Worker static void *
get_resource_pointer(const struct vkr_resource_attachment * att,int base_iov_index,size_t offset)42*bbecb9d1SAndroid Build Coastguard Worker get_resource_pointer(const struct vkr_resource_attachment *att,
43*bbecb9d1SAndroid Build Coastguard Worker                      int base_iov_index,
44*bbecb9d1SAndroid Build Coastguard Worker                      size_t offset)
45*bbecb9d1SAndroid Build Coastguard Worker {
46*bbecb9d1SAndroid Build Coastguard Worker    const struct iovec *iov =
47*bbecb9d1SAndroid Build Coastguard Worker       seek_resource(att, base_iov_index, offset, &base_iov_index, &offset);
48*bbecb9d1SAndroid Build Coastguard Worker    return (uint8_t *)iov->iov_base + offset;
49*bbecb9d1SAndroid Build Coastguard Worker }
50*bbecb9d1SAndroid Build Coastguard Worker 
51*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_init_extra(struct vkr_ring * ring,const struct vkr_ring_layout * layout)52*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_init_extra(struct vkr_ring *ring, const struct vkr_ring_layout *layout)
53*bbecb9d1SAndroid Build Coastguard Worker {
54*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring_extra *extra = &ring->extra;
55*bbecb9d1SAndroid Build Coastguard Worker 
56*bbecb9d1SAndroid Build Coastguard Worker    seek_resource(layout->attachment, 0, layout->extra.begin, &extra->base_iov_index,
57*bbecb9d1SAndroid Build Coastguard Worker                  &extra->base_iov_offset);
58*bbecb9d1SAndroid Build Coastguard Worker 
59*bbecb9d1SAndroid Build Coastguard Worker    extra->region = vkr_region_make_relative(&layout->extra);
60*bbecb9d1SAndroid Build Coastguard Worker }
61*bbecb9d1SAndroid Build Coastguard Worker 
62*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_init_buffer(struct vkr_ring * ring,const struct vkr_ring_layout * layout)63*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_init_buffer(struct vkr_ring *ring, const struct vkr_ring_layout *layout)
64*bbecb9d1SAndroid Build Coastguard Worker {
65*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring_buffer *buf = &ring->buffer;
66*bbecb9d1SAndroid Build Coastguard Worker 
67*bbecb9d1SAndroid Build Coastguard Worker    const struct iovec *base_iov =
68*bbecb9d1SAndroid Build Coastguard Worker       seek_resource(layout->attachment, 0, layout->buffer.begin, &buf->base_iov_index,
69*bbecb9d1SAndroid Build Coastguard Worker                     &buf->base_iov_offset);
70*bbecb9d1SAndroid Build Coastguard Worker 
71*bbecb9d1SAndroid Build Coastguard Worker    buf->size = vkr_region_size(&layout->buffer);
72*bbecb9d1SAndroid Build Coastguard Worker    assert(util_is_power_of_two_nonzero(buf->size));
73*bbecb9d1SAndroid Build Coastguard Worker    buf->mask = buf->size - 1;
74*bbecb9d1SAndroid Build Coastguard Worker 
75*bbecb9d1SAndroid Build Coastguard Worker    buf->cur = 0;
76*bbecb9d1SAndroid Build Coastguard Worker    buf->cur_iov = base_iov;
77*bbecb9d1SAndroid Build Coastguard Worker    buf->cur_iov_index = buf->base_iov_index;
78*bbecb9d1SAndroid Build Coastguard Worker    buf->cur_iov_offset = buf->base_iov_offset;
79*bbecb9d1SAndroid Build Coastguard Worker }
80*bbecb9d1SAndroid Build Coastguard Worker 
81*bbecb9d1SAndroid Build Coastguard Worker static bool
vkr_ring_init_control(struct vkr_ring * ring,const struct vkr_ring_layout * layout)82*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_init_control(struct vkr_ring *ring, const struct vkr_ring_layout *layout)
83*bbecb9d1SAndroid Build Coastguard Worker {
84*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring_control *ctrl = &ring->control;
85*bbecb9d1SAndroid Build Coastguard Worker 
86*bbecb9d1SAndroid Build Coastguard Worker    ctrl->head = get_resource_pointer(layout->attachment, 0, layout->head.begin);
87*bbecb9d1SAndroid Build Coastguard Worker    ctrl->tail = get_resource_pointer(layout->attachment, 0, layout->tail.begin);
88*bbecb9d1SAndroid Build Coastguard Worker    ctrl->status = get_resource_pointer(layout->attachment, 0, layout->status.begin);
89*bbecb9d1SAndroid Build Coastguard Worker 
90*bbecb9d1SAndroid Build Coastguard Worker    /* we will manage head and status, and we expect them to be 0 initially */
91*bbecb9d1SAndroid Build Coastguard Worker    if (*ctrl->head || *ctrl->status)
92*bbecb9d1SAndroid Build Coastguard Worker       return false;
93*bbecb9d1SAndroid Build Coastguard Worker 
94*bbecb9d1SAndroid Build Coastguard Worker    return true;
95*bbecb9d1SAndroid Build Coastguard Worker }
96*bbecb9d1SAndroid Build Coastguard Worker 
97*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_store_head(struct vkr_ring * ring)98*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_store_head(struct vkr_ring *ring)
99*bbecb9d1SAndroid Build Coastguard Worker {
100*bbecb9d1SAndroid Build Coastguard Worker    /* the renderer is expected to load the head with memory_order_acquire,
101*bbecb9d1SAndroid Build Coastguard Worker     * forming a release-acquire ordering
102*bbecb9d1SAndroid Build Coastguard Worker     */
103*bbecb9d1SAndroid Build Coastguard Worker    atomic_store_explicit(ring->control.head, ring->buffer.cur, memory_order_release);
104*bbecb9d1SAndroid Build Coastguard Worker }
105*bbecb9d1SAndroid Build Coastguard Worker 
106*bbecb9d1SAndroid Build Coastguard Worker static uint32_t
vkr_ring_load_tail(const struct vkr_ring * ring)107*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_load_tail(const struct vkr_ring *ring)
108*bbecb9d1SAndroid Build Coastguard Worker {
109*bbecb9d1SAndroid Build Coastguard Worker    /* the driver is expected to store the tail with memory_order_release,
110*bbecb9d1SAndroid Build Coastguard Worker     * forming a release-acquire ordering
111*bbecb9d1SAndroid Build Coastguard Worker     */
112*bbecb9d1SAndroid Build Coastguard Worker    return atomic_load_explicit(ring->control.tail, memory_order_acquire);
113*bbecb9d1SAndroid Build Coastguard Worker }
114*bbecb9d1SAndroid Build Coastguard Worker 
115*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_store_status(struct vkr_ring * ring,uint32_t status)116*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_store_status(struct vkr_ring *ring, uint32_t status)
117*bbecb9d1SAndroid Build Coastguard Worker {
118*bbecb9d1SAndroid Build Coastguard Worker    atomic_store_explicit(ring->control.status, status, memory_order_seq_cst);
119*bbecb9d1SAndroid Build Coastguard Worker }
120*bbecb9d1SAndroid Build Coastguard Worker 
121*bbecb9d1SAndroid Build Coastguard Worker /* TODO consider requiring virgl_resource to be logically contiguous */
122*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_read_buffer(struct vkr_ring * ring,void * data,uint32_t size)123*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_read_buffer(struct vkr_ring *ring, void *data, uint32_t size)
124*bbecb9d1SAndroid Build Coastguard Worker {
125*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring_buffer *buf = &ring->buffer;
126*bbecb9d1SAndroid Build Coastguard Worker    const struct vkr_resource_attachment *att = ring->attachment;
127*bbecb9d1SAndroid Build Coastguard Worker 
128*bbecb9d1SAndroid Build Coastguard Worker    assert(size <= buf->size);
129*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t buf_offset = buf->cur & buf->mask;
130*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t buf_avail = buf->size - buf_offset;
131*bbecb9d1SAndroid Build Coastguard Worker    const bool wrap = size >= buf_avail;
132*bbecb9d1SAndroid Build Coastguard Worker 
133*bbecb9d1SAndroid Build Coastguard Worker    uint32_t read_size;
134*bbecb9d1SAndroid Build Coastguard Worker    uint32_t wrap_size;
135*bbecb9d1SAndroid Build Coastguard Worker    if (!wrap) {
136*bbecb9d1SAndroid Build Coastguard Worker       read_size = size;
137*bbecb9d1SAndroid Build Coastguard Worker       wrap_size = 0;
138*bbecb9d1SAndroid Build Coastguard Worker    } else {
139*bbecb9d1SAndroid Build Coastguard Worker       read_size = buf_avail;
140*bbecb9d1SAndroid Build Coastguard Worker       /* When size == buf_avail, wrap is true but wrap_size is 0.  We want to
141*bbecb9d1SAndroid Build Coastguard Worker        * wrap because it seems slightly faster on the next call.  Besides,
142*bbecb9d1SAndroid Build Coastguard Worker        * seek_resource does not support seeking to end-of-resource which could
143*bbecb9d1SAndroid Build Coastguard Worker        * happen if we don't wrap and the buffer region end coincides with the
144*bbecb9d1SAndroid Build Coastguard Worker        * resource end.
145*bbecb9d1SAndroid Build Coastguard Worker        */
146*bbecb9d1SAndroid Build Coastguard Worker       wrap_size = size - buf_avail;
147*bbecb9d1SAndroid Build Coastguard Worker    }
148*bbecb9d1SAndroid Build Coastguard Worker 
149*bbecb9d1SAndroid Build Coastguard Worker    /* do the reads */
150*bbecb9d1SAndroid Build Coastguard Worker    if (read_size <= buf->cur_iov->iov_len - buf->cur_iov_offset) {
151*bbecb9d1SAndroid Build Coastguard Worker       const void *src = (const uint8_t *)buf->cur_iov->iov_base + buf->cur_iov_offset;
152*bbecb9d1SAndroid Build Coastguard Worker       memcpy(data, src, read_size);
153*bbecb9d1SAndroid Build Coastguard Worker 
154*bbecb9d1SAndroid Build Coastguard Worker       /* fast path */
155*bbecb9d1SAndroid Build Coastguard Worker       if (!wrap) {
156*bbecb9d1SAndroid Build Coastguard Worker          assert(!wrap_size);
157*bbecb9d1SAndroid Build Coastguard Worker          buf->cur += read_size;
158*bbecb9d1SAndroid Build Coastguard Worker          buf->cur_iov_offset += read_size;
159*bbecb9d1SAndroid Build Coastguard Worker          return;
160*bbecb9d1SAndroid Build Coastguard Worker       }
161*bbecb9d1SAndroid Build Coastguard Worker    } else {
162*bbecb9d1SAndroid Build Coastguard Worker       vrend_read_from_iovec(buf->cur_iov, att->iov_count - buf->cur_iov_index,
163*bbecb9d1SAndroid Build Coastguard Worker                             buf->cur_iov_offset, data, read_size);
164*bbecb9d1SAndroid Build Coastguard Worker    }
165*bbecb9d1SAndroid Build Coastguard Worker 
166*bbecb9d1SAndroid Build Coastguard Worker    if (wrap_size) {
167*bbecb9d1SAndroid Build Coastguard Worker       vrend_read_from_iovec(att->iov + buf->base_iov_index,
168*bbecb9d1SAndroid Build Coastguard Worker                             att->iov_count - buf->base_iov_index, buf->base_iov_offset,
169*bbecb9d1SAndroid Build Coastguard Worker                             (char *)data + read_size, wrap_size);
170*bbecb9d1SAndroid Build Coastguard Worker    }
171*bbecb9d1SAndroid Build Coastguard Worker 
172*bbecb9d1SAndroid Build Coastguard Worker    /* advance cur */
173*bbecb9d1SAndroid Build Coastguard Worker    buf->cur += size;
174*bbecb9d1SAndroid Build Coastguard Worker    if (!wrap) {
175*bbecb9d1SAndroid Build Coastguard Worker       buf->cur_iov = seek_resource(att, buf->cur_iov_index, buf->cur_iov_offset + size,
176*bbecb9d1SAndroid Build Coastguard Worker                                    &buf->cur_iov_index, &buf->cur_iov_offset);
177*bbecb9d1SAndroid Build Coastguard Worker    } else {
178*bbecb9d1SAndroid Build Coastguard Worker       buf->cur_iov =
179*bbecb9d1SAndroid Build Coastguard Worker          seek_resource(att, buf->base_iov_index, buf->base_iov_offset + wrap_size,
180*bbecb9d1SAndroid Build Coastguard Worker                        &buf->cur_iov_index, &buf->cur_iov_offset);
181*bbecb9d1SAndroid Build Coastguard Worker    }
182*bbecb9d1SAndroid Build Coastguard Worker }
183*bbecb9d1SAndroid Build Coastguard Worker 
184*bbecb9d1SAndroid Build Coastguard Worker struct vkr_ring *
vkr_ring_create(const struct vkr_ring_layout * layout,struct virgl_context * ctx,uint64_t idle_timeout)185*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_create(const struct vkr_ring_layout *layout,
186*bbecb9d1SAndroid Build Coastguard Worker                 struct virgl_context *ctx,
187*bbecb9d1SAndroid Build Coastguard Worker                 uint64_t idle_timeout)
188*bbecb9d1SAndroid Build Coastguard Worker {
189*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring *ring;
190*bbecb9d1SAndroid Build Coastguard Worker    int ret;
191*bbecb9d1SAndroid Build Coastguard Worker 
192*bbecb9d1SAndroid Build Coastguard Worker    ring = calloc(1, sizeof(*ring));
193*bbecb9d1SAndroid Build Coastguard Worker    if (!ring)
194*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
195*bbecb9d1SAndroid Build Coastguard Worker 
196*bbecb9d1SAndroid Build Coastguard Worker    ring->attachment = layout->attachment;
197*bbecb9d1SAndroid Build Coastguard Worker 
198*bbecb9d1SAndroid Build Coastguard Worker    if (!vkr_ring_init_control(ring, layout)) {
199*bbecb9d1SAndroid Build Coastguard Worker       free(ring);
200*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
201*bbecb9d1SAndroid Build Coastguard Worker    }
202*bbecb9d1SAndroid Build Coastguard Worker 
203*bbecb9d1SAndroid Build Coastguard Worker    vkr_ring_init_buffer(ring, layout);
204*bbecb9d1SAndroid Build Coastguard Worker    vkr_ring_init_extra(ring, layout);
205*bbecb9d1SAndroid Build Coastguard Worker 
206*bbecb9d1SAndroid Build Coastguard Worker    ring->cmd = malloc(ring->buffer.size);
207*bbecb9d1SAndroid Build Coastguard Worker    if (!ring->cmd) {
208*bbecb9d1SAndroid Build Coastguard Worker       free(ring);
209*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
210*bbecb9d1SAndroid Build Coastguard Worker    }
211*bbecb9d1SAndroid Build Coastguard Worker 
212*bbecb9d1SAndroid Build Coastguard Worker    ring->context = ctx;
213*bbecb9d1SAndroid Build Coastguard Worker    ring->idle_timeout = idle_timeout;
214*bbecb9d1SAndroid Build Coastguard Worker 
215*bbecb9d1SAndroid Build Coastguard Worker    ret = mtx_init(&ring->mutex, mtx_plain);
216*bbecb9d1SAndroid Build Coastguard Worker    if (ret != thrd_success) {
217*bbecb9d1SAndroid Build Coastguard Worker       free(ring->cmd);
218*bbecb9d1SAndroid Build Coastguard Worker       free(ring);
219*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
220*bbecb9d1SAndroid Build Coastguard Worker    }
221*bbecb9d1SAndroid Build Coastguard Worker    ret = cnd_init(&ring->cond);
222*bbecb9d1SAndroid Build Coastguard Worker    if (ret != thrd_success) {
223*bbecb9d1SAndroid Build Coastguard Worker       mtx_destroy(&ring->mutex);
224*bbecb9d1SAndroid Build Coastguard Worker       free(ring->cmd);
225*bbecb9d1SAndroid Build Coastguard Worker       free(ring);
226*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
227*bbecb9d1SAndroid Build Coastguard Worker    }
228*bbecb9d1SAndroid Build Coastguard Worker 
229*bbecb9d1SAndroid Build Coastguard Worker    return ring;
230*bbecb9d1SAndroid Build Coastguard Worker }
231*bbecb9d1SAndroid Build Coastguard Worker 
232*bbecb9d1SAndroid Build Coastguard Worker void
vkr_ring_destroy(struct vkr_ring * ring)233*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_destroy(struct vkr_ring *ring)
234*bbecb9d1SAndroid Build Coastguard Worker {
235*bbecb9d1SAndroid Build Coastguard Worker    list_del(&ring->head);
236*bbecb9d1SAndroid Build Coastguard Worker 
237*bbecb9d1SAndroid Build Coastguard Worker    assert(!ring->started);
238*bbecb9d1SAndroid Build Coastguard Worker    mtx_destroy(&ring->mutex);
239*bbecb9d1SAndroid Build Coastguard Worker    cnd_destroy(&ring->cond);
240*bbecb9d1SAndroid Build Coastguard Worker    free(ring->cmd);
241*bbecb9d1SAndroid Build Coastguard Worker    free(ring);
242*bbecb9d1SAndroid Build Coastguard Worker }
243*bbecb9d1SAndroid Build Coastguard Worker 
244*bbecb9d1SAndroid Build Coastguard Worker static uint64_t
vkr_ring_now(void)245*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_now(void)
246*bbecb9d1SAndroid Build Coastguard Worker {
247*bbecb9d1SAndroid Build Coastguard Worker    const uint64_t ns_per_sec = 1000000000llu;
248*bbecb9d1SAndroid Build Coastguard Worker    struct timespec now;
249*bbecb9d1SAndroid Build Coastguard Worker    if (clock_gettime(CLOCK_MONOTONIC, &now))
250*bbecb9d1SAndroid Build Coastguard Worker       return 0;
251*bbecb9d1SAndroid Build Coastguard Worker    return ns_per_sec * now.tv_sec + now.tv_nsec;
252*bbecb9d1SAndroid Build Coastguard Worker }
253*bbecb9d1SAndroid Build Coastguard Worker 
254*bbecb9d1SAndroid Build Coastguard Worker static void
vkr_ring_relax(uint32_t * iter)255*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_relax(uint32_t *iter)
256*bbecb9d1SAndroid Build Coastguard Worker {
257*bbecb9d1SAndroid Build Coastguard Worker    /* TODO do better */
258*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t busy_wait_order = 4;
259*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t base_sleep_us = 10;
260*bbecb9d1SAndroid Build Coastguard Worker 
261*bbecb9d1SAndroid Build Coastguard Worker    (*iter)++;
262*bbecb9d1SAndroid Build Coastguard Worker    if (*iter < (1u << busy_wait_order)) {
263*bbecb9d1SAndroid Build Coastguard Worker       thrd_yield();
264*bbecb9d1SAndroid Build Coastguard Worker       return;
265*bbecb9d1SAndroid Build Coastguard Worker    }
266*bbecb9d1SAndroid Build Coastguard Worker 
267*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t shift = util_last_bit(*iter) - busy_wait_order - 1;
268*bbecb9d1SAndroid Build Coastguard Worker    const uint32_t us = base_sleep_us << shift;
269*bbecb9d1SAndroid Build Coastguard Worker    const struct timespec ts = {
270*bbecb9d1SAndroid Build Coastguard Worker       .tv_sec = us / 1000000,
271*bbecb9d1SAndroid Build Coastguard Worker       .tv_nsec = (us % 1000000) * 1000,
272*bbecb9d1SAndroid Build Coastguard Worker    };
273*bbecb9d1SAndroid Build Coastguard Worker    clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
274*bbecb9d1SAndroid Build Coastguard Worker }
275*bbecb9d1SAndroid Build Coastguard Worker 
276*bbecb9d1SAndroid Build Coastguard Worker static int
vkr_ring_thread(void * arg)277*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_thread(void *arg)
278*bbecb9d1SAndroid Build Coastguard Worker {
279*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring *ring = arg;
280*bbecb9d1SAndroid Build Coastguard Worker    struct virgl_context *ctx = ring->context;
281*bbecb9d1SAndroid Build Coastguard Worker    char thread_name[16];
282*bbecb9d1SAndroid Build Coastguard Worker 
283*bbecb9d1SAndroid Build Coastguard Worker    snprintf(thread_name, ARRAY_SIZE(thread_name), "vkr-ring-%d", ctx->ctx_id);
284*bbecb9d1SAndroid Build Coastguard Worker    u_thread_setname(thread_name);
285*bbecb9d1SAndroid Build Coastguard Worker 
286*bbecb9d1SAndroid Build Coastguard Worker    uint64_t last_submit = vkr_ring_now();
287*bbecb9d1SAndroid Build Coastguard Worker    uint32_t relax_iter = 0;
288*bbecb9d1SAndroid Build Coastguard Worker    int ret = 0;
289*bbecb9d1SAndroid Build Coastguard Worker    while (ring->started) {
290*bbecb9d1SAndroid Build Coastguard Worker       bool wait = false;
291*bbecb9d1SAndroid Build Coastguard Worker       uint32_t cmd_size;
292*bbecb9d1SAndroid Build Coastguard Worker 
293*bbecb9d1SAndroid Build Coastguard Worker       if (vkr_ring_now() >= last_submit + ring->idle_timeout) {
294*bbecb9d1SAndroid Build Coastguard Worker          ring->pending_notify = false;
295*bbecb9d1SAndroid Build Coastguard Worker          vkr_ring_store_status(ring, VKR_RING_STATUS_IDLE);
296*bbecb9d1SAndroid Build Coastguard Worker          wait = ring->buffer.cur == vkr_ring_load_tail(ring);
297*bbecb9d1SAndroid Build Coastguard Worker          if (!wait)
298*bbecb9d1SAndroid Build Coastguard Worker             vkr_ring_store_status(ring, 0);
299*bbecb9d1SAndroid Build Coastguard Worker       }
300*bbecb9d1SAndroid Build Coastguard Worker 
301*bbecb9d1SAndroid Build Coastguard Worker       if (wait) {
302*bbecb9d1SAndroid Build Coastguard Worker          TRACE_SCOPE("ring idle");
303*bbecb9d1SAndroid Build Coastguard Worker 
304*bbecb9d1SAndroid Build Coastguard Worker          mtx_lock(&ring->mutex);
305*bbecb9d1SAndroid Build Coastguard Worker          if (ring->started && !ring->pending_notify)
306*bbecb9d1SAndroid Build Coastguard Worker             cnd_wait(&ring->cond, &ring->mutex);
307*bbecb9d1SAndroid Build Coastguard Worker          vkr_ring_store_status(ring, 0);
308*bbecb9d1SAndroid Build Coastguard Worker          mtx_unlock(&ring->mutex);
309*bbecb9d1SAndroid Build Coastguard Worker 
310*bbecb9d1SAndroid Build Coastguard Worker          if (!ring->started)
311*bbecb9d1SAndroid Build Coastguard Worker             break;
312*bbecb9d1SAndroid Build Coastguard Worker 
313*bbecb9d1SAndroid Build Coastguard Worker          last_submit = vkr_ring_now();
314*bbecb9d1SAndroid Build Coastguard Worker          relax_iter = 0;
315*bbecb9d1SAndroid Build Coastguard Worker       }
316*bbecb9d1SAndroid Build Coastguard Worker 
317*bbecb9d1SAndroid Build Coastguard Worker       cmd_size = vkr_ring_load_tail(ring) - ring->buffer.cur;
318*bbecb9d1SAndroid Build Coastguard Worker       if (cmd_size) {
319*bbecb9d1SAndroid Build Coastguard Worker          if (cmd_size > ring->buffer.size) {
320*bbecb9d1SAndroid Build Coastguard Worker             ret = -EINVAL;
321*bbecb9d1SAndroid Build Coastguard Worker             break;
322*bbecb9d1SAndroid Build Coastguard Worker          }
323*bbecb9d1SAndroid Build Coastguard Worker 
324*bbecb9d1SAndroid Build Coastguard Worker          vkr_ring_read_buffer(ring, ring->cmd, cmd_size);
325*bbecb9d1SAndroid Build Coastguard Worker          ctx->submit_cmd(ctx, ring->cmd, cmd_size);
326*bbecb9d1SAndroid Build Coastguard Worker          vkr_ring_store_head(ring);
327*bbecb9d1SAndroid Build Coastguard Worker 
328*bbecb9d1SAndroid Build Coastguard Worker          last_submit = vkr_ring_now();
329*bbecb9d1SAndroid Build Coastguard Worker          relax_iter = 0;
330*bbecb9d1SAndroid Build Coastguard Worker       } else {
331*bbecb9d1SAndroid Build Coastguard Worker          vkr_ring_relax(&relax_iter);
332*bbecb9d1SAndroid Build Coastguard Worker       }
333*bbecb9d1SAndroid Build Coastguard Worker    }
334*bbecb9d1SAndroid Build Coastguard Worker 
335*bbecb9d1SAndroid Build Coastguard Worker    return ret;
336*bbecb9d1SAndroid Build Coastguard Worker }
337*bbecb9d1SAndroid Build Coastguard Worker 
338*bbecb9d1SAndroid Build Coastguard Worker void
vkr_ring_start(struct vkr_ring * ring)339*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_start(struct vkr_ring *ring)
340*bbecb9d1SAndroid Build Coastguard Worker {
341*bbecb9d1SAndroid Build Coastguard Worker    int ret;
342*bbecb9d1SAndroid Build Coastguard Worker 
343*bbecb9d1SAndroid Build Coastguard Worker    assert(!ring->started);
344*bbecb9d1SAndroid Build Coastguard Worker    ring->started = true;
345*bbecb9d1SAndroid Build Coastguard Worker    ret = thrd_create(&ring->thread, vkr_ring_thread, ring);
346*bbecb9d1SAndroid Build Coastguard Worker    if (ret != thrd_success)
347*bbecb9d1SAndroid Build Coastguard Worker       ring->started = false;
348*bbecb9d1SAndroid Build Coastguard Worker }
349*bbecb9d1SAndroid Build Coastguard Worker 
350*bbecb9d1SAndroid Build Coastguard Worker bool
vkr_ring_stop(struct vkr_ring * ring)351*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_stop(struct vkr_ring *ring)
352*bbecb9d1SAndroid Build Coastguard Worker {
353*bbecb9d1SAndroid Build Coastguard Worker    mtx_lock(&ring->mutex);
354*bbecb9d1SAndroid Build Coastguard Worker    if (thrd_equal(ring->thread, thrd_current())) {
355*bbecb9d1SAndroid Build Coastguard Worker       mtx_unlock(&ring->mutex);
356*bbecb9d1SAndroid Build Coastguard Worker       return false;
357*bbecb9d1SAndroid Build Coastguard Worker    }
358*bbecb9d1SAndroid Build Coastguard Worker    assert(ring->started);
359*bbecb9d1SAndroid Build Coastguard Worker    ring->started = false;
360*bbecb9d1SAndroid Build Coastguard Worker    cnd_signal(&ring->cond);
361*bbecb9d1SAndroid Build Coastguard Worker    mtx_unlock(&ring->mutex);
362*bbecb9d1SAndroid Build Coastguard Worker 
363*bbecb9d1SAndroid Build Coastguard Worker    thrd_join(ring->thread, NULL);
364*bbecb9d1SAndroid Build Coastguard Worker 
365*bbecb9d1SAndroid Build Coastguard Worker    return true;
366*bbecb9d1SAndroid Build Coastguard Worker }
367*bbecb9d1SAndroid Build Coastguard Worker 
368*bbecb9d1SAndroid Build Coastguard Worker void
vkr_ring_notify(struct vkr_ring * ring)369*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_notify(struct vkr_ring *ring)
370*bbecb9d1SAndroid Build Coastguard Worker {
371*bbecb9d1SAndroid Build Coastguard Worker    mtx_lock(&ring->mutex);
372*bbecb9d1SAndroid Build Coastguard Worker    ring->pending_notify = true;
373*bbecb9d1SAndroid Build Coastguard Worker    cnd_signal(&ring->cond);
374*bbecb9d1SAndroid Build Coastguard Worker    mtx_unlock(&ring->mutex);
375*bbecb9d1SAndroid Build Coastguard Worker 
376*bbecb9d1SAndroid Build Coastguard Worker    {
377*bbecb9d1SAndroid Build Coastguard Worker       TRACE_SCOPE("ring notify done");
378*bbecb9d1SAndroid Build Coastguard Worker    }
379*bbecb9d1SAndroid Build Coastguard Worker }
380*bbecb9d1SAndroid Build Coastguard Worker 
381*bbecb9d1SAndroid Build Coastguard Worker bool
vkr_ring_write_extra(struct vkr_ring * ring,size_t offset,uint32_t val)382*bbecb9d1SAndroid Build Coastguard Worker vkr_ring_write_extra(struct vkr_ring *ring, size_t offset, uint32_t val)
383*bbecb9d1SAndroid Build Coastguard Worker {
384*bbecb9d1SAndroid Build Coastguard Worker    struct vkr_ring_extra *extra = &ring->extra;
385*bbecb9d1SAndroid Build Coastguard Worker 
386*bbecb9d1SAndroid Build Coastguard Worker    if (unlikely(extra->cached_offset != offset || !extra->cached_data)) {
387*bbecb9d1SAndroid Build Coastguard Worker       const struct vkr_region access = VKR_REGION_INIT(offset, sizeof(val));
388*bbecb9d1SAndroid Build Coastguard Worker       if (!vkr_region_is_valid(&access) || !vkr_region_is_within(&access, &extra->region))
389*bbecb9d1SAndroid Build Coastguard Worker          return false;
390*bbecb9d1SAndroid Build Coastguard Worker 
391*bbecb9d1SAndroid Build Coastguard Worker       /* Mesa always sets offset to 0 and the cache hit rate will be 100% */
392*bbecb9d1SAndroid Build Coastguard Worker       extra->cached_offset = offset;
393*bbecb9d1SAndroid Build Coastguard Worker       extra->cached_data = get_resource_pointer(ring->attachment, extra->base_iov_index,
394*bbecb9d1SAndroid Build Coastguard Worker                                                 extra->base_iov_offset + offset);
395*bbecb9d1SAndroid Build Coastguard Worker    }
396*bbecb9d1SAndroid Build Coastguard Worker 
397*bbecb9d1SAndroid Build Coastguard Worker    atomic_store_explicit(extra->cached_data, val, memory_order_release);
398*bbecb9d1SAndroid Build Coastguard Worker 
399*bbecb9d1SAndroid Build Coastguard Worker    {
400*bbecb9d1SAndroid Build Coastguard Worker       TRACE_SCOPE("ring extra done");
401*bbecb9d1SAndroid Build Coastguard Worker    }
402*bbecb9d1SAndroid Build Coastguard Worker 
403*bbecb9d1SAndroid Build Coastguard Worker    return true;
404*bbecb9d1SAndroid Build Coastguard Worker }
405