2 * Copyright © 2008 Intel Corporation
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:
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
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
24 * Eric Anholt <eric@anholt.net>
30 * \brief Support for GL_ARB_sync and EGL_KHR_fence_sync.
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.
41 #include <libsync.h> /* Requires Android or libdrm-2.4.72 */
43 #include "main/imports.h"
45 #include "brw_context.h"
46 #include "intel_batchbuffer.h"
49 struct brw_context
*brw
;
52 /** The fence waits for completion of brw_fence::batch_bo. */
53 BRW_FENCE_TYPE_BO_WAIT
,
55 /** The fence waits for brw_fence::sync_fd to signal. */
56 BRW_FENCE_TYPE_SYNC_FD
,
60 struct brw_bo
*batch_bo
;
62 /* This struct owns the fd. */
71 struct gl_sync_object gl
;
72 struct brw_fence fence
;
76 brw_fence_init(struct brw_context
*brw
, struct brw_fence
*fence
,
77 enum brw_fence_type type
)
81 mtx_init(&fence
->mutex
, mtx_plain
);
84 case BRW_FENCE_TYPE_BO_WAIT
:
85 fence
->batch_bo
= NULL
;
87 case BRW_FENCE_TYPE_SYNC_FD
:
94 brw_fence_finish(struct brw_fence
*fence
)
96 switch (fence
->type
) {
97 case BRW_FENCE_TYPE_BO_WAIT
:
99 brw_bo_unreference(fence
->batch_bo
);
101 case BRW_FENCE_TYPE_SYNC_FD
:
102 if (fence
->sync_fd
!= -1)
103 close(fence
->sync_fd
);
107 mtx_destroy(&fence
->mutex
);
110 static bool MUST_CHECK
111 brw_fence_insert_locked(struct brw_context
*brw
, struct brw_fence
*fence
)
113 __DRIcontext
*driContext
= brw
->driContext
;
114 __DRIdrawable
*driDrawable
= driContext
->driDrawablePriv
;
117 * From KHR_fence_sync:
119 * When the condition of the sync object is satisfied by the fence
120 * command, the sync is signaled by the associated client API context,
121 * causing any eglClientWaitSyncKHR commands (see below) blocking on
122 * <sync> to unblock. The only condition currently supported is
123 * EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR, which is satisfied by
124 * completion of the fence command corresponding to the sync object,
125 * and all preceding commands in the associated client API context's
126 * command stream. The sync object will not be signaled until all
127 * effects from these commands on the client API's internal and
128 * framebuffer state are fully realized. No other state is affected by
129 * execution of the fence command.
131 * Note the emphasis there on ensuring that the framebuffer is fully
132 * realised before the fence is signaled. We cannot just flush the batch,
133 * but must also resolve the drawable first. The importance of this is,
134 * for example, in creating a fence for a frame to be passed to a
135 * remote compositor. Without us flushing the drawable explicitly, the
136 * resolve will be in a following batch (when the client finally calls
137 * SwapBuffers, or triggers a resolve via some other path) and so the
138 * compositor may read the incomplete framebuffer instead.
141 intel_resolve_for_dri2_flush(brw
, driDrawable
);
142 brw_emit_mi_flush(brw
);
144 switch (fence
->type
) {
145 case BRW_FENCE_TYPE_BO_WAIT
:
146 assert(!fence
->batch_bo
);
147 assert(!fence
->signalled
);
149 fence
->batch_bo
= brw
->batch
.batch
.bo
;
150 brw_bo_reference(fence
->batch_bo
);
152 if (intel_batchbuffer_flush(brw
) < 0) {
153 brw_bo_unreference(fence
->batch_bo
);
154 fence
->batch_bo
= NULL
;
158 case BRW_FENCE_TYPE_SYNC_FD
:
159 assert(!fence
->signalled
);
161 if (fence
->sync_fd
== -1) {
162 /* Create an out-fence that signals after all pending commands
165 if (intel_batchbuffer_flush_fence(brw
, -1, &fence
->sync_fd
) < 0)
167 assert(fence
->sync_fd
!= -1);
169 /* Wait on the in-fence before executing any subsequently submitted
172 if (intel_batchbuffer_flush(brw
) < 0)
175 /* Emit a dummy batch just for the fence. */
176 brw_emit_mi_flush(brw
);
177 if (intel_batchbuffer_flush_fence(brw
, fence
->sync_fd
, NULL
) < 0)
186 static bool MUST_CHECK
187 brw_fence_insert(struct brw_context
*brw
, struct brw_fence
*fence
)
191 mtx_lock(&fence
->mutex
);
192 ret
= brw_fence_insert_locked(brw
, fence
);
193 mtx_unlock(&fence
->mutex
);
199 brw_fence_has_completed_locked(struct brw_fence
*fence
)
201 if (fence
->signalled
)
204 switch (fence
->type
) {
205 case BRW_FENCE_TYPE_BO_WAIT
:
206 if (!fence
->batch_bo
) {
207 /* There may be no batch if intel_batchbuffer_flush() failed. */
211 if (brw_bo_busy(fence
->batch_bo
))
214 brw_bo_unreference(fence
->batch_bo
);
215 fence
->batch_bo
= NULL
;
216 fence
->signalled
= true;
220 case BRW_FENCE_TYPE_SYNC_FD
:
221 assert(fence
->sync_fd
!= -1);
223 if (sync_wait(fence
->sync_fd
, 0) == -1)
226 fence
->signalled
= true;
235 brw_fence_has_completed(struct brw_fence
*fence
)
239 mtx_lock(&fence
->mutex
);
240 ret
= brw_fence_has_completed_locked(fence
);
241 mtx_unlock(&fence
->mutex
);
247 brw_fence_client_wait_locked(struct brw_context
*brw
, struct brw_fence
*fence
,
252 if (fence
->signalled
)
255 switch (fence
->type
) {
256 case BRW_FENCE_TYPE_BO_WAIT
:
257 if (!fence
->batch_bo
) {
258 /* There may be no batch if intel_batchbuffer_flush() failed. */
262 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and returns
263 * immediately for timeouts <= 0. The best we can do is to clamp the
264 * timeout to INT64_MAX. This limits the maximum timeout from 584 years to
265 * 292 years - likely not a big deal.
267 if (timeout
> INT64_MAX
)
270 if (brw_bo_wait(fence
->batch_bo
, timeout
) != 0)
273 fence
->signalled
= true;
274 brw_bo_unreference(fence
->batch_bo
);
275 fence
->batch_bo
= NULL
;
278 case BRW_FENCE_TYPE_SYNC_FD
:
279 if (fence
->sync_fd
== -1)
282 if (timeout
> INT32_MAX
)
285 timeout_i32
= timeout
;
287 if (sync_wait(fence
->sync_fd
, timeout_i32
) == -1)
290 fence
->signalled
= true;
294 assert(!"bad enum brw_fence_type");
299 * Return true if the function successfully signals or has already signalled.
300 * (This matches the behavior expected from __DRI2fence::client_wait_sync).
303 brw_fence_client_wait(struct brw_context
*brw
, struct brw_fence
*fence
,
308 mtx_lock(&fence
->mutex
);
309 ret
= brw_fence_client_wait_locked(brw
, fence
, timeout
);
310 mtx_unlock(&fence
->mutex
);
316 brw_fence_server_wait(struct brw_context
*brw
, struct brw_fence
*fence
)
318 switch (fence
->type
) {
319 case BRW_FENCE_TYPE_BO_WAIT
:
320 /* We have nothing to do for WaitSync. Our GL command stream is sequential,
321 * so given that the sync object has already flushed the batchbuffer, any
322 * batchbuffers coming after this waitsync will naturally not occur until
323 * the previous one is done.
326 case BRW_FENCE_TYPE_SYNC_FD
:
327 assert(fence
->sync_fd
!= -1);
329 /* The user wants explicit synchronization, so give them what they want. */
330 if (!brw_fence_insert(brw
, fence
)) {
331 /* FIXME: There exists no way yet to report an error here. If an error
332 * occurs, continue silently and hope for the best.
339 static struct gl_sync_object
*
340 brw_gl_new_sync(struct gl_context
*ctx
)
342 struct brw_gl_sync
*sync
;
344 sync
= calloc(1, sizeof(*sync
));
352 brw_gl_delete_sync(struct gl_context
*ctx
, struct gl_sync_object
*_sync
)
354 struct brw_gl_sync
*sync
= (struct brw_gl_sync
*) _sync
;
356 brw_fence_finish(&sync
->fence
);
357 free(sync
->gl
.Label
);
362 brw_gl_fence_sync(struct gl_context
*ctx
, struct gl_sync_object
*_sync
,
363 GLenum condition
, GLbitfield flags
)
365 struct brw_context
*brw
= brw_context(ctx
);
366 struct brw_gl_sync
*sync
= (struct brw_gl_sync
*) _sync
;
368 /* brw_fence_insert_locked() assumes it must do a complete flush */
369 assert(condition
== GL_SYNC_GPU_COMMANDS_COMPLETE
);
371 brw_fence_init(brw
, &sync
->fence
, BRW_FENCE_TYPE_BO_WAIT
);
373 if (!brw_fence_insert_locked(brw
, &sync
->fence
)) {
374 /* FIXME: There exists no way to report a GL error here. If an error
375 * occurs, continue silently and hope for the best.
381 brw_gl_client_wait_sync(struct gl_context
*ctx
, struct gl_sync_object
*_sync
,
382 GLbitfield flags
, GLuint64 timeout
)
384 struct brw_context
*brw
= brw_context(ctx
);
385 struct brw_gl_sync
*sync
= (struct brw_gl_sync
*) _sync
;
387 if (brw_fence_client_wait(brw
, &sync
->fence
, timeout
))
388 sync
->gl
.StatusFlag
= 1;
392 brw_gl_server_wait_sync(struct gl_context
*ctx
, struct gl_sync_object
*_sync
,
393 GLbitfield flags
, GLuint64 timeout
)
395 struct brw_context
*brw
= brw_context(ctx
);
396 struct brw_gl_sync
*sync
= (struct brw_gl_sync
*) _sync
;
398 brw_fence_server_wait(brw
, &sync
->fence
);
402 brw_gl_check_sync(struct gl_context
*ctx
, struct gl_sync_object
*_sync
)
404 struct brw_gl_sync
*sync
= (struct brw_gl_sync
*) _sync
;
406 if (brw_fence_has_completed(&sync
->fence
))
407 sync
->gl
.StatusFlag
= 1;
411 brw_init_syncobj_functions(struct dd_function_table
*functions
)
413 functions
->NewSyncObject
= brw_gl_new_sync
;
414 functions
->DeleteSyncObject
= brw_gl_delete_sync
;
415 functions
->FenceSync
= brw_gl_fence_sync
;
416 functions
->CheckSync
= brw_gl_check_sync
;
417 functions
->ClientWaitSync
= brw_gl_client_wait_sync
;
418 functions
->ServerWaitSync
= brw_gl_server_wait_sync
;
422 brw_dri_create_fence(__DRIcontext
*ctx
)
424 struct brw_context
*brw
= ctx
->driverPrivate
;
425 struct brw_fence
*fence
;
427 fence
= calloc(1, sizeof(*fence
));
431 brw_fence_init(brw
, fence
, BRW_FENCE_TYPE_BO_WAIT
);
433 if (!brw_fence_insert_locked(brw
, fence
)) {
434 brw_fence_finish(fence
);
443 brw_dri_destroy_fence(__DRIscreen
*dri_screen
, void *_fence
)
445 struct brw_fence
*fence
= _fence
;
447 brw_fence_finish(fence
);
452 brw_dri_client_wait_sync(__DRIcontext
*ctx
, void *_fence
, unsigned flags
,
455 struct brw_fence
*fence
= _fence
;
457 return brw_fence_client_wait(fence
->brw
, fence
, timeout
);
461 brw_dri_server_wait_sync(__DRIcontext
*ctx
, void *_fence
, unsigned flags
)
463 struct brw_fence
*fence
= _fence
;
465 /* We might be called here with a NULL fence as a result of WaitSyncKHR
466 * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case.
471 brw_fence_server_wait(fence
->brw
, fence
);
475 brw_dri_get_capabilities(__DRIscreen
*dri_screen
)
477 struct intel_screen
*screen
= dri_screen
->driverPrivate
;
480 if (screen
->has_exec_fence
)
481 caps
|= __DRI_FENCE_CAP_NATIVE_FD
;
487 brw_dri_create_fence_fd(__DRIcontext
*dri_ctx
, int fd
)
489 struct brw_context
*brw
= dri_ctx
->driverPrivate
;
490 struct brw_fence
*fence
;
492 assert(brw
->screen
->has_exec_fence
);
494 fence
= calloc(1, sizeof(*fence
));
498 brw_fence_init(brw
, fence
, BRW_FENCE_TYPE_SYNC_FD
);
501 /* Create an out-fence fd */
502 if (!brw_fence_insert_locked(brw
, fence
))
505 /* Import the sync fd as an in-fence. */
506 fence
->sync_fd
= dup(fd
);
509 assert(fence
->sync_fd
!= -1);
514 brw_fence_finish(fence
);
520 brw_dri_get_fence_fd_locked(struct brw_fence
*fence
)
522 assert(fence
->type
== BRW_FENCE_TYPE_SYNC_FD
);
523 return dup(fence
->sync_fd
);
527 brw_dri_get_fence_fd(__DRIscreen
*dri_screen
, void *_fence
)
529 struct brw_fence
*fence
= _fence
;
532 mtx_lock(&fence
->mutex
);
533 fd
= brw_dri_get_fence_fd_locked(fence
);
534 mtx_unlock(&fence
->mutex
);
539 const __DRI2fenceExtension intelFenceExtension
= {
540 .base
= { __DRI2_FENCE
, 2 },
542 .create_fence
= brw_dri_create_fence
,
543 .destroy_fence
= brw_dri_destroy_fence
,
544 .client_wait_sync
= brw_dri_client_wait_sync
,
545 .server_wait_sync
= brw_dri_server_wait_sync
,
546 .get_fence_from_cl_event
= NULL
,
547 .get_capabilities
= brw_dri_get_capabilities
,
548 .create_fence_fd
= brw_dri_create_fence_fd
,
549 .get_fence_fd
= brw_dri_get_fence_fd
,