• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    /** The fence waits for completion of this batch. */
49    drm_intel_bo *batch_bo;
50 
51    mtx_t mutex;
52    bool signalled;
53 };
54 
55 struct brw_gl_sync {
56    struct gl_sync_object gl;
57    struct brw_fence fence;
58 };
59 
60 static void
brw_fence_init(struct brw_context * brw,struct brw_fence * fence)61 brw_fence_init(struct brw_context *brw, struct brw_fence *fence)
62 {
63    fence->brw = brw;
64    fence->batch_bo = NULL;
65    mtx_init(&fence->mutex, mtx_plain);
66 }
67 
68 static void
brw_fence_finish(struct brw_fence * fence)69 brw_fence_finish(struct brw_fence *fence)
70 {
71    if (fence->batch_bo)
72       drm_intel_bo_unreference(fence->batch_bo);
73 
74    mtx_destroy(&fence->mutex);
75 }
76 
77 static void
brw_fence_insert(struct brw_context * brw,struct brw_fence * fence)78 brw_fence_insert(struct brw_context *brw, struct brw_fence *fence)
79 {
80    assert(!fence->batch_bo);
81    assert(!fence->signalled);
82 
83    brw_emit_mi_flush(brw);
84    fence->batch_bo = brw->batch.bo;
85    drm_intel_bo_reference(fence->batch_bo);
86    intel_batchbuffer_flush(brw);
87 }
88 
89 static bool
brw_fence_has_completed_locked(struct brw_fence * fence)90 brw_fence_has_completed_locked(struct brw_fence *fence)
91 {
92    if (fence->signalled)
93       return true;
94 
95    if (fence->batch_bo && !drm_intel_bo_busy(fence->batch_bo)) {
96       drm_intel_bo_unreference(fence->batch_bo);
97       fence->batch_bo = NULL;
98       fence->signalled = true;
99       return true;
100    }
101 
102    return false;
103 }
104 
105 static bool
brw_fence_has_completed(struct brw_fence * fence)106 brw_fence_has_completed(struct brw_fence *fence)
107 {
108    bool ret;
109 
110    mtx_lock(&fence->mutex);
111    ret = brw_fence_has_completed_locked(fence);
112    mtx_unlock(&fence->mutex);
113 
114    return ret;
115 }
116 
117 static bool
brw_fence_client_wait_locked(struct brw_context * brw,struct brw_fence * fence,uint64_t timeout)118 brw_fence_client_wait_locked(struct brw_context *brw, struct brw_fence *fence,
119                              uint64_t timeout)
120 {
121    if (fence->signalled)
122       return true;
123 
124    assert(fence->batch_bo);
125 
126    /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and returns
127     * immediately for timeouts <= 0.  The best we can do is to clamp the
128     * timeout to INT64_MAX.  This limits the maximum timeout from 584 years to
129     * 292 years - likely not a big deal.
130     */
131    if (timeout > INT64_MAX)
132       timeout = INT64_MAX;
133 
134    if (drm_intel_gem_bo_wait(fence->batch_bo, timeout) != 0)
135       return false;
136 
137    fence->signalled = true;
138    drm_intel_bo_unreference(fence->batch_bo);
139    fence->batch_bo = NULL;
140 
141    return true;
142 }
143 
144 /**
145  * Return true if the function successfully signals or has already signalled.
146  * (This matches the behavior expected from __DRI2fence::client_wait_sync).
147  */
148 static bool
brw_fence_client_wait(struct brw_context * brw,struct brw_fence * fence,uint64_t timeout)149 brw_fence_client_wait(struct brw_context *brw, struct brw_fence *fence,
150                       uint64_t timeout)
151 {
152    bool ret;
153 
154    mtx_lock(&fence->mutex);
155    ret = brw_fence_client_wait_locked(brw, fence, timeout);
156    mtx_unlock(&fence->mutex);
157 
158    return ret;
159 }
160 
161 static void
brw_fence_server_wait(struct brw_context * brw,struct brw_fence * fence)162 brw_fence_server_wait(struct brw_context *brw, struct brw_fence *fence)
163 {
164    /* We have nothing to do for WaitSync.  Our GL command stream is sequential,
165     * so given that the sync object has already flushed the batchbuffer, any
166     * batchbuffers coming after this waitsync will naturally not occur until
167     * the previous one is done.
168     */
169 }
170 
171 static struct gl_sync_object *
brw_gl_new_sync(struct gl_context * ctx,GLuint id)172 brw_gl_new_sync(struct gl_context *ctx, GLuint id)
173 {
174    struct brw_gl_sync *sync;
175 
176    sync = calloc(1, sizeof(*sync));
177    if (!sync)
178       return NULL;
179 
180    return &sync->gl;
181 }
182 
183 static void
brw_gl_delete_sync(struct gl_context * ctx,struct gl_sync_object * _sync)184 brw_gl_delete_sync(struct gl_context *ctx, struct gl_sync_object *_sync)
185 {
186    struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
187 
188    brw_fence_finish(&sync->fence);
189    free(sync);
190 }
191 
192 static void
brw_gl_fence_sync(struct gl_context * ctx,struct gl_sync_object * _sync,GLenum condition,GLbitfield flags)193 brw_gl_fence_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
194                   GLenum condition, GLbitfield flags)
195 {
196    struct brw_context *brw = brw_context(ctx);
197    struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
198 
199    brw_fence_init(brw, &sync->fence);
200    brw_fence_insert(brw, &sync->fence);
201 }
202 
203 static void
brw_gl_client_wait_sync(struct gl_context * ctx,struct gl_sync_object * _sync,GLbitfield flags,GLuint64 timeout)204 brw_gl_client_wait_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
205                         GLbitfield flags, GLuint64 timeout)
206 {
207    struct brw_context *brw = brw_context(ctx);
208    struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
209 
210    if (brw_fence_client_wait(brw, &sync->fence, timeout))
211       sync->gl.StatusFlag = 1;
212 }
213 
214 static void
brw_gl_server_wait_sync(struct gl_context * ctx,struct gl_sync_object * _sync,GLbitfield flags,GLuint64 timeout)215 brw_gl_server_wait_sync(struct gl_context *ctx, struct gl_sync_object *_sync,
216                           GLbitfield flags, GLuint64 timeout)
217 {
218    struct brw_context *brw = brw_context(ctx);
219    struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
220 
221    brw_fence_server_wait(brw, &sync->fence);
222 }
223 
224 static void
brw_gl_check_sync(struct gl_context * ctx,struct gl_sync_object * _sync)225 brw_gl_check_sync(struct gl_context *ctx, struct gl_sync_object *_sync)
226 {
227    struct brw_gl_sync *sync = (struct brw_gl_sync *) _sync;
228 
229    if (brw_fence_has_completed(&sync->fence))
230       sync->gl.StatusFlag = 1;
231 }
232 
233 void
brw_init_syncobj_functions(struct dd_function_table * functions)234 brw_init_syncobj_functions(struct dd_function_table *functions)
235 {
236    functions->NewSyncObject = brw_gl_new_sync;
237    functions->DeleteSyncObject = brw_gl_delete_sync;
238    functions->FenceSync = brw_gl_fence_sync;
239    functions->CheckSync = brw_gl_check_sync;
240    functions->ClientWaitSync = brw_gl_client_wait_sync;
241    functions->ServerWaitSync = brw_gl_server_wait_sync;
242 }
243 
244 static void *
brw_dri_create_fence(__DRIcontext * ctx)245 brw_dri_create_fence(__DRIcontext *ctx)
246 {
247    struct brw_context *brw = ctx->driverPrivate;
248    struct brw_fence *fence;
249 
250    fence = calloc(1, sizeof(*fence));
251    if (!fence)
252       return NULL;
253 
254    brw_fence_init(brw, fence);
255    brw_fence_insert(brw, fence);
256 
257    return fence;
258 }
259 
260 static void
brw_dri_destroy_fence(__DRIscreen * dri_screen,void * _fence)261 brw_dri_destroy_fence(__DRIscreen *dri_screen, void *_fence)
262 {
263    struct brw_fence *fence = _fence;
264 
265    brw_fence_finish(fence);
266    free(fence);
267 }
268 
269 static GLboolean
brw_dri_client_wait_sync(__DRIcontext * ctx,void * _fence,unsigned flags,uint64_t timeout)270 brw_dri_client_wait_sync(__DRIcontext *ctx, void *_fence, unsigned flags,
271                          uint64_t timeout)
272 {
273    struct brw_fence *fence = _fence;
274 
275    return brw_fence_client_wait(fence->brw, fence, timeout);
276 }
277 
278 static void
brw_dri_server_wait_sync(__DRIcontext * ctx,void * _fence,unsigned flags)279 brw_dri_server_wait_sync(__DRIcontext *ctx, void *_fence, unsigned flags)
280 {
281    struct brw_fence *fence = _fence;
282 
283    /* We might be called here with a NULL fence as a result of WaitSyncKHR
284     * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case.
285     */
286    if (!fence)
287       return;
288 
289    brw_fence_server_wait(fence->brw, fence);
290 }
291 
292 const __DRI2fenceExtension intelFenceExtension = {
293    .base = { __DRI2_FENCE, 1 },
294 
295    .create_fence = brw_dri_create_fence,
296    .destroy_fence = brw_dri_destroy_fence,
297    .client_wait_sync = brw_dri_client_wait_sync,
298    .server_wait_sync = brw_dri_server_wait_sync,
299    .get_fence_from_cl_event = NULL,
300 };
301