i965/sync: Rename brw_fence_insert()
[mesa.git] / src / mesa / drivers / dri / i965 / brw_sync.c
1 /*
2 * Copyright © 2008 Intel Corporation
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28 /**
29 * \file
30 * \brief Support for GL_ARB_sync and EGL_KHR_fence_sync.
31 *
32 * GL_ARB_sync is implemented by flushing the current batchbuffer and keeping a
33 * reference on it. We can then check for completion or wait for completion
34 * using the normal buffer object mechanisms. This does mean that if an
35 * application is using many sync objects, it will emit small batchbuffers
36 * which may end up being a significant overhead. In other tests of removing
37 * gratuitous batchbuffer syncs in Mesa, it hasn't appeared to be a significant
38 * performance bottleneck, though.
39 */
40
41 #include "main/imports.h"
42
43 #include "brw_context.h"
44 #include "intel_batchbuffer.h"
45
46 struct brw_fence {
47 struct brw_context *brw;
48
49 enum brw_fence_type {
50 BRW_FENCE_TYPE_BO_WAIT,
51 } type;
52
53 /** The fence waits for completion of this batch. */
54 drm_intel_bo *batch_bo;
55
56 mtx_t mutex;
57 bool signalled;
58 };
59
60 struct brw_gl_sync {
61 struct gl_sync_object gl;
62 struct brw_fence fence;
63 };
64
65 static void
66 brw_fence_init(struct brw_context *brw, struct brw_fence *fence,
67 enum brw_fence_type type)
68 {
69 fence->brw = brw;
70 fence->type = type;
71 mtx_init(&fence->mutex, mtx_plain);
72
73 switch (type) {
74 case BRW_FENCE_TYPE_BO_WAIT:
75 fence->batch_bo = NULL;
76 break;
77 }
78 }
79
80 static void
81 brw_fence_finish(struct brw_fence *fence)
82 {
83 switch (fence->type) {
84 case BRW_FENCE_TYPE_BO_WAIT:
85 if (fence->batch_bo)
86 drm_intel_bo_unreference(fence->batch_bo);
87 break;
88 }
89
90 mtx_destroy(&fence->mutex);
91 }
92
93 static bool MUST_CHECK
94 brw_fence_insert_locked(struct brw_context *brw, struct brw_fence *fence)
95 {
96 brw_emit_mi_flush(brw);
97
98 switch (fence->type) {
99 case BRW_FENCE_TYPE_BO_WAIT:
100 assert(!fence->batch_bo);
101 assert(!fence->signalled);
102
103 fence->batch_bo = brw->batch.bo;
104 drm_intel_bo_reference(fence->batch_bo);
105
106 if (intel_batchbuffer_flush(brw) < 0) {
107 drm_intel_bo_unreference(fence->batch_bo);
108 fence->batch_bo = NULL;
109 return false;
110 }
111 break;
112 }
113
114 return true;
115 }
116
117 static bool
118 brw_fence_has_completed_locked(struct brw_fence *fence)
119 {
120 if (fence->signalled)
121 return true;
122
123 switch (fence->type) {
124 case BRW_FENCE_TYPE_BO_WAIT:
125 if (!fence->batch_bo) {
126 /* There may be no batch if intel_batchbuffer_flush() failed. */
127 return false;
128 }
129
130 if (drm_intel_bo_busy(fence->batch_bo))
131 return false;
132
133 drm_intel_bo_unreference(fence->batch_bo);
134 fence->batch_bo = NULL;
135 fence->signalled = true;
136
137 return true;
138 }
139
140 return false;
141 }
142
143 static bool
144 brw_fence_has_completed(struct brw_fence *fence)
145 {
146 bool ret;
147
148 mtx_lock(&fence->mutex);
149 ret = brw_fence_has_completed_locked(fence);
150 mtx_unlock(&fence->mutex);
151
152 return ret;
153 }
154
155 static bool
156 brw_fence_client_wait_locked(struct brw_context *brw, struct brw_fence *fence,
157 uint64_t timeout)
158 {
159 if (fence->signalled)
160 return true;
161
162 switch (fence->type) {
163 case BRW_FENCE_TYPE_BO_WAIT:
164 if (!fence->batch_bo) {
165 /* There may be no batch if intel_batchbuffer_flush() failed. */
166 return false;
167 }
168
169 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and returns
170 * immediately for timeouts <= 0. The best we can do is to clamp the
171 * timeout to INT64_MAX. This limits the maximum timeout from 584 years to
172 * 292 years - likely not a big deal.
173 */
174 if (timeout > INT64_MAX)
175 timeout = INT64_MAX;
176
177 if (drm_intel_gem_bo_wait(fence->batch_bo, timeout) != 0)
178 return false;
179
180 fence->signalled = true;
181 drm_intel_bo_unreference(fence->batch_bo);
182 fence->batch_bo = NULL;
183
184 return true;
185 }
186
187 assert(!"bad enum brw_fence_type");
188 return false;
189 }
190
191 /**
192 * Return true if the function successfully signals or has already signalled.
193 * (This matches the behavior expected from __DRI2fence::client_wait_sync).
194 */
195 static bool
196 brw_fence_client_wait(struct brw_context *brw, struct brw_fence *fence,
197 uint64_t timeout)
198 {
199 bool ret;
200
201 mtx_lock(&fence->mutex);
202 ret = brw_fence_client_wait_locked(brw, fence, timeout);
203 mtx_unlock(&fence->mutex);
204
205 return ret;
206 }
207
208 static void
209 brw_fence_server_wait(struct brw_context *brw, struct brw_fence *fence)
210 {
211 switch (fence->type) {
212 case BRW_FENCE_TYPE_BO_WAIT:
213 /* We have nothing to do for WaitSync. Our GL command stream is sequential,
214 * so given that the sync object has already flushed the batchbuffer, any
215 * batchbuffers coming after this waitsync will naturally not occur until
216 * the previous one is done.
217 */
218 break;
219 }
220 }
221
222 static struct gl_sync_object *
223 brw_gl_new_sync(struct gl_context *ctx, GLuint id)
224 {
225 struct brw_gl_sync *sync;
226
227 sync = calloc(1, sizeof(*sync));
228 if (!sync)
229 return NULL;
230
231 return &sync->gl;
232 }
233
234 static void
235 brw_gl_delete_sync(struct gl_context *ctx, struct gl_sync_object *_sync)
236 {
237 struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
238
239 brw_fence_finish(&sync->fence);
240 free(sync);
241 }
242
243 static void
244 brw_gl_fence_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
245 GLenum condition, GLbitfield flags)
246 {
247 struct brw_context *brw = brw_context(ctx);
248 struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
249
250 brw_fence_init(brw, &sync->fence, BRW_FENCE_TYPE_BO_WAIT);
251
252 if (!brw_fence_insert_locked(brw, &sync->fence)) {
253 /* FIXME: There exists no way to report a GL error here. If an error
254 * occurs, continue silently and hope for the best.
255 */
256 }
257 }
258
259 static void
260 brw_gl_client_wait_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
261 GLbitfield flags, GLuint64 timeout)
262 {
263 struct brw_context *brw = brw_context(ctx);
264 struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
265
266 if (brw_fence_client_wait(brw, &sync->fence, timeout))
267 sync->gl.StatusFlag = 1;
268 }
269
270 static void
271 brw_gl_server_wait_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
272 GLbitfield flags, GLuint64 timeout)
273 {
274 struct brw_context *brw = brw_context(ctx);
275 struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
276
277 brw_fence_server_wait(brw, &sync->fence);
278 }
279
280 static void
281 brw_gl_check_sync(struct gl_context *ctx, struct gl_sync_object *_sync)
282 {
283 struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
284
285 if (brw_fence_has_completed(&sync->fence))
286 sync->gl.StatusFlag = 1;
287 }
288
289 void
290 brw_init_syncobj_functions(struct dd_function_table *functions)
291 {
292 functions->NewSyncObject = brw_gl_new_sync;
293 functions->DeleteSyncObject = brw_gl_delete_sync;
294 functions->FenceSync = brw_gl_fence_sync;
295 functions->CheckSync = brw_gl_check_sync;
296 functions->ClientWaitSync = brw_gl_client_wait_sync;
297 functions->ServerWaitSync = brw_gl_server_wait_sync;
298 }
299
300 static void *
301 brw_dri_create_fence(__DRIcontext *ctx)
302 {
303 struct brw_context *brw = ctx->driverPrivate;
304 struct brw_fence *fence;
305
306 fence = calloc(1, sizeof(*fence));
307 if (!fence)
308 return NULL;
309
310 brw_fence_init(brw, fence, BRW_FENCE_TYPE_BO_WAIT);
311
312 if (!brw_fence_insert_locked(brw, fence)) {
313 brw_fence_finish(fence);
314 free(fence);
315 return NULL;
316 }
317
318 return fence;
319 }
320
321 static void
322 brw_dri_destroy_fence(__DRIscreen *dri_screen, void *_fence)
323 {
324 struct brw_fence *fence = _fence;
325
326 brw_fence_finish(fence);
327 free(fence);
328 }
329
330 static GLboolean
331 brw_dri_client_wait_sync(__DRIcontext *ctx, void *_fence, unsigned flags,
332 uint64_t timeout)
333 {
334 struct brw_fence *fence = _fence;
335
336 return brw_fence_client_wait(fence->brw, fence, timeout);
337 }
338
339 static void
340 brw_dri_server_wait_sync(__DRIcontext *ctx, void *_fence, unsigned flags)
341 {
342 struct brw_fence *fence = _fence;
343
344 /* We might be called here with a NULL fence as a result of WaitSyncKHR
345 * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case.
346 */
347 if (!fence)
348 return;
349
350 brw_fence_server_wait(fence->brw, fence);
351 }
352
353 const __DRI2fenceExtension intelFenceExtension = {
354 .base = { __DRI2_FENCE, 1 },
355
356 .create_fence = brw_dri_create_fence,
357 .destroy_fence = brw_dri_destroy_fence,
358 .client_wait_sync = brw_dri_client_wait_sync,
359 .server_wait_sync = brw_dri_server_wait_sync,
360 .get_fence_from_cl_event = NULL,
361 };