gallium: move filter assignment out of loop
[mesa.git] / src / gallium / auxiliary / pipebuffer / pb_buffer_fenced.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * \file
30 * Implementation of fenced buffers.
31 *
32 * \author José Fonseca <jrfonseca-at-tungstengraphics-dot-com>
33 * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com>
34 */
35
36
37 #include "pipe/p_compiler.h"
38 #include "pipe/p_debug.h"
39 #include "pipe/p_winsys.h"
40 #include "pipe/p_thread.h"
41 #include "pipe/p_util.h"
42 #include "util/u_double_list.h"
43
44 #include "pb_buffer.h"
45 #include "pb_buffer_fenced.h"
46
47 #ifndef __MSC__
48 #include <unistd.h>
49 #endif
50
51
52 /**
53 * Convenience macro (type safe).
54 */
55 #define SUPER(__derived) (&(__derived)->base)
56
57
58 struct fenced_buffer_list
59 {
60 _glthread_Mutex mutex;
61
62 struct pipe_winsys *winsys;
63
64 size_t numDelayed;
65 size_t checkDelayed;
66
67 struct list_head delayed;
68 };
69
70
71 /**
72 * Wrapper around a pipe buffer which adds fencing and reference counting.
73 */
74 struct fenced_buffer
75 {
76 struct pb_buffer base;
77
78 struct pb_buffer *buffer;
79
80 struct pipe_fence_handle *fence;
81
82 struct list_head head;
83 struct fenced_buffer_list *list;
84 };
85
86
87 static INLINE struct fenced_buffer *
88 fenced_buffer(struct pb_buffer *buf)
89 {
90 assert(buf);
91 assert(buf->vtbl == &fenced_buffer_vtbl);
92 return (struct fenced_buffer *)buf;
93 }
94
95
96
97
98 static void
99 _fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
100 int wait)
101 {
102 struct pipe_winsys *winsys = fenced_list->winsys;
103 struct fenced_buffer *fenced_buf;
104 struct list_head *list, *prev;
105 int signaled = -1;
106
107 list = fenced_list->delayed.next;
108
109 if (fenced_list->numDelayed > 3) {
110 unsigned i;
111
112 for (i = 0; i < fenced_list->numDelayed; i += 3) {
113 list = list->next;
114 }
115 }
116
117 prev = list->prev;
118 for (; list != &fenced_list->delayed; list = prev, prev = list->prev) {
119
120 fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head);
121
122 if (signaled != 0) {
123 if (wait) {
124 signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
125 }
126 else {
127 signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
128 }
129 }
130
131 if (signaled != 0)
132 /* XXX: we are assuming that buffers are freed in the same order they
133 * are fenced which may not always be true...
134 */
135 break;
136
137 winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
138
139 LIST_DEL(list);
140 fenced_list->numDelayed--;
141
142 /* Do the delayed destroy:
143 */
144 pb_reference(&fenced_buf->buffer, NULL);
145 FREE(fenced_buf);
146 }
147 }
148
149
150 static void
151 fenced_buffer_destroy(struct pb_buffer *buf)
152 {
153 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
154 struct fenced_buffer_list *fenced_list = fenced_buf->list;
155
156 if (fenced_buf->fence) {
157 LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
158 fenced_list->numDelayed++;
159 }
160 else {
161 pb_reference(&fenced_buf->buffer, NULL);
162 FREE(fenced_buf);
163 }
164
165 if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0)
166 _fenced_buffer_list_check_free(fenced_list, 0);
167 }
168
169
170 static void *
171 fenced_buffer_map(struct pb_buffer *buf,
172 unsigned flags)
173 {
174 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
175 return pb_map(fenced_buf->buffer, flags);
176 }
177
178
179 static void
180 fenced_buffer_unmap(struct pb_buffer *buf)
181 {
182 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
183 pb_unmap(fenced_buf->buffer);
184 }
185
186
187 static void
188 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
189 struct pb_buffer **base_buf,
190 unsigned *offset)
191 {
192 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
193 pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
194 }
195
196
197 const struct pb_vtbl
198 fenced_buffer_vtbl = {
199 fenced_buffer_destroy,
200 fenced_buffer_map,
201 fenced_buffer_unmap,
202 fenced_buffer_get_base_buffer
203 };
204
205
206 struct pb_buffer *
207 fenced_buffer_create(struct fenced_buffer_list *fenced_list,
208 struct pb_buffer *buffer)
209 {
210 struct fenced_buffer *buf;
211
212 if(!buffer)
213 return NULL;
214
215 buf = CALLOC_STRUCT(fenced_buffer);
216 if(!buf)
217 return NULL;
218
219 buf->base.base.refcount = 1;
220 buf->base.base.alignment = buffer->base.alignment;
221 buf->base.base.usage = buffer->base.usage;
222 buf->base.base.size = buffer->base.size;
223
224 buf->base.vtbl = &fenced_buffer_vtbl;
225 buf->buffer = buffer;
226 buf->list = fenced_list;
227
228 return &buf->base;
229 }
230
231
232 void
233 buffer_fence(struct pb_buffer *buf,
234 struct pipe_fence_handle *fence)
235 {
236 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
237 struct fenced_buffer_list *fenced_list = fenced_buf->list;
238 struct pipe_winsys *winsys = fenced_list->winsys;
239
240 _glthread_LOCK_MUTEX(fenced_list->mutex);
241 winsys->fence_reference(winsys, &fenced_buf->fence, fence);
242 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
243 }
244
245
246 struct fenced_buffer_list *
247 fenced_buffer_list_create(struct pipe_winsys *winsys)
248 {
249 struct fenced_buffer_list *fenced_list;
250
251 fenced_list = (struct fenced_buffer_list *)CALLOC(1, sizeof(*fenced_list));
252 if (!fenced_list)
253 return NULL;
254
255 fenced_list->winsys = winsys;
256
257 LIST_INITHEAD(&fenced_list->delayed);
258
259 fenced_list->numDelayed = 0;
260
261 /* TODO: don't hard code this */
262 fenced_list->checkDelayed = 5;
263
264 _glthread_INIT_MUTEX(fenced_list->mutex);
265
266 return fenced_list;
267 }
268
269
270 void
271 fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
272 int wait)
273 {
274 _glthread_LOCK_MUTEX(fenced_list->mutex);
275 _fenced_buffer_list_check_free(fenced_list, wait);
276 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
277 }
278
279
280 void
281 fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list)
282 {
283 _glthread_LOCK_MUTEX(fenced_list->mutex);
284
285 /* Wait on outstanding fences */
286 while (fenced_list->numDelayed) {
287 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
288 #ifndef __MSC__
289 sched_yield();
290 #endif
291 _fenced_buffer_list_check_free(fenced_list, 1);
292 _glthread_LOCK_MUTEX(fenced_list->mutex);
293 }
294
295 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
296
297 FREE(fenced_list);
298 }
299
300