xref: /aosp_15_r20/external/virglrenderer/src/drm/drm_fence.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker  * Copyright 2022 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 <poll.h>
7*bbecb9d1SAndroid Build Coastguard Worker #include <string.h>
8*bbecb9d1SAndroid Build Coastguard Worker 
9*bbecb9d1SAndroid Build Coastguard Worker #include "virgl_context.h"
10*bbecb9d1SAndroid Build Coastguard Worker #include "virgl_util.h"
11*bbecb9d1SAndroid Build Coastguard Worker 
12*bbecb9d1SAndroid Build Coastguard Worker #include "util/os_file.h"
13*bbecb9d1SAndroid Build Coastguard Worker #include "util/u_atomic.h"
14*bbecb9d1SAndroid Build Coastguard Worker #include "util/u_thread.h"
15*bbecb9d1SAndroid Build Coastguard Worker 
16*bbecb9d1SAndroid Build Coastguard Worker #include "drm_fence.h"
17*bbecb9d1SAndroid Build Coastguard Worker #include "drm_util.h"
18*bbecb9d1SAndroid Build Coastguard Worker 
19*bbecb9d1SAndroid Build Coastguard Worker /**
20*bbecb9d1SAndroid Build Coastguard Worker  * Tracking for a single fence on a timeline
21*bbecb9d1SAndroid Build Coastguard Worker  */
22*bbecb9d1SAndroid Build Coastguard Worker struct drm_fence {
23*bbecb9d1SAndroid Build Coastguard Worker    int fd;
24*bbecb9d1SAndroid Build Coastguard Worker    uint32_t flags;
25*bbecb9d1SAndroid Build Coastguard Worker    uint64_t fence_id;
26*bbecb9d1SAndroid Build Coastguard Worker    struct list_head node;
27*bbecb9d1SAndroid Build Coastguard Worker };
28*bbecb9d1SAndroid Build Coastguard Worker 
29*bbecb9d1SAndroid Build Coastguard Worker static void
drm_fence_destroy(struct drm_fence * fence)30*bbecb9d1SAndroid Build Coastguard Worker drm_fence_destroy(struct drm_fence *fence)
31*bbecb9d1SAndroid Build Coastguard Worker {
32*bbecb9d1SAndroid Build Coastguard Worker    close(fence->fd);
33*bbecb9d1SAndroid Build Coastguard Worker    list_del(&fence->node);
34*bbecb9d1SAndroid Build Coastguard Worker    free(fence);
35*bbecb9d1SAndroid Build Coastguard Worker }
36*bbecb9d1SAndroid Build Coastguard Worker 
37*bbecb9d1SAndroid Build Coastguard Worker static struct drm_fence *
drm_fence_create(int fd,uint32_t flags,uint64_t fence_id)38*bbecb9d1SAndroid Build Coastguard Worker drm_fence_create(int fd, uint32_t flags, uint64_t fence_id)
39*bbecb9d1SAndroid Build Coastguard Worker {
40*bbecb9d1SAndroid Build Coastguard Worker    struct drm_fence *fence = calloc(1, sizeof(*fence));
41*bbecb9d1SAndroid Build Coastguard Worker 
42*bbecb9d1SAndroid Build Coastguard Worker    if (!fence)
43*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
44*bbecb9d1SAndroid Build Coastguard Worker 
45*bbecb9d1SAndroid Build Coastguard Worker    fence->fd = os_dupfd_cloexec(fd);
46*bbecb9d1SAndroid Build Coastguard Worker 
47*bbecb9d1SAndroid Build Coastguard Worker    if (fence->fd < 0) {
48*bbecb9d1SAndroid Build Coastguard Worker       free(fence);
49*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
50*bbecb9d1SAndroid Build Coastguard Worker    }
51*bbecb9d1SAndroid Build Coastguard Worker 
52*bbecb9d1SAndroid Build Coastguard Worker    fence->flags = flags;
53*bbecb9d1SAndroid Build Coastguard Worker    fence->fence_id = fence_id;
54*bbecb9d1SAndroid Build Coastguard Worker 
55*bbecb9d1SAndroid Build Coastguard Worker    return fence;
56*bbecb9d1SAndroid Build Coastguard Worker }
57*bbecb9d1SAndroid Build Coastguard Worker 
58*bbecb9d1SAndroid Build Coastguard Worker static int
thread_sync(void * arg)59*bbecb9d1SAndroid Build Coastguard Worker thread_sync(void *arg)
60*bbecb9d1SAndroid Build Coastguard Worker {
61*bbecb9d1SAndroid Build Coastguard Worker    struct drm_timeline *timeline = arg;
62*bbecb9d1SAndroid Build Coastguard Worker 
63*bbecb9d1SAndroid Build Coastguard Worker    u_thread_setname(timeline->name);
64*bbecb9d1SAndroid Build Coastguard Worker 
65*bbecb9d1SAndroid Build Coastguard Worker    mtx_lock(&timeline->fence_mutex);
66*bbecb9d1SAndroid Build Coastguard Worker    while (!timeline->stop_sync_thread) {
67*bbecb9d1SAndroid Build Coastguard Worker       if (list_is_empty(&timeline->pending_fences)) {
68*bbecb9d1SAndroid Build Coastguard Worker          if (cnd_wait(&timeline->fence_cond, &timeline->fence_mutex))
69*bbecb9d1SAndroid Build Coastguard Worker             drm_log("error waiting on fence condition");
70*bbecb9d1SAndroid Build Coastguard Worker          continue;
71*bbecb9d1SAndroid Build Coastguard Worker       }
72*bbecb9d1SAndroid Build Coastguard Worker 
73*bbecb9d1SAndroid Build Coastguard Worker       struct drm_fence *fence =
74*bbecb9d1SAndroid Build Coastguard Worker          list_first_entry(&timeline->pending_fences, struct drm_fence, node);
75*bbecb9d1SAndroid Build Coastguard Worker       int ret;
76*bbecb9d1SAndroid Build Coastguard Worker 
77*bbecb9d1SAndroid Build Coastguard Worker       mtx_unlock(&timeline->fence_mutex);
78*bbecb9d1SAndroid Build Coastguard Worker       ret = poll(&(struct pollfd){fence->fd, POLLIN}, 1, -1); /* wait forever */
79*bbecb9d1SAndroid Build Coastguard Worker       mtx_lock(&timeline->fence_mutex);
80*bbecb9d1SAndroid Build Coastguard Worker 
81*bbecb9d1SAndroid Build Coastguard Worker       if (ret == 1) {
82*bbecb9d1SAndroid Build Coastguard Worker          drm_dbg("fence signaled: %p (%" PRIu64 ")", fence, fence->fence_id);
83*bbecb9d1SAndroid Build Coastguard Worker          timeline->vctx->fence_retire(timeline->vctx, timeline->ring_idx,
84*bbecb9d1SAndroid Build Coastguard Worker                                       fence->fence_id);
85*bbecb9d1SAndroid Build Coastguard Worker          write_eventfd(timeline->eventfd, 1);
86*bbecb9d1SAndroid Build Coastguard Worker          drm_fence_destroy(fence);
87*bbecb9d1SAndroid Build Coastguard Worker       } else if (ret != 0) {
88*bbecb9d1SAndroid Build Coastguard Worker          drm_log("poll failed: %s", strerror(errno));
89*bbecb9d1SAndroid Build Coastguard Worker       }
90*bbecb9d1SAndroid Build Coastguard Worker    }
91*bbecb9d1SAndroid Build Coastguard Worker    mtx_unlock(&timeline->fence_mutex);
92*bbecb9d1SAndroid Build Coastguard Worker 
93*bbecb9d1SAndroid Build Coastguard Worker    return 0;
94*bbecb9d1SAndroid Build Coastguard Worker }
95*bbecb9d1SAndroid Build Coastguard Worker 
96*bbecb9d1SAndroid Build Coastguard Worker void
drm_timeline_init(struct drm_timeline * timeline,struct virgl_context * vctx,const char * name,int eventfd,int ring_idx)97*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_init(struct drm_timeline *timeline, struct virgl_context *vctx,
98*bbecb9d1SAndroid Build Coastguard Worker                   const char *name, int eventfd, int ring_idx)
99*bbecb9d1SAndroid Build Coastguard Worker {
100*bbecb9d1SAndroid Build Coastguard Worker    timeline->vctx = vctx;
101*bbecb9d1SAndroid Build Coastguard Worker    timeline->name = name;
102*bbecb9d1SAndroid Build Coastguard Worker    timeline->eventfd = eventfd;
103*bbecb9d1SAndroid Build Coastguard Worker    timeline->ring_idx = ring_idx;
104*bbecb9d1SAndroid Build Coastguard Worker 
105*bbecb9d1SAndroid Build Coastguard Worker    timeline->last_fence_fd = -1;
106*bbecb9d1SAndroid Build Coastguard Worker 
107*bbecb9d1SAndroid Build Coastguard Worker    list_inithead(&timeline->pending_fences);
108*bbecb9d1SAndroid Build Coastguard Worker 
109*bbecb9d1SAndroid Build Coastguard Worker    mtx_init(&timeline->fence_mutex, mtx_plain);
110*bbecb9d1SAndroid Build Coastguard Worker    cnd_init(&timeline->fence_cond);
111*bbecb9d1SAndroid Build Coastguard Worker 
112*bbecb9d1SAndroid Build Coastguard Worker    timeline->sync_thread = u_thread_create(thread_sync, timeline);
113*bbecb9d1SAndroid Build Coastguard Worker }
114*bbecb9d1SAndroid Build Coastguard Worker 
115*bbecb9d1SAndroid Build Coastguard Worker void
drm_timeline_fini(struct drm_timeline * timeline)116*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_fini(struct drm_timeline *timeline)
117*bbecb9d1SAndroid Build Coastguard Worker {
118*bbecb9d1SAndroid Build Coastguard Worker    /* signal thread_sync to shutdown: */
119*bbecb9d1SAndroid Build Coastguard Worker    mtx_lock(&timeline->fence_mutex);
120*bbecb9d1SAndroid Build Coastguard Worker    timeline->stop_sync_thread = true;
121*bbecb9d1SAndroid Build Coastguard Worker    cnd_signal(&timeline->fence_cond);
122*bbecb9d1SAndroid Build Coastguard Worker    mtx_unlock(&timeline->fence_mutex);
123*bbecb9d1SAndroid Build Coastguard Worker 
124*bbecb9d1SAndroid Build Coastguard Worker    /* wait for thread_sync to exit: */
125*bbecb9d1SAndroid Build Coastguard Worker    thrd_join(timeline->sync_thread, NULL);
126*bbecb9d1SAndroid Build Coastguard Worker 
127*bbecb9d1SAndroid Build Coastguard Worker    if (timeline->last_fence_fd != -1)
128*bbecb9d1SAndroid Build Coastguard Worker       close(timeline->last_fence_fd);
129*bbecb9d1SAndroid Build Coastguard Worker 
130*bbecb9d1SAndroid Build Coastguard Worker    /* cleanup remaining fences: */
131*bbecb9d1SAndroid Build Coastguard Worker    list_for_each_entry_safe (struct drm_fence, fence, &timeline->pending_fences, node) {
132*bbecb9d1SAndroid Build Coastguard Worker       drm_fence_destroy(fence);
133*bbecb9d1SAndroid Build Coastguard Worker    }
134*bbecb9d1SAndroid Build Coastguard Worker 
135*bbecb9d1SAndroid Build Coastguard Worker    cnd_destroy(&timeline->fence_cond);
136*bbecb9d1SAndroid Build Coastguard Worker    mtx_destroy(&timeline->fence_mutex);
137*bbecb9d1SAndroid Build Coastguard Worker }
138*bbecb9d1SAndroid Build Coastguard Worker 
139*bbecb9d1SAndroid Build Coastguard Worker int
drm_timeline_submit_fence(struct drm_timeline * timeline,uint32_t flags,uint64_t fence_id)140*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_submit_fence(struct drm_timeline *timeline, uint32_t flags,
141*bbecb9d1SAndroid Build Coastguard Worker                           uint64_t fence_id)
142*bbecb9d1SAndroid Build Coastguard Worker {
143*bbecb9d1SAndroid Build Coastguard Worker    if (timeline->last_fence_fd == -1)
144*bbecb9d1SAndroid Build Coastguard Worker       return -EINVAL;
145*bbecb9d1SAndroid Build Coastguard Worker 
146*bbecb9d1SAndroid Build Coastguard Worker    struct drm_fence *fence =
147*bbecb9d1SAndroid Build Coastguard Worker       drm_fence_create(timeline->last_fence_fd, flags, fence_id);
148*bbecb9d1SAndroid Build Coastguard Worker 
149*bbecb9d1SAndroid Build Coastguard Worker    if (!fence)
150*bbecb9d1SAndroid Build Coastguard Worker       return -ENOMEM;
151*bbecb9d1SAndroid Build Coastguard Worker 
152*bbecb9d1SAndroid Build Coastguard Worker    drm_dbg("fence: %p (%" PRIu64 ")", fence, fence->fence_id);
153*bbecb9d1SAndroid Build Coastguard Worker 
154*bbecb9d1SAndroid Build Coastguard Worker    mtx_lock(&timeline->fence_mutex);
155*bbecb9d1SAndroid Build Coastguard Worker    list_addtail(&fence->node, &timeline->pending_fences);
156*bbecb9d1SAndroid Build Coastguard Worker    cnd_signal(&timeline->fence_cond);
157*bbecb9d1SAndroid Build Coastguard Worker    mtx_unlock(&timeline->fence_mutex);
158*bbecb9d1SAndroid Build Coastguard Worker 
159*bbecb9d1SAndroid Build Coastguard Worker    return 0;
160*bbecb9d1SAndroid Build Coastguard Worker }
161*bbecb9d1SAndroid Build Coastguard Worker 
162*bbecb9d1SAndroid Build Coastguard Worker /* takes ownership of the fd */
163*bbecb9d1SAndroid Build Coastguard Worker void
drm_timeline_set_last_fence_fd(struct drm_timeline * timeline,int fd)164*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_set_last_fence_fd(struct drm_timeline *timeline, int fd)
165*bbecb9d1SAndroid Build Coastguard Worker {
166*bbecb9d1SAndroid Build Coastguard Worker    if (timeline->last_fence_fd != -1)
167*bbecb9d1SAndroid Build Coastguard Worker       close(timeline->last_fence_fd);
168*bbecb9d1SAndroid Build Coastguard Worker    timeline->last_fence_fd = fd;
169*bbecb9d1SAndroid Build Coastguard Worker }
170