1848b8605Smrg/*
2848b8605Smrg * Copyright 2010 Christoph Bumiller
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice shall be included in
12848b8605Smrg * all copies or substantial portions of the Software.
13848b8605Smrg *
14848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
21848b8605Smrg */
22848b8605Smrg
23848b8605Smrg#include "nouveau_screen.h"
24848b8605Smrg#include "nouveau_winsys.h"
25848b8605Smrg#include "nouveau_fence.h"
26b8e80941Smrg#include "util/os_time.h"
27848b8605Smrg
28848b8605Smrg#ifdef PIPE_OS_UNIX
29848b8605Smrg#include <sched.h>
30848b8605Smrg#endif
31848b8605Smrg
32b8e80941Smrgbool
33b8e80941Smrgnouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence)
34848b8605Smrg{
35848b8605Smrg   *fence = CALLOC_STRUCT(nouveau_fence);
36848b8605Smrg   if (!*fence)
37b8e80941Smrg      return false;
38848b8605Smrg
39848b8605Smrg   (*fence)->screen = screen;
40848b8605Smrg   (*fence)->ref = 1;
41848b8605Smrg   LIST_INITHEAD(&(*fence)->work);
42848b8605Smrg
43b8e80941Smrg   return true;
44848b8605Smrg}
45848b8605Smrg
46848b8605Smrgstatic void
47848b8605Smrgnouveau_fence_trigger_work(struct nouveau_fence *fence)
48848b8605Smrg{
49848b8605Smrg   struct nouveau_fence_work *work, *tmp;
50848b8605Smrg
51848b8605Smrg   LIST_FOR_EACH_ENTRY_SAFE(work, tmp, &fence->work, list) {
52848b8605Smrg      work->func(work->data);
53848b8605Smrg      LIST_DEL(&work->list);
54848b8605Smrg      FREE(work);
55848b8605Smrg   }
56848b8605Smrg}
57848b8605Smrg
58848b8605Smrgvoid
59848b8605Smrgnouveau_fence_emit(struct nouveau_fence *fence)
60848b8605Smrg{
61848b8605Smrg   struct nouveau_screen *screen = fence->screen;
62848b8605Smrg
63848b8605Smrg   assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE);
64848b8605Smrg
65848b8605Smrg   /* set this now, so that if fence.emit triggers a flush we don't recurse */
66848b8605Smrg   fence->state = NOUVEAU_FENCE_STATE_EMITTING;
67848b8605Smrg
68848b8605Smrg   ++fence->ref;
69848b8605Smrg
70848b8605Smrg   if (screen->fence.tail)
71848b8605Smrg      screen->fence.tail->next = fence;
72848b8605Smrg   else
73848b8605Smrg      screen->fence.head = fence;
74848b8605Smrg
75848b8605Smrg   screen->fence.tail = fence;
76848b8605Smrg
77848b8605Smrg   screen->fence.emit(&screen->base, &fence->sequence);
78848b8605Smrg
79848b8605Smrg   assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
80848b8605Smrg   fence->state = NOUVEAU_FENCE_STATE_EMITTED;
81848b8605Smrg}
82848b8605Smrg
83848b8605Smrgvoid
84848b8605Smrgnouveau_fence_del(struct nouveau_fence *fence)
85848b8605Smrg{
86848b8605Smrg   struct nouveau_fence *it;
87848b8605Smrg   struct nouveau_screen *screen = fence->screen;
88848b8605Smrg
89848b8605Smrg   if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
90848b8605Smrg       fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
91848b8605Smrg      if (fence == screen->fence.head) {
92848b8605Smrg         screen->fence.head = fence->next;
93848b8605Smrg         if (!screen->fence.head)
94848b8605Smrg            screen->fence.tail = NULL;
95848b8605Smrg      } else {
96848b8605Smrg         for (it = screen->fence.head; it && it->next != fence; it = it->next);
97848b8605Smrg         it->next = fence->next;
98848b8605Smrg         if (screen->fence.tail == fence)
99848b8605Smrg            screen->fence.tail = it;
100848b8605Smrg      }
101848b8605Smrg   }
102848b8605Smrg
103848b8605Smrg   if (!LIST_IS_EMPTY(&fence->work)) {
104848b8605Smrg      debug_printf("WARNING: deleting fence with work still pending !\n");
105848b8605Smrg      nouveau_fence_trigger_work(fence);
106848b8605Smrg   }
107848b8605Smrg
108848b8605Smrg   FREE(fence);
109848b8605Smrg}
110848b8605Smrg
111848b8605Smrgvoid
112b8e80941Smrgnouveau_fence_update(struct nouveau_screen *screen, bool flushed)
113848b8605Smrg{
114848b8605Smrg   struct nouveau_fence *fence;
115848b8605Smrg   struct nouveau_fence *next = NULL;
116848b8605Smrg   u32 sequence = screen->fence.update(&screen->base);
117848b8605Smrg
118848b8605Smrg   if (screen->fence.sequence_ack == sequence)
119848b8605Smrg      return;
120848b8605Smrg   screen->fence.sequence_ack = sequence;
121848b8605Smrg
122848b8605Smrg   for (fence = screen->fence.head; fence; fence = next) {
123848b8605Smrg      next = fence->next;
124848b8605Smrg      sequence = fence->sequence;
125848b8605Smrg
126848b8605Smrg      fence->state = NOUVEAU_FENCE_STATE_SIGNALLED;
127848b8605Smrg
128848b8605Smrg      nouveau_fence_trigger_work(fence);
129848b8605Smrg      nouveau_fence_ref(NULL, &fence);
130848b8605Smrg
131848b8605Smrg      if (sequence == screen->fence.sequence_ack)
132848b8605Smrg         break;
133848b8605Smrg   }
134848b8605Smrg   screen->fence.head = next;
135848b8605Smrg   if (!next)
136848b8605Smrg      screen->fence.tail = NULL;
137848b8605Smrg
138848b8605Smrg   if (flushed) {
139848b8605Smrg      for (fence = next; fence; fence = fence->next)
140848b8605Smrg         if (fence->state == NOUVEAU_FENCE_STATE_EMITTED)
141848b8605Smrg            fence->state = NOUVEAU_FENCE_STATE_FLUSHED;
142848b8605Smrg   }
143848b8605Smrg}
144848b8605Smrg
145848b8605Smrg#define NOUVEAU_FENCE_MAX_SPINS (1 << 31)
146848b8605Smrg
147b8e80941Smrgbool
148848b8605Smrgnouveau_fence_signalled(struct nouveau_fence *fence)
149848b8605Smrg{
150848b8605Smrg   struct nouveau_screen *screen = fence->screen;
151848b8605Smrg
152848b8605Smrg   if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
153b8e80941Smrg      return true;
154848b8605Smrg
155848b8605Smrg   if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED)
156b8e80941Smrg      nouveau_fence_update(screen, false);
157848b8605Smrg
158848b8605Smrg   return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
159848b8605Smrg}
160848b8605Smrg
161b8e80941Smrgstatic bool
162b8e80941Smrgnouveau_fence_kick(struct nouveau_fence *fence)
163848b8605Smrg{
164848b8605Smrg   struct nouveau_screen *screen = fence->screen;
165848b8605Smrg
166848b8605Smrg   /* wtf, someone is waiting on a fence in flush_notify handler? */
167848b8605Smrg   assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
168848b8605Smrg
169b8e80941Smrg   if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) {
170b8e80941Smrg      PUSH_SPACE(screen->pushbuf, 8);
171b8e80941Smrg      /* The space allocation might trigger a flush, which could emit the
172b8e80941Smrg       * current fence. So check again.
173b8e80941Smrg       */
174b8e80941Smrg      if (fence->state < NOUVEAU_FENCE_STATE_EMITTED)
175b8e80941Smrg         nouveau_fence_emit(fence);
176b8e80941Smrg   }
177848b8605Smrg
178848b8605Smrg   if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED)
179848b8605Smrg      if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
180b8e80941Smrg         return false;
181848b8605Smrg
182848b8605Smrg   if (fence == screen->fence.current)
183848b8605Smrg      nouveau_fence_next(screen);
184848b8605Smrg
185b8e80941Smrg   nouveau_fence_update(screen, false);
186b8e80941Smrg
187b8e80941Smrg   return true;
188b8e80941Smrg}
189b8e80941Smrg
190b8e80941Smrgbool
191b8e80941Smrgnouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debug)
192b8e80941Smrg{
193b8e80941Smrg   struct nouveau_screen *screen = fence->screen;
194b8e80941Smrg   uint32_t spins = 0;
195b8e80941Smrg   int64_t start = 0;
196848b8605Smrg
197b8e80941Smrg   if (debug && debug->debug_message)
198b8e80941Smrg      start = os_time_get_nano();
199b8e80941Smrg
200b8e80941Smrg   if (!nouveau_fence_kick(fence))
201b8e80941Smrg      return false;
202b8e80941Smrg
203b8e80941Smrg   do {
204b8e80941Smrg      if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
205b8e80941Smrg         if (debug && debug->debug_message)
206b8e80941Smrg            pipe_debug_message(debug, PERF_INFO,
207b8e80941Smrg                               "stalled %.3f ms waiting for fence",
208b8e80941Smrg                               (os_time_get_nano() - start) / 1000000.f);
209b8e80941Smrg         return true;
210b8e80941Smrg      }
211848b8605Smrg      if (!spins)
212848b8605Smrg         NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1);
213848b8605Smrg      spins++;
214848b8605Smrg#ifdef PIPE_OS_UNIX
215848b8605Smrg      if (!(spins % 8)) /* donate a few cycles */
216848b8605Smrg         sched_yield();
217848b8605Smrg#endif
218b8e80941Smrg
219b8e80941Smrg      nouveau_fence_update(screen, false);
220848b8605Smrg   } while (spins < NOUVEAU_FENCE_MAX_SPINS);
221848b8605Smrg
222848b8605Smrg   debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
223848b8605Smrg                fence->sequence,
224848b8605Smrg                screen->fence.sequence_ack, screen->fence.sequence);
225848b8605Smrg
226b8e80941Smrg   return false;
227848b8605Smrg}
228848b8605Smrg
229848b8605Smrgvoid
230848b8605Smrgnouveau_fence_next(struct nouveau_screen *screen)
231848b8605Smrg{
232b8e80941Smrg   if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING) {
233b8e80941Smrg      if (screen->fence.current->ref > 1)
234b8e80941Smrg         nouveau_fence_emit(screen->fence.current);
235b8e80941Smrg      else
236b8e80941Smrg         return;
237b8e80941Smrg   }
238848b8605Smrg
239848b8605Smrg   nouveau_fence_ref(NULL, &screen->fence.current);
240848b8605Smrg
241b8e80941Smrg   nouveau_fence_new(screen, &screen->fence.current);
242b8e80941Smrg}
243b8e80941Smrg
244b8e80941Smrgvoid
245b8e80941Smrgnouveau_fence_unref_bo(void *data)
246b8e80941Smrg{
247b8e80941Smrg   struct nouveau_bo *bo = data;
248b8e80941Smrg
249b8e80941Smrg   nouveau_bo_ref(NULL, &bo);
250b8e80941Smrg}
251b8e80941Smrg
252b8e80941Smrgbool
253b8e80941Smrgnouveau_fence_work(struct nouveau_fence *fence,
254b8e80941Smrg                   void (*func)(void *), void *data)
255b8e80941Smrg{
256b8e80941Smrg   struct nouveau_fence_work *work;
257b8e80941Smrg
258b8e80941Smrg   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
259b8e80941Smrg      func(data);
260b8e80941Smrg      return true;
261b8e80941Smrg   }
262b8e80941Smrg
263b8e80941Smrg   work = CALLOC_STRUCT(nouveau_fence_work);
264b8e80941Smrg   if (!work)
265b8e80941Smrg      return false;
266b8e80941Smrg   work->func = func;
267b8e80941Smrg   work->data = data;
268b8e80941Smrg   LIST_ADD(&work->list, &fence->work);
269b8e80941Smrg   p_atomic_inc(&fence->work_count);
270b8e80941Smrg   if (fence->work_count > 64)
271b8e80941Smrg      nouveau_fence_kick(fence);
272b8e80941Smrg   return true;
273848b8605Smrg}
274