29ee6627e2d1fb2cfa1d54d5732b977a4751b2c3
[mesa.git] / src / gallium / drivers / freedreno / freedreno_fence.c
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 <libsync.h>
28
29 #include "util/os_file.h"
30 #include "util/u_inlines.h"
31
32 #include "freedreno_fence.h"
33 #include "freedreno_context.h"
34 #include "freedreno_util.h"
35 /* TODO: Use the interface drm/freedreno_drmif.h instead of calling directly */
36 #include <xf86drm.h>
37
38 struct pipe_fence_handle {
39 struct pipe_reference reference;
40 /* fence holds a weak reference to the batch until the batch is flushed,
41 * at which point fd_fence_populate() is called and timestamp and possibly
42 * fence_fd become valid and the week reference is dropped.
43 */
44 struct fd_batch *batch;
45 struct fd_pipe *pipe;
46 struct fd_screen *screen;
47 int fence_fd;
48 uint32_t timestamp;
49 uint32_t syncobj;
50 };
51
52 static void fence_flush(struct pipe_fence_handle *fence)
53 {
54 if (fence->batch)
55 fd_batch_flush(fence->batch);
56 debug_assert(!fence->batch);
57 }
58
59 void fd_fence_populate(struct pipe_fence_handle *fence,
60 uint32_t timestamp, int fence_fd)
61 {
62 if (!fence->batch)
63 return;
64 fence->timestamp = timestamp;
65 fence->fence_fd = fence_fd;
66 fence->batch = NULL;
67 }
68
69 static void fd_fence_destroy(struct pipe_fence_handle *fence)
70 {
71 if (fence->fence_fd != -1)
72 close(fence->fence_fd);
73 if (fence->syncobj)
74 drmSyncobjDestroy(fd_device_fd(fence->screen->dev), fence->syncobj);
75 fd_pipe_del(fence->pipe);
76 FREE(fence);
77 }
78
79 void fd_fence_ref(struct pipe_fence_handle **ptr,
80 struct pipe_fence_handle *pfence)
81 {
82 if (pipe_reference(&(*ptr)->reference, &pfence->reference))
83 fd_fence_destroy(*ptr);
84
85 *ptr = pfence;
86 }
87
88 bool fd_fence_finish(struct pipe_screen *pscreen,
89 struct pipe_context *ctx,
90 struct pipe_fence_handle *fence,
91 uint64_t timeout)
92 {
93 fence_flush(fence);
94
95 if (fence->fence_fd != -1) {
96 int ret = sync_wait(fence->fence_fd, timeout / 1000000);
97 return ret == 0;
98 }
99
100 if (fd_pipe_wait_timeout(fence->pipe, fence->timestamp, timeout))
101 return false;
102
103 return true;
104 }
105
106 static struct pipe_fence_handle * fence_create(struct fd_context *ctx,
107 struct fd_batch *batch, uint32_t timestamp, int fence_fd, int syncobj)
108 {
109 struct pipe_fence_handle *fence;
110
111 fence = CALLOC_STRUCT(pipe_fence_handle);
112 if (!fence)
113 return NULL;
114
115 pipe_reference_init(&fence->reference, 1);
116
117 fence->batch = batch;
118 fence->pipe = fd_pipe_ref(ctx->pipe);
119 fence->screen = ctx->screen;
120 fence->timestamp = timestamp;
121 fence->fence_fd = fence_fd;
122 fence->syncobj = syncobj;
123
124 return fence;
125 }
126
127 void fd_create_fence_fd(struct pipe_context *pctx,
128 struct pipe_fence_handle **pfence, int fd,
129 enum pipe_fd_type type)
130 {
131 struct fd_context *ctx = fd_context(pctx);
132
133 switch (type) {
134 case PIPE_FD_TYPE_NATIVE_SYNC:
135 *pfence = fence_create(fd_context(pctx), NULL, 0, os_dupfd_cloexec(fd), 0);
136 break;
137 case PIPE_FD_TYPE_SYNCOBJ: {
138 int ret;
139 uint32_t syncobj;
140
141 assert(ctx->screen->has_syncobj);
142 ret = drmSyncobjFDToHandle(fd_device_fd(ctx->screen->dev), fd, &syncobj);
143 if (!ret)
144 close(fd);
145
146 *pfence = fence_create(fd_context(pctx), NULL, 0, -1, syncobj);
147 break;
148 }
149 default:
150 unreachable("Unhandled fence type");
151 }
152 }
153
154 void fd_fence_server_sync(struct pipe_context *pctx,
155 struct pipe_fence_handle *fence)
156 {
157 struct fd_context *ctx = fd_context(pctx);
158 struct fd_batch *batch = fd_context_batch(ctx);
159
160 fence_flush(fence);
161
162 /* if not an external fence, then nothing more to do without preemption: */
163 if (fence->fence_fd == -1)
164 return;
165
166 if (sync_accumulate("freedreno", &batch->in_fence_fd, fence->fence_fd)) {
167 /* error */
168 }
169 }
170
171 void fd_fence_server_signal(struct pipe_context *pctx,
172 struct pipe_fence_handle *fence)
173 {
174 struct fd_context *ctx = fd_context(pctx);
175
176 if (fence->syncobj) {
177 drmSyncobjSignal(fd_device_fd(ctx->screen->dev), &fence->syncobj, 1);
178 }
179 }
180
181 int fd_fence_get_fd(struct pipe_screen *pscreen,
182 struct pipe_fence_handle *fence)
183 {
184 fence_flush(fence);
185 return os_dupfd_cloexec(fence->fence_fd);
186 }
187
188 bool fd_fence_is_fd(struct pipe_fence_handle *fence)
189 {
190 return fence->fence_fd != -1;
191 }
192
193 struct pipe_fence_handle * fd_fence_create(struct fd_batch *batch)
194 {
195 return fence_create(batch->ctx, batch, 0, -1, 0);
196 }