xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/asahi/agx_fence.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Based on panfrost/pan_fence.c:
3  *
4  * Copyright 2022 Amazon.com, Inc. or its affiliates.
5  * Copyright 2008 VMware, Inc.
6  * Copyright 2014 Broadcom
7  * Copyright 2018 Alyssa Rosenzweig
8  * Copyright 2019 Collabora, Ltd.
9  * Copyright 2012 Rob Clark
10  * SPDX-License-Identifier: MIT
11  */
12 
13 #include <xf86drm.h>
14 
15 #include "agx_fence.h"
16 #include "agx_state.h"
17 
18 #include "util/libsync.h"
19 #include "util/os_time.h"
20 #include "util/u_inlines.h"
21 
22 void
agx_fence_reference(struct pipe_screen * pscreen,struct pipe_fence_handle ** ptr,struct pipe_fence_handle * fence)23 agx_fence_reference(struct pipe_screen *pscreen, struct pipe_fence_handle **ptr,
24                     struct pipe_fence_handle *fence)
25 {
26    struct agx_device *dev = agx_device(pscreen);
27    struct pipe_fence_handle *old = *ptr;
28 
29    if (pipe_reference(old ? &old->reference : NULL,
30                       fence ? &fence->reference : NULL)) {
31       drmSyncobjDestroy(dev->fd, old->syncobj);
32       free(old);
33    }
34 
35    *ptr = fence;
36 }
37 
38 bool
agx_fence_finish(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_fence_handle * fence,uint64_t timeout)39 agx_fence_finish(struct pipe_screen *pscreen, struct pipe_context *ctx,
40                  struct pipe_fence_handle *fence, uint64_t timeout)
41 {
42    struct agx_device *dev = agx_device(pscreen);
43    int ret;
44 
45    if (fence->signaled)
46       return true;
47 
48    uint64_t abs_timeout = os_time_get_absolute_timeout(timeout);
49    if (abs_timeout == OS_TIMEOUT_INFINITE)
50       abs_timeout = INT64_MAX;
51 
52    ret = drmSyncobjWait(dev->fd, &fence->syncobj, 1, abs_timeout,
53                         DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, NULL);
54 
55    assert(ret >= 0 || ret == -ETIME);
56    fence->signaled = (ret >= 0);
57    return fence->signaled;
58 }
59 
60 int
agx_fence_get_fd(struct pipe_screen * screen,struct pipe_fence_handle * f)61 agx_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *f)
62 {
63    struct agx_device *dev = agx_device(screen);
64    int fd = -1;
65 
66    int ret = drmSyncobjExportSyncFile(dev->fd, f->syncobj, &fd);
67    assert(ret >= 0);
68    assert(fd >= 0);
69 
70    return fd;
71 }
72 
73 struct pipe_fence_handle *
agx_fence_from_fd(struct agx_context * ctx,int fd,enum pipe_fd_type type)74 agx_fence_from_fd(struct agx_context *ctx, int fd, enum pipe_fd_type type)
75 {
76    struct agx_device *dev = agx_device(ctx->base.screen);
77    int ret;
78 
79    struct pipe_fence_handle *f = calloc(1, sizeof(*f));
80    if (!f)
81       return NULL;
82 
83    if (type == PIPE_FD_TYPE_NATIVE_SYNC) {
84       ret = drmSyncobjCreate(dev->fd, 0, &f->syncobj);
85       if (ret) {
86          agx_msg("create syncobj failed\n");
87          goto err_free_fence;
88       }
89 
90       ret = drmSyncobjImportSyncFile(dev->fd, f->syncobj, fd);
91       if (ret) {
92          agx_msg("import syncfile failed\n");
93          goto err_destroy_syncobj;
94       }
95    } else {
96       assert(type == PIPE_FD_TYPE_SYNCOBJ);
97       ret = drmSyncobjFDToHandle(dev->fd, fd, &f->syncobj);
98       if (ret) {
99          agx_msg("import syncobj FD failed\n");
100          goto err_free_fence;
101       }
102    }
103 
104    pipe_reference_init(&f->reference, 1);
105 
106    return f;
107 
108 err_destroy_syncobj:
109    drmSyncobjDestroy(dev->fd, f->syncobj);
110 err_free_fence:
111    free(f);
112    return NULL;
113 }
114 
115 struct pipe_fence_handle *
agx_fence_create(struct agx_context * ctx)116 agx_fence_create(struct agx_context *ctx)
117 {
118    struct agx_device *dev = agx_device(ctx->base.screen);
119    int fd = -1, ret;
120 
121    /* Snapshot the last rendering out fence. We'd rather have another
122     * syncobj instead of a sync file, but this is all we get.
123     * (HandleToFD/FDToHandle just gives you another syncobj ID for the
124     * same syncobj).
125     */
126    ret = drmSyncobjExportSyncFile(dev->fd, ctx->syncobj, &fd);
127    assert(ret >= 0 && fd != -1 && "export failed");
128    if (ret || fd == -1) {
129       agx_msg("export failed\n");
130       return NULL;
131    }
132 
133    struct pipe_fence_handle *f =
134       agx_fence_from_fd(ctx, fd, PIPE_FD_TYPE_NATIVE_SYNC);
135 
136    close(fd);
137 
138    return f;
139 }
140 
141 void
agx_create_fence_fd(struct pipe_context * pctx,struct pipe_fence_handle ** pfence,int fd,enum pipe_fd_type type)142 agx_create_fence_fd(struct pipe_context *pctx,
143                     struct pipe_fence_handle **pfence, int fd,
144                     enum pipe_fd_type type)
145 {
146    *pfence = agx_fence_from_fd(agx_context(pctx), fd, type);
147 }
148 
149 void
agx_fence_server_sync(struct pipe_context * pctx,struct pipe_fence_handle * f)150 agx_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *f)
151 {
152    struct agx_device *dev = agx_device(pctx->screen);
153    struct agx_context *ctx = agx_context(pctx);
154    int fd = -1, ret;
155 
156    ret = drmSyncobjExportSyncFile(dev->fd, f->syncobj, &fd);
157    assert(!ret);
158 
159    sync_accumulate("asahi", &ctx->in_sync_fd, fd);
160    close(fd);
161 }
162