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