2 * Copyright © 2018 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 shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
26 * Fences for driver and IPC serialisation, scheduling and synchronisation.
29 #include "util/u_inlines.h"
31 #include "iris_batch.h"
32 #include "iris_bufmgr.h"
33 #include "iris_context.h"
34 #include "iris_fence.h"
35 #include "iris_screen.h"
38 gem_syncobj_create(int fd
, uint32_t flags
)
40 struct drm_syncobj_create args
= {
44 drm_ioctl(fd
, DRM_IOCTL_SYNCOBJ_CREATE
, &args
);
50 gem_syncobj_destroy(int fd
, uint32_t handle
)
52 struct drm_syncobj_destroy args
= {
56 drm_ioctl(fd
, DRM_IOCTL_SYNCOBJ_DESTROY
, &args
);
60 * Make a new sync-point.
63 iris_create_syncpt(struct iris_screen
*screen
)
65 struct iris_syncpt
*syncpt
= malloc(sizeof(*syncpt
));
70 syncpt
->handle
= gem_syncobj_create(screen
->fd
, 0);
71 assert(syncpt
->handle
);
73 pipe_reference_init(&syncpt
->ref
, 1);
79 iris_syncpt_destroy(struct iris_screen
*screen
, struct iris_syncpt
*syncpt
)
81 gem_syncobj_destroy(screen
->fd
, syncpt
->handle
);
86 * Add a sync-point to the batch, with the given flags.
88 * \p flags One of I915_EXEC_FENCE_WAIT or I915_EXEC_FENCE_SIGNAL.
91 iris_batch_add_syncpt(struct iris_batch
*batch
,
92 struct iris_syncpt
*syncpt
,
95 struct drm_i915_gem_exec_fence
*fence
=
96 util_dynarray_grow(&batch
->exec_fences
, sizeof(*fence
));
98 *fence
= (struct drm_i915_gem_exec_fence
) {
99 .handle
= syncpt
->handle
,
103 struct iris_syncpt
**store
=
104 util_dynarray_grow(&batch
->syncpts
, sizeof(*store
));
107 iris_syncpt_reference(batch
->screen
, store
, syncpt
);
110 /* ------------------------------------------------------------------- */
112 struct pipe_fence_handle
{
113 struct pipe_reference ref
;
114 struct iris_syncpt
*syncpt
[IRIS_BATCH_COUNT
];
119 iris_fence_destroy(struct pipe_screen
*p_screen
,
120 struct pipe_fence_handle
*fence
)
122 struct iris_screen
*screen
= (struct iris_screen
*)p_screen
;
124 for (unsigned i
= 0; i
< fence
->count
; i
++)
125 iris_syncpt_reference(screen
, &fence
->syncpt
[i
], NULL
);
131 iris_fence_reference(struct pipe_screen
*p_screen
,
132 struct pipe_fence_handle
**dst
,
133 struct pipe_fence_handle
*src
)
135 if (pipe_reference(&(*dst
)->ref
, &src
->ref
))
136 iris_fence_destroy(p_screen
, *dst
);
142 check_syncpt(struct pipe_screen
*p_screen
,
143 struct iris_syncpt
*syncpt
)
148 struct iris_screen
*screen
= (struct iris_screen
*)p_screen
;
149 struct drm_syncobj_wait args
= {
150 .handles
= (uintptr_t)&syncpt
->handle
,
153 return drm_ioctl(screen
->fd
, DRM_IOCTL_SYNCOBJ_WAIT
, &args
);
157 iris_fence_flush(struct pipe_context
*ctx
,
158 struct pipe_fence_handle
**out_fence
,
161 struct iris_screen
*screen
= (void *) ctx
->screen
;
162 struct iris_context
*ice
= (struct iris_context
*)ctx
;
163 struct iris_batch
*batch
[IRIS_BATCH_COUNT
] = {
168 /* XXX PIPE_FLUSH_DEFERRED */
169 for (unsigned i
= 0; i
< ARRAY_SIZE(batch
); i
++)
170 iris_batch_flush(batch
[i
]);
175 struct pipe_fence_handle
*fence
= calloc(1, sizeof(*fence
));
179 pipe_reference_init(&fence
->ref
, 1);
181 for (unsigned b
= 0; b
< ARRAY_SIZE(batch
); b
++) {
182 if (!check_syncpt(ctx
->screen
, batch
[b
]->last_syncpt
))
185 iris_syncpt_reference(screen
, &fence
->syncpt
[fence
->count
++],
186 batch
[b
]->last_syncpt
);
192 iris_fence_await(struct pipe_context
*ctx
,
193 struct pipe_fence_handle
*fence
)
195 struct iris_context
*ice
= (struct iris_context
*)ctx
;
196 struct iris_batch
*batch
[IRIS_BATCH_COUNT
] = {
200 for (unsigned b
= 0; b
< ARRAY_SIZE(batch
); b
++) {
201 for (unsigned i
= 0; i
< fence
->count
; i
++) {
202 iris_batch_add_syncpt(batch
[b
], fence
->syncpt
[i
],
203 I915_EXEC_FENCE_WAIT
);
208 #define NSEC_PER_SEC (1000 * USEC_PER_SEC)
209 #define USEC_PER_SEC (1000 * MSEC_PER_SEC)
210 #define MSEC_PER_SEC (1000)
213 rel2abs(uint64_t timeout
)
221 if (timeout
== PIPE_TIMEOUT_INFINITE
)
224 clock_gettime(CLOCK_MONOTONIC
, &ts
);
225 now
= ts
.tv_sec
* NSEC_PER_SEC
+ ts
.tv_nsec
;
227 if (now
> INT64_MAX
- timeout
)
230 return now
+ timeout
;
234 iris_fence_finish(struct pipe_screen
*p_screen
,
235 struct pipe_context
*ctx
,
236 struct pipe_fence_handle
*fence
,
239 struct iris_screen
*screen
= (struct iris_screen
*)p_screen
;
244 uint32_t handles
[ARRAY_SIZE(fence
->syncpt
)];
245 for (unsigned i
= 0; i
< fence
->count
; i
++)
246 handles
[i
] = fence
->syncpt
[i
]->handle
;
248 struct drm_syncobj_wait args
= {
249 .handles
= (uintptr_t)handles
,
250 .count_handles
= fence
->count
,
251 .timeout_nsec
= rel2abs(timeout
), /* XXX */
252 .flags
= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
254 return drm_ioctl(screen
->fd
, DRM_IOCTL_SYNCOBJ_WAIT
, &args
) == 0;
257 #ifndef SYNC_IOC_MAGIC
258 /* duplicated from linux/sync_file.h to avoid build-time dependency
259 * on new (v4.7) kernel headers. Once distro's are mostly using
260 * something newer than v4.7 drop this and #include <linux/sync_file.h>
263 struct sync_merge_data
{
271 #define SYNC_IOC_MAGIC '>'
272 #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
276 sync_merge_fd(int sync_fd
, int new_fd
)
284 struct sync_merge_data args
= {
285 .name
= "iris fence",
290 drm_ioctl(sync_fd
, SYNC_IOC_MERGE
, &args
);
298 iris_fence_get_fd(struct pipe_screen
*p_screen
,
299 struct pipe_fence_handle
*fence
)
301 struct iris_screen
*screen
= (struct iris_screen
*)p_screen
;
304 for (unsigned i
= 0; i
< fence
->count
; i
++) {
305 struct drm_syncobj_handle args
= {
306 .handle
= fence
->syncpt
[i
]->handle
,
307 .flags
= DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
,
311 drm_ioctl(screen
->fd
, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
, &args
);
312 fd
= sync_merge_fd(fd
, args
.fd
);
319 iris_fence_create_fd(struct pipe_context
*ctx
,
320 struct pipe_fence_handle
**out
,
322 enum pipe_fd_type type
)
324 assert(type
== PIPE_FD_TYPE_NATIVE_SYNC
);
326 struct iris_screen
*screen
= (struct iris_screen
*)ctx
->screen
;
327 struct drm_syncobj_handle args
= {
328 .flags
= DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
,
331 drm_ioctl(screen
->fd
, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
, &args
);
333 struct iris_syncpt
*syncpt
= malloc(sizeof(*syncpt
));
334 syncpt
->handle
= args
.handle
;
335 pipe_reference_init(&syncpt
->ref
, 1);
337 struct pipe_fence_handle
*fence
= malloc(sizeof(*fence
));
338 pipe_reference_init(&fence
->ref
, 1);
339 fence
->syncpt
[0] = syncpt
;
346 iris_init_screen_fence_functions(struct pipe_screen
*screen
)
348 screen
->fence_reference
= iris_fence_reference
;
349 screen
->fence_finish
= iris_fence_finish
;
350 screen
->fence_get_fd
= iris_fence_get_fd
;
354 iris_init_context_fence_functions(struct pipe_context
*ctx
)
356 ctx
->flush
= iris_fence_flush
;
357 ctx
->create_fence_fd
= iris_fence_create_fd
;
358 ctx
->fence_server_sync
= iris_fence_await
;