pb_buffer_fenced.c revision 687a8b96ef13658bbe779d0011ce1144844f1972
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 "pipe/p_compiler.h"
40#include "pipe/p_debug.h"
41#include "pipe/p_winsys.h"
42#include "pipe/p_thread.h"
43#include "pipe/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
59struct 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 */
75struct 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
88static INLINE struct fenced_buffer *
89fenced_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
99static 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
151static void
152fenced_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
171static void *
172fenced_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
180static void
181fenced_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
188static void
189fenced_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
198const struct pb_vtbl
199fenced_buffer_vtbl = {
200      fenced_buffer_destroy,
201      fenced_buffer_map,
202      fenced_buffer_unmap,
203      fenced_buffer_get_base_buffer
204};
205
206
207struct pb_buffer *
208fenced_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
233void
234buffer_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
247struct fenced_buffer_list *
248fenced_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
271void
272fenced_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
281void
282fenced_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
300