Subversion Repositories Kolibri OS

Rev

Rev 4358 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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