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