1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "util/os_file.h"
28bf215546Sopenharmony_ci#include "util/u_inlines.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "freedreno_batch.h"
31bf215546Sopenharmony_ci#include "freedreno_context.h"
32bf215546Sopenharmony_ci#include "freedreno_fence.h"
33bf215546Sopenharmony_ci#include "freedreno_util.h"
34bf215546Sopenharmony_ci/* TODO: Use the interface drm/freedreno_drmif.h instead of calling directly */
35bf215546Sopenharmony_ci#include <xf86drm.h>
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_cistatic bool
38bf215546Sopenharmony_cifence_flush(struct pipe_context *pctx, struct pipe_fence_handle *fence,
39bf215546Sopenharmony_ci            uint64_t timeout)
40bf215546Sopenharmony_ci   /* NOTE: in the !fence_is_signalled() case we may be called from non-driver
41bf215546Sopenharmony_ci    * thread, but we don't call fd_batch_flush() in that case
42bf215546Sopenharmony_ci    */
43bf215546Sopenharmony_ci   in_dt
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci   if (!util_queue_fence_is_signalled(&fence->ready)) {
46bf215546Sopenharmony_ci      if (fence->tc_token) {
47bf215546Sopenharmony_ci         threaded_context_flush(pctx, fence->tc_token, timeout == 0);
48bf215546Sopenharmony_ci      }
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci      if (!timeout)
51bf215546Sopenharmony_ci         return false;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci      if (timeout == PIPE_TIMEOUT_INFINITE) {
54bf215546Sopenharmony_ci         util_queue_fence_wait(&fence->ready);
55bf215546Sopenharmony_ci      } else {
56bf215546Sopenharmony_ci         int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
57bf215546Sopenharmony_ci         if (!util_queue_fence_wait_timeout(&fence->ready, abs_timeout)) {
58bf215546Sopenharmony_ci            return false;
59bf215546Sopenharmony_ci         }
60bf215546Sopenharmony_ci      }
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci      util_queue_fence_wait(&fence->submit_fence.ready);
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci      /* We've already waited for batch to be flushed and fence->batch
65bf215546Sopenharmony_ci       * to be cleared:
66bf215546Sopenharmony_ci       */
67bf215546Sopenharmony_ci      assert(!fence->batch);
68bf215546Sopenharmony_ci      return true;
69bf215546Sopenharmony_ci   }
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   if (fence->batch)
72bf215546Sopenharmony_ci      fd_batch_flush(fence->batch);
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   util_queue_fence_wait(&fence->submit_fence.ready);
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   assert(!fence->batch);
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   return true;
79bf215546Sopenharmony_ci}
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_civoid
82bf215546Sopenharmony_cifd_fence_repopulate(struct pipe_fence_handle *fence, struct pipe_fence_handle *last_fence)
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   if (last_fence->last_fence)
85bf215546Sopenharmony_ci      fd_fence_repopulate(fence, last_fence->last_fence);
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   /* The fence we are re-populating must not be an fd-fence (but last_fince
88bf215546Sopenharmony_ci    * might have been)
89bf215546Sopenharmony_ci    */
90bf215546Sopenharmony_ci   assert(!fence->submit_fence.use_fence_fd);
91bf215546Sopenharmony_ci   assert(!last_fence->batch);
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   fd_fence_ref(&fence->last_fence, last_fence);
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   /* We have nothing to flush, so nothing will clear the batch reference
96bf215546Sopenharmony_ci    * (which is normally done when the batch is flushed), so do it now:
97bf215546Sopenharmony_ci    */
98bf215546Sopenharmony_ci   fd_fence_set_batch(fence, NULL);
99bf215546Sopenharmony_ci}
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_cistatic void
102bf215546Sopenharmony_cifd_fence_destroy(struct pipe_fence_handle *fence)
103bf215546Sopenharmony_ci{
104bf215546Sopenharmony_ci   fd_fence_ref(&fence->last_fence, NULL);
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci   tc_unflushed_batch_token_reference(&fence->tc_token, NULL);
107bf215546Sopenharmony_ci   if (fence->submit_fence.use_fence_fd)
108bf215546Sopenharmony_ci      close(fence->submit_fence.fence_fd);
109bf215546Sopenharmony_ci   if (fence->syncobj)
110bf215546Sopenharmony_ci      drmSyncobjDestroy(fd_device_fd(fence->screen->dev), fence->syncobj);
111bf215546Sopenharmony_ci   fd_pipe_del(fence->pipe);
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   /* TODO might be worth trying harder to avoid a potential stall here,
114bf215546Sopenharmony_ci    * but that would require the submit somehow holding a reference to
115bf215546Sopenharmony_ci    * the pipe_fence_handle.. and I'm not sure if it is a thing that is
116bf215546Sopenharmony_ci    * likely to matter much.
117bf215546Sopenharmony_ci    */
118bf215546Sopenharmony_ci   util_queue_fence_wait(&fence->submit_fence.ready);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   FREE(fence);
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_civoid
124bf215546Sopenharmony_cifd_fence_ref(struct pipe_fence_handle **ptr, struct pipe_fence_handle *pfence)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   if (pipe_reference(&(*ptr)->reference, &pfence->reference))
127bf215546Sopenharmony_ci      fd_fence_destroy(*ptr);
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   *ptr = pfence;
130bf215546Sopenharmony_ci}
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_cibool
133bf215546Sopenharmony_cifd_fence_finish(struct pipe_screen *pscreen, struct pipe_context *pctx,
134bf215546Sopenharmony_ci                struct pipe_fence_handle *fence, uint64_t timeout)
135bf215546Sopenharmony_ci{
136bf215546Sopenharmony_ci   /* Note: for TC deferred fence, pctx->flush() may not have been called
137bf215546Sopenharmony_ci    * yet, so always do fence_flush() *first* before delegating to
138bf215546Sopenharmony_ci    * fence->last_fence
139bf215546Sopenharmony_ci    */
140bf215546Sopenharmony_ci   if (!fence_flush(pctx, fence, timeout))
141bf215546Sopenharmony_ci      return false;
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   if (fence->last_fence)
144bf215546Sopenharmony_ci      return fd_fence_finish(pscreen, pctx, fence->last_fence, timeout);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   if (fence->last_fence)
147bf215546Sopenharmony_ci      fence = fence->last_fence;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   if (fence->submit_fence.use_fence_fd) {
150bf215546Sopenharmony_ci      int ret = sync_wait(fence->submit_fence.fence_fd, timeout / 1000000);
151bf215546Sopenharmony_ci      return ret == 0;
152bf215546Sopenharmony_ci   }
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   if (fd_pipe_wait_timeout(fence->pipe, &fence->submit_fence.fence, timeout))
155bf215546Sopenharmony_ci      return false;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   return true;
158bf215546Sopenharmony_ci}
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_cistatic struct pipe_fence_handle *
161bf215546Sopenharmony_cifence_create(struct fd_context *ctx, struct fd_batch *batch, int fence_fd,
162bf215546Sopenharmony_ci             int syncobj)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   struct pipe_fence_handle *fence;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   fence = CALLOC_STRUCT(pipe_fence_handle);
167bf215546Sopenharmony_ci   if (!fence)
168bf215546Sopenharmony_ci      return NULL;
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   pipe_reference_init(&fence->reference, 1);
171bf215546Sopenharmony_ci   util_queue_fence_init(&fence->ready);
172bf215546Sopenharmony_ci   util_queue_fence_init(&fence->submit_fence.ready);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   fence->ctx = ctx;
175bf215546Sopenharmony_ci   fd_fence_set_batch(fence, batch);
176bf215546Sopenharmony_ci   fence->pipe = fd_pipe_ref(ctx->pipe);
177bf215546Sopenharmony_ci   fence->screen = ctx->screen;
178bf215546Sopenharmony_ci   fence->submit_fence.fence_fd = fence_fd;
179bf215546Sopenharmony_ci   fence->submit_fence.use_fence_fd = (fence_fd != -1);
180bf215546Sopenharmony_ci   fence->syncobj = syncobj;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   return fence;
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_civoid
186bf215546Sopenharmony_cifd_create_fence_fd(struct pipe_context *pctx, struct pipe_fence_handle **pfence,
187bf215546Sopenharmony_ci                   int fd, enum pipe_fd_type type)
188bf215546Sopenharmony_ci{
189bf215546Sopenharmony_ci   struct fd_context *ctx = fd_context(pctx);
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   switch (type) {
192bf215546Sopenharmony_ci   case PIPE_FD_TYPE_NATIVE_SYNC:
193bf215546Sopenharmony_ci      *pfence =
194bf215546Sopenharmony_ci         fence_create(fd_context(pctx), NULL, os_dupfd_cloexec(fd), 0);
195bf215546Sopenharmony_ci      break;
196bf215546Sopenharmony_ci   case PIPE_FD_TYPE_SYNCOBJ: {
197bf215546Sopenharmony_ci      int ret;
198bf215546Sopenharmony_ci      uint32_t syncobj;
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci      assert(ctx->screen->has_syncobj);
201bf215546Sopenharmony_ci      ret = drmSyncobjFDToHandle(fd_device_fd(ctx->screen->dev), fd, &syncobj);
202bf215546Sopenharmony_ci      if (!ret)
203bf215546Sopenharmony_ci         close(fd);
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci      *pfence = fence_create(fd_context(pctx), NULL, -1, syncobj);
206bf215546Sopenharmony_ci      break;
207bf215546Sopenharmony_ci   }
208bf215546Sopenharmony_ci   default:
209bf215546Sopenharmony_ci      unreachable("Unhandled fence type");
210bf215546Sopenharmony_ci   }
211bf215546Sopenharmony_ci}
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_civoid
214bf215546Sopenharmony_cifd_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *fence)
215bf215546Sopenharmony_ci{
216bf215546Sopenharmony_ci   struct fd_context *ctx = fd_context(pctx);
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   /* NOTE: we don't expect the combination of fence-fd + async-flush-fence,
219bf215546Sopenharmony_ci    * so timeout==0 is ok here:
220bf215546Sopenharmony_ci    */
221bf215546Sopenharmony_ci   fence_flush(pctx, fence, 0);
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   if (fence->last_fence) {
224bf215546Sopenharmony_ci      fd_fence_server_sync(pctx, fence->last_fence);
225bf215546Sopenharmony_ci      return;
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   /* if not an external fence, then nothing more to do without preemption: */
229bf215546Sopenharmony_ci   if (!fence->submit_fence.use_fence_fd)
230bf215546Sopenharmony_ci      return;
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (sync_accumulate("freedreno", &ctx->in_fence_fd, fence->submit_fence.fence_fd)) {
233bf215546Sopenharmony_ci      /* error */
234bf215546Sopenharmony_ci   }
235bf215546Sopenharmony_ci}
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_civoid
238bf215546Sopenharmony_cifd_fence_server_signal(struct pipe_context *pctx,
239bf215546Sopenharmony_ci                       struct pipe_fence_handle *fence)
240bf215546Sopenharmony_ci{
241bf215546Sopenharmony_ci   struct fd_context *ctx = fd_context(pctx);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   if (fence->syncobj) {
244bf215546Sopenharmony_ci      drmSyncobjSignal(fd_device_fd(ctx->screen->dev), &fence->syncobj, 1);
245bf215546Sopenharmony_ci   }
246bf215546Sopenharmony_ci}
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ciint
249bf215546Sopenharmony_cifd_fence_get_fd(struct pipe_screen *pscreen, struct pipe_fence_handle *fence)
250bf215546Sopenharmony_ci{
251bf215546Sopenharmony_ci   /* We don't expect deferred flush to be combined with fence-fd: */
252bf215546Sopenharmony_ci   assert(!fence->last_fence);
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   assert(fence->submit_fence.use_fence_fd);
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   /* NOTE: in the deferred fence case, the pctx we want is the threaded-ctx
257bf215546Sopenharmony_ci    * but if TC is not used, this will be null.  Which is fine, we won't call
258bf215546Sopenharmony_ci    * threaded_context_flush() in that case
259bf215546Sopenharmony_ci    */
260bf215546Sopenharmony_ci   fence_flush(&fence->ctx->tc->base, fence, PIPE_TIMEOUT_INFINITE);
261bf215546Sopenharmony_ci   return os_dupfd_cloexec(fence->submit_fence.fence_fd);
262bf215546Sopenharmony_ci}
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_cibool
265bf215546Sopenharmony_cifd_fence_is_fd(struct pipe_fence_handle *fence)
266bf215546Sopenharmony_ci{
267bf215546Sopenharmony_ci   return fence->submit_fence.use_fence_fd;
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_cistruct pipe_fence_handle *
271bf215546Sopenharmony_cifd_fence_create(struct fd_batch *batch)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   return fence_create(batch->ctx, batch, -1, 0);
274bf215546Sopenharmony_ci}
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_civoid
277bf215546Sopenharmony_cifd_fence_set_batch(struct pipe_fence_handle *fence, struct fd_batch *batch)
278bf215546Sopenharmony_ci{
279bf215546Sopenharmony_ci   if (batch) {
280bf215546Sopenharmony_ci      assert(!fence->batch);
281bf215546Sopenharmony_ci      fence->batch = batch;
282bf215546Sopenharmony_ci      fd_batch_needs_flush(batch);
283bf215546Sopenharmony_ci   } else {
284bf215546Sopenharmony_ci      fence->batch = NULL;
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci      /* When the batch is dis-associated with the fence, we can signal TC
287bf215546Sopenharmony_ci       * that the fence is flushed
288bf215546Sopenharmony_ci       */
289bf215546Sopenharmony_ci      if (fence->needs_signal) {
290bf215546Sopenharmony_ci         util_queue_fence_signal(&fence->ready);
291bf215546Sopenharmony_ci         fence->needs_signal = false;
292bf215546Sopenharmony_ci      }
293bf215546Sopenharmony_ci   }
294bf215546Sopenharmony_ci}
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_cistruct pipe_fence_handle *
297bf215546Sopenharmony_cifd_fence_create_unflushed(struct pipe_context *pctx,
298bf215546Sopenharmony_ci                          struct tc_unflushed_batch_token *tc_token)
299bf215546Sopenharmony_ci{
300bf215546Sopenharmony_ci   struct pipe_fence_handle *fence =
301bf215546Sopenharmony_ci      fence_create(fd_context(pctx), NULL, -1, 0);
302bf215546Sopenharmony_ci   fence->needs_signal = true;
303bf215546Sopenharmony_ci   util_queue_fence_reset(&fence->ready);
304bf215546Sopenharmony_ci   tc_unflushed_batch_token_reference(&fence->tc_token, tc_token);
305bf215546Sopenharmony_ci   return fence;
306bf215546Sopenharmony_ci}
307