Subversion Repositories Kolibri OS

Rev

Rev 4358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Copyright 2010 Christoph Bumiller
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 shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * 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
18
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
 * OTHER DEALINGS IN THE SOFTWARE.
21
 */
22
 
23
#include "util/u_double_list.h"
24
 
25
#include "nouveau_screen.h"
26
#include "nouveau_winsys.h"
27
#include "nouveau_fence.h"
28
 
29
#ifdef PIPE_OS_UNIX
30
#include 
31
#endif
32
 
33
boolean
34
nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence,
35
                  boolean emit)
36
{
37
   *fence = CALLOC_STRUCT(nouveau_fence);
38
   if (!*fence)
39
      return FALSE;
40
 
41
   (*fence)->screen = screen;
42
   (*fence)->ref = 1;
43
   LIST_INITHEAD(&(*fence)->work);
44
 
45
   if (emit)
46
      nouveau_fence_emit(*fence);
47
 
48
   return TRUE;
49
}
50
 
51
static void
52
nouveau_fence_trigger_work(struct nouveau_fence *fence)
53
{
54
   struct nouveau_fence_work *work, *tmp;
55
 
56
   LIST_FOR_EACH_ENTRY_SAFE(work, tmp, &fence->work, list) {
57
      work->func(work->data);
58
      LIST_DEL(&work->list);
59
      FREE(work);
60
   }
61
}
62
 
63
boolean
64
nouveau_fence_work(struct nouveau_fence *fence,
65
                   void (*func)(void *), void *data)
66
{
67
   struct nouveau_fence_work *work;
68
 
69
   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
70
      func(data);
71
      return TRUE;
72
   }
73
 
74
   work = CALLOC_STRUCT(nouveau_fence_work);
75
   if (!work)
76
      return FALSE;
77
   work->func = func;
78
   work->data = data;
79
   LIST_ADD(&work->list, &fence->work);
80
   return TRUE;
81
}
82
 
83
void
84
nouveau_fence_emit(struct nouveau_fence *fence)
85
{
86
   struct nouveau_screen *screen = fence->screen;
87
 
88
   assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE);
89
 
90
   /* set this now, so that if fence.emit triggers a flush we don't recurse */
91
   fence->state = NOUVEAU_FENCE_STATE_EMITTING;
92
 
93
   ++fence->ref;
94
 
95
   if (screen->fence.tail)
96
      screen->fence.tail->next = fence;
97
   else
98
      screen->fence.head = fence;
99
 
100
   screen->fence.tail = fence;
101
 
102
   screen->fence.emit(&screen->base, &fence->sequence);
103
 
104
   assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
105
   fence->state = NOUVEAU_FENCE_STATE_EMITTED;
106
}
107
 
108
void
109
nouveau_fence_del(struct nouveau_fence *fence)
110
{
111
   struct nouveau_fence *it;
112
   struct nouveau_screen *screen = fence->screen;
113
 
114
   if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
115
       fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
116
      if (fence == screen->fence.head) {
117
         screen->fence.head = fence->next;
118
         if (!screen->fence.head)
119
            screen->fence.tail = NULL;
120
      } else {
121
         for (it = screen->fence.head; it && it->next != fence; it = it->next);
122
         it->next = fence->next;
123
         if (screen->fence.tail == fence)
124
            screen->fence.tail = it;
125
      }
126
   }
127
 
128
   if (!LIST_IS_EMPTY(&fence->work)) {
129
      debug_printf("WARNING: deleting fence with work still pending !\n");
130
      nouveau_fence_trigger_work(fence);
131
   }
132
 
133
   FREE(fence);
134
}
135
 
136
void
137
nouveau_fence_update(struct nouveau_screen *screen, boolean flushed)
138
{
139
   struct nouveau_fence *fence;
140
   struct nouveau_fence *next = NULL;
141
   u32 sequence = screen->fence.update(&screen->base);
142
 
143
   if (screen->fence.sequence_ack == sequence)
144
      return;
145
   screen->fence.sequence_ack = sequence;
146
 
147
   for (fence = screen->fence.head; fence; fence = next) {
148
      next = fence->next;
149
      sequence = fence->sequence;
150
 
151
      fence->state = NOUVEAU_FENCE_STATE_SIGNALLED;
152
 
153
      nouveau_fence_trigger_work(fence);
154
      nouveau_fence_ref(NULL, &fence);
155
 
156
      if (sequence == screen->fence.sequence_ack)
157
         break;
158
   }
159
   screen->fence.head = next;
160
   if (!next)
161
      screen->fence.tail = NULL;
162
 
163
   if (flushed) {
164
      for (fence = next; fence; fence = fence->next)
165
         if (fence->state == NOUVEAU_FENCE_STATE_EMITTED)
166
            fence->state = NOUVEAU_FENCE_STATE_FLUSHED;
167
   }
168
}
169
 
170
#define NOUVEAU_FENCE_MAX_SPINS (1 << 31)
171
 
172
boolean
173
nouveau_fence_signalled(struct nouveau_fence *fence)
174
{
175
   struct nouveau_screen *screen = fence->screen;
176
 
177
   if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED)
178
      nouveau_fence_update(screen, FALSE);
179
 
180
   return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
181
}
182
 
183
boolean
184
nouveau_fence_wait(struct nouveau_fence *fence)
185
{
186
   struct nouveau_screen *screen = fence->screen;
187
   uint32_t spins = 0;
188
 
189
   /* wtf, someone is waiting on a fence in flush_notify handler? */
190
   assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
191
 
4401 Serge 192
   if (fence->state < NOUVEAU_FENCE_STATE_EMITTED)
4358 Serge 193
      nouveau_fence_emit(fence);
194
 
4401 Serge 195
   if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED)
4358 Serge 196
      if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
197
         return FALSE;
198
 
4401 Serge 199
   if (fence == screen->fence.current)
200
      nouveau_fence_next(screen);
201
 
4358 Serge 202
   do {
203
      nouveau_fence_update(screen, FALSE);
204
 
205
      if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
206
         return TRUE;
207
      if (!spins)
208
         NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1);
209
      spins++;
210
#ifdef PIPE_OS_UNIX
211
      if (!(spins % 8)) /* donate a few cycles */
212
         sched_yield();
213
#endif
214
   } while (spins < NOUVEAU_FENCE_MAX_SPINS);
215
 
216
   debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
217
                fence->sequence,
218
                screen->fence.sequence_ack, screen->fence.sequence);
219
 
220
   return FALSE;
221
}
222
 
223
void
224
nouveau_fence_next(struct nouveau_screen *screen)
225
{
226
   if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING)
227
      nouveau_fence_emit(screen->fence.current);
228
 
229
   nouveau_fence_ref(NULL, &screen->fence.current);
230
 
231
   nouveau_fence_new(screen, &screen->fence.current, FALSE);
232
}