Code reorganization: placeholder for state-trackers.
[mesa.git] / src / gallium / aux / 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 "linked_list.h"
38
39 #include "p_compiler.h"
40 #include "p_debug.h"
41 #include "p_winsys.h"
42 #include "p_thread.h"
43 #include "p_util.h"
44
45 #include "pb_buffer.h"
46 #include "pb_buffer_fenced.h"
47
48 #ifndef __MSC__
49 #include <unistd.h>
50 #endif
51
52
53 /**
54 * Convenience macro (type safe).
55 */
56 #define SUPER(__derived) (&(__derived)->base)
57
58
59 struct fenced_buffer_list
60 {
61 _glthread_Mutex mutex;
62
63 struct pipe_winsys *winsys;
64
65 size_t numDelayed;
66 size_t checkDelayed;
67
68 struct list_head delayed;
69 };
70
71
72 /**
73 * Wrapper around a pipe buffer which adds fencing and reference counting.
74 */
75 struct fenced_buffer
76 {
77 struct pb_buffer base;
78
79 struct pb_buffer *buffer;
80
81 struct pipe_fence_handle *fence;
82
83 struct list_head head;
84 struct fenced_buffer_list *list;
85 };
86
87
88 static INLINE struct fenced_buffer *
89 fenced_buffer(struct pb_buffer *buf)
90 {
91 assert(buf);
92 assert(buf->vtbl == &fenced_buffer_vtbl);
93 return (struct fenced_buffer *)buf;
94 }
95
96
97
98
99 static void
100 _fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
101 int wait)
102 {
103 struct pipe_winsys *winsys = fenced_list->winsys;
104 struct fenced_buffer *fenced_buf;
105 struct list_head *list, *prev;
106 int signaled = -1;
107
108 list = fenced_list->delayed.next;
109
110 if (fenced_list->numDelayed > 3) {
111 unsigned i;
112
113 for (i = 0; i < fenced_list->numDelayed; i += 3) {
114 list = list->next;
115 }
116 }
117
118 prev = list->prev;
119 for (; list != &fenced_list->delayed; list = prev, prev = list->prev) {
120
121 fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head);
122
123 if (signaled != 0) {
124 if (wait) {
125 signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
126 }
127 else {
128 signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
129 }
130 }
131
132 if (signaled != 0)
133 /* XXX: we are assuming that buffers are freed in the same order they
134 * are fenced which may not always be true...
135 */
136 break;
137
138 winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
139
140 LIST_DEL(list);
141 fenced_list->numDelayed--;
142
143 /* Do the delayed destroy:
144 */
145 pb_reference(&fenced_buf->buffer, NULL);
146 FREE(fenced_buf);
147 }
148 }
149
150
151 static void
152 fenced_buffer_destroy(struct pb_buffer *buf)
153 {
154 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
155 struct fenced_buffer_list *fenced_list = fenced_buf->list;
156
157 if (fenced_buf->fence) {
158 LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
159 fenced_list->numDelayed++;
160 }
161 else {
162 pb_reference(&fenced_buf->buffer, NULL);
163 FREE(fenced_buf);
164 }
165
166 if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0)
167 _fenced_buffer_list_check_free(fenced_list, 0);
168 }
169
170
171 static void *
172 fenced_buffer_map(struct pb_buffer *buf,
173 unsigned flags)
174 {
175 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
176 return pb_map(fenced_buf->buffer, flags);
177 }
178
179
180 static void
181 fenced_buffer_unmap(struct pb_buffer *buf)
182 {
183 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
184 pb_unmap(fenced_buf->buffer);
185 }
186
187
188 static void
189 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
190 struct pb_buffer **base_buf,
191 unsigned *offset)
192 {
193 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
194 pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
195 }
196
197
198 const struct pb_vtbl
199 fenced_buffer_vtbl = {
200 fenced_buffer_destroy,
201 fenced_buffer_map,
202 fenced_buffer_unmap,
203 fenced_buffer_get_base_buffer
204 };
205
206
207 struct pb_buffer *
208 fenced_buffer_create(struct fenced_buffer_list *fenced_list,
209 struct pb_buffer *buffer)
210 {
211 struct fenced_buffer *buf;
212
213 if(!buffer)
214 return NULL;
215
216 buf = CALLOC_STRUCT(fenced_buffer);
217 if(!buf)
218 return NULL;
219
220 buf->base.base.refcount = 1;
221 buf->base.base.alignment = buffer->base.alignment;
222 buf->base.base.usage = buffer->base.usage;
223 buf->base.base.size = buffer->base.size;
224
225 buf->base.vtbl = &fenced_buffer_vtbl;
226 buf->buffer = buffer;
227 buf->list = fenced_list;
228
229 return &buf->base;
230 }
231
232
233 void
234 buffer_fence(struct pb_buffer *buf,
235 struct pipe_fence_handle *fence)
236 {
237 struct fenced_buffer *fenced_buf = fenced_buffer(buf);
238 struct fenced_buffer_list *fenced_list = fenced_buf->list;
239 struct pipe_winsys *winsys = fenced_list->winsys;
240
241 _glthread_LOCK_MUTEX(fenced_list->mutex);
242 winsys->fence_reference(winsys, &fenced_buf->fence, fence);
243 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
244 }
245
246
247 struct fenced_buffer_list *
248 fenced_buffer_list_create(struct pipe_winsys *winsys)
249 {
250 struct fenced_buffer_list *fenced_list;
251
252 fenced_list = (struct fenced_buffer_list *)CALLOC(1, sizeof(*fenced_list));
253 if (!fenced_list)
254 return NULL;
255
256 fenced_list->winsys = winsys;
257
258 LIST_INITHEAD(&fenced_list->delayed);
259
260 fenced_list->numDelayed = 0;
261
262 /* TODO: don't hard code this */
263 fenced_list->checkDelayed = 5;
264
265 _glthread_INIT_MUTEX(fenced_list->mutex);
266
267 return fenced_list;
268 }
269
270
271 void
272 fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list,
273 int wait)
274 {
275 _glthread_LOCK_MUTEX(fenced_list->mutex);
276 _fenced_buffer_list_check_free(fenced_list, wait);
277 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
278 }
279
280
281 void
282 fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list)
283 {
284 _glthread_LOCK_MUTEX(fenced_list->mutex);
285
286 /* Wait on outstanding fences */
287 while (fenced_list->numDelayed) {
288 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
289 sched_yield();
290 _fenced_buffer_list_check_free(fenced_list, 1);
291 _glthread_LOCK_MUTEX(fenced_list->mutex);
292 }
293
294 _glthread_UNLOCK_MUTEX(fenced_list->mutex);
295
296 FREE(fenced_list);
297 }
298
299