1 /*
2 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #include "util/os_file.h"
28 #include "util/u_inlines.h"
29
30 #include "freedreno_fence.h"
31 #include "freedreno_context.h"
32 #include "freedreno_util.h"
33 /* TODO: Use the interface drm/freedreno_drmif.h instead of calling directly */
34 #include <xf86drm.h>
35
36 struct pipe_fence_handle {
37 struct pipe_reference reference;
38 /* fence holds a weak reference to the batch until the batch is flushed,
39 * at which point fd_fence_populate() is called and timestamp and possibly
40 * fence_fd become valid and the week reference is dropped.
41 */
42 struct fd_batch *batch;
43 struct fd_pipe *pipe;
44 struct fd_screen *screen;
45 int fence_fd;
46 uint32_t timestamp;
47 uint32_t syncobj;
48 };
49
fence_flush(struct pipe_fence_handle * fence)50 static void fence_flush(struct pipe_fence_handle *fence)
51 {
52 if (fence->batch)
53 fd_batch_flush(fence->batch);
54 debug_assert(!fence->batch);
55 }
56
fd_fence_populate(struct pipe_fence_handle * fence,uint32_t timestamp,int fence_fd)57 void fd_fence_populate(struct pipe_fence_handle *fence,
58 uint32_t timestamp, int fence_fd)
59 {
60 if (!fence->batch)
61 return;
62 fence->timestamp = timestamp;
63 fence->fence_fd = fence_fd;
64 fence->batch = NULL;
65 }
66
fd_fence_destroy(struct pipe_fence_handle * fence)67 static void fd_fence_destroy(struct pipe_fence_handle *fence)
68 {
69 if (fence->fence_fd != -1)
70 close(fence->fence_fd);
71 if (fence->syncobj)
72 drmSyncobjDestroy(fd_device_fd(fence->screen->dev), fence->syncobj);
73 fd_pipe_del(fence->pipe);
74 FREE(fence);
75 }
76
fd_fence_ref(struct pipe_fence_handle ** ptr,struct pipe_fence_handle * pfence)77 void fd_fence_ref(struct pipe_fence_handle **ptr,
78 struct pipe_fence_handle *pfence)
79 {
80 if (pipe_reference(&(*ptr)->reference, &pfence->reference))
81 fd_fence_destroy(*ptr);
82
83 *ptr = pfence;
84 }
85
fd_fence_finish(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_fence_handle * fence,uint64_t timeout)86 bool fd_fence_finish(struct pipe_screen *pscreen,
87 struct pipe_context *ctx,
88 struct pipe_fence_handle *fence,
89 uint64_t timeout)
90 {
91 fence_flush(fence);
92
93 if (fence->fence_fd != -1) {
94 int ret = sync_wait(fence->fence_fd, timeout / 1000000);
95 return ret == 0;
96 }
97
98 if (fd_pipe_wait_timeout(fence->pipe, fence->timestamp, timeout))
99 return false;
100
101 return true;
102 }
103
fence_create(struct fd_context * ctx,struct fd_batch * batch,uint32_t timestamp,int fence_fd,int syncobj)104 static struct pipe_fence_handle * fence_create(struct fd_context *ctx,
105 struct fd_batch *batch, uint32_t timestamp, int fence_fd, int syncobj)
106 {
107 struct pipe_fence_handle *fence;
108
109 fence = CALLOC_STRUCT(pipe_fence_handle);
110 if (!fence)
111 return NULL;
112
113 pipe_reference_init(&fence->reference, 1);
114
115 fence->batch = batch;
116 fence->pipe = fd_pipe_ref(ctx->pipe);
117 fence->screen = ctx->screen;
118 fence->timestamp = timestamp;
119 fence->fence_fd = fence_fd;
120 fence->syncobj = syncobj;
121
122 return fence;
123 }
124
fd_create_fence_fd(struct pipe_context * pctx,struct pipe_fence_handle ** pfence,int fd,enum pipe_fd_type type)125 void fd_create_fence_fd(struct pipe_context *pctx,
126 struct pipe_fence_handle **pfence, int fd,
127 enum pipe_fd_type type)
128 {
129 struct fd_context *ctx = fd_context(pctx);
130
131 switch (type) {
132 case PIPE_FD_TYPE_NATIVE_SYNC:
133 *pfence = fence_create(fd_context(pctx), NULL, 0, os_dupfd_cloexec(fd), 0);
134 break;
135 case PIPE_FD_TYPE_SYNCOBJ: {
136 int ret;
137 uint32_t syncobj;
138
139 assert(ctx->screen->has_syncobj);
140 ret = drmSyncobjFDToHandle(fd_device_fd(ctx->screen->dev), fd, &syncobj);
141 if (!ret)
142 close(fd);
143
144 *pfence = fence_create(fd_context(pctx), NULL, 0, -1, syncobj);
145 break;
146 }
147 default:
148 unreachable("Unhandled fence type");
149 }
150 }
151
fd_fence_server_sync(struct pipe_context * pctx,struct pipe_fence_handle * fence)152 void fd_fence_server_sync(struct pipe_context *pctx,
153 struct pipe_fence_handle *fence)
154 {
155 struct fd_context *ctx = fd_context(pctx);
156
157 fence_flush(fence);
158
159 /* if not an external fence, then nothing more to do without preemption: */
160 if (fence->fence_fd == -1)
161 return;
162
163 if (sync_accumulate("freedreno", &ctx->in_fence_fd, fence->fence_fd)) {
164 /* error */
165 }
166 }
167
fd_fence_server_signal(struct pipe_context * pctx,struct pipe_fence_handle * fence)168 void fd_fence_server_signal(struct pipe_context *pctx,
169 struct pipe_fence_handle *fence)
170 {
171 struct fd_context *ctx = fd_context(pctx);
172
173 if (fence->syncobj) {
174 drmSyncobjSignal(fd_device_fd(ctx->screen->dev), &fence->syncobj, 1);
175 }
176 }
177
fd_fence_get_fd(struct pipe_screen * pscreen,struct pipe_fence_handle * fence)178 int fd_fence_get_fd(struct pipe_screen *pscreen,
179 struct pipe_fence_handle *fence)
180 {
181 fence_flush(fence);
182 return os_dupfd_cloexec(fence->fence_fd);
183 }
184
fd_fence_is_fd(struct pipe_fence_handle * fence)185 bool fd_fence_is_fd(struct pipe_fence_handle *fence)
186 {
187 return fence->fence_fd != -1;
188 }
189
fd_fence_create(struct fd_batch * batch)190 struct pipe_fence_handle * fd_fence_create(struct fd_batch *batch)
191 {
192 return fence_create(batch->ctx, batch, 0, -1, 0);
193 }
194