pb_bufmgr_pool.c revision 92fcbf6e7bc622dcace226bb70ff6d5cdbdbaecb
1/**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28
29/**
30 * \file
31 * Batch buffer pool management.
32 *
33 * \author Jos� Fonseca <jrfonseca-at-tungstengraphics-dot-com>
34 * \author Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com>
35 */
36
37
38#include "linked_list.h"
39
40#include "p_compiler.h"
41#include "p_debug.h"
42#include "p_thread.h"
43#include "p_defines.h"
44#include "p_util.h"
45
46#include "pb_buffer.h"
47#include "pb_bufmgr.h"
48
49
50/**
51 * Convenience macro (type safe).
52 */
53#define SUPER(__derived) (&(__derived)->base)
54
55
56struct pool_pb_manager
57{
58   struct pb_manager base;
59
60   _glthread_Mutex mutex;
61
62   size_t bufSize;
63   size_t bufAlign;
64
65   size_t numFree;
66   size_t numTot;
67
68   struct list_head free;
69
70   struct pb_buffer *buffer;
71   void *map;
72
73   struct pool_buffer *bufs;
74};
75
76
77static INLINE struct pool_pb_manager *
78pool_pb_manager(struct pb_manager *mgr)
79{
80   assert(mgr);
81   return (struct pool_pb_manager *)mgr;
82}
83
84
85struct pool_buffer
86{
87   struct pb_buffer base;
88
89   struct pool_pb_manager *mgr;
90
91   struct list_head head;
92
93   size_t start;
94};
95
96
97static INLINE struct pool_buffer *
98pool_buffer(struct pb_buffer *buf)
99{
100   assert(buf);
101   return (struct pool_buffer *)buf;
102}
103
104
105
106static void
107pool_buffer_destroy(struct pb_buffer *buf)
108{
109   struct pool_buffer *pool_buf = pool_buffer(buf);
110   struct pool_pb_manager *pool = pool_buf->mgr;
111
112   assert(pool_buf->base.base.refcount == 0);
113
114   _glthread_LOCK_MUTEX(pool->mutex);
115   LIST_ADD(&pool_buf->head, &pool->free);
116   pool->numFree++;
117   _glthread_UNLOCK_MUTEX(pool->mutex);
118}
119
120
121static void *
122pool_buffer_map(struct pb_buffer *buf, unsigned flags)
123{
124   struct pool_buffer *pool_buf = pool_buffer(buf);
125   struct pool_pb_manager *pool = pool_buf->mgr;
126   void *map;
127
128   _glthread_LOCK_MUTEX(pool->mutex);
129   map = (unsigned char *) pool->map + pool_buf->start;
130   _glthread_UNLOCK_MUTEX(pool->mutex);
131   return map;
132}
133
134
135static void
136pool_buffer_unmap(struct pb_buffer *buf)
137{
138   /* No-op */
139}
140
141
142static void
143pool_buffer_get_base_buffer(struct pb_buffer *buf,
144                            struct pb_buffer **base_buf,
145                            unsigned *offset)
146{
147   struct pool_buffer *pool_buf = pool_buffer(buf);
148   struct pool_pb_manager *pool = pool_buf->mgr;
149   pb_get_base_buffer(pool->buffer, base_buf, offset);
150   *offset += pool_buf->start;
151}
152
153
154static const struct pb_vtbl
155pool_buffer_vtbl = {
156      pool_buffer_destroy,
157      pool_buffer_map,
158      pool_buffer_unmap,
159      pool_buffer_get_base_buffer
160};
161
162
163static struct pb_buffer *
164pool_bufmgr_create_buffer(struct pb_manager *mgr,
165                          size_t size,
166                          const struct pb_desc *desc)
167{
168   struct pool_pb_manager *pool = pool_pb_manager(mgr);
169   struct pool_buffer *pool_buf;
170   struct list_head *item;
171
172   assert(size == pool->bufSize);
173   assert(pool->bufAlign % desc->alignment == 0);
174
175   _glthread_LOCK_MUTEX(pool->mutex);
176
177   if (pool->numFree == 0) {
178      _glthread_UNLOCK_MUTEX(pool->mutex);
179      debug_printf("warning: out of fixed size buffer objects\n");
180      return NULL;
181   }
182
183   item = pool->free.next;
184
185   if (item == &pool->free) {
186      _glthread_UNLOCK_MUTEX(pool->mutex);
187      debug_printf("error: fixed size buffer pool corruption\n");
188      return NULL;
189   }
190
191   LIST_DEL(item);
192   --pool->numFree;
193
194   _glthread_UNLOCK_MUTEX(pool->mutex);
195
196   pool_buf = LIST_ENTRY(struct pool_buffer, item, head);
197   assert(pool_buf->base.base.refcount == 0);
198   pool_buf->base.base.refcount = 1;
199   pool_buf->base.base.alignment = desc->alignment;
200   pool_buf->base.base.usage = desc->usage;
201
202   return SUPER(pool_buf);
203}
204
205
206static void
207pool_bufmgr_destroy(struct pb_manager *mgr)
208{
209   struct pool_pb_manager *pool = pool_pb_manager(mgr);
210   _glthread_LOCK_MUTEX(pool->mutex);
211
212   FREE(pool->bufs);
213
214   pb_unmap(pool->buffer);
215   pb_reference(&pool->buffer, NULL);
216
217   _glthread_UNLOCK_MUTEX(pool->mutex);
218
219   FREE(mgr);
220}
221
222
223struct pb_manager *
224pool_bufmgr_create(struct pb_manager *provider,
225                   size_t numBufs,
226                   size_t bufSize,
227                   const struct pb_desc *desc)
228{
229   struct pool_pb_manager *pool;
230   struct pool_buffer *pool_buf;
231   size_t i;
232
233   pool = (struct pool_pb_manager *)CALLOC(1, sizeof(*pool));
234   if (!pool)
235      return NULL;
236
237   pool->base.destroy = pool_bufmgr_destroy;
238   pool->base.create_buffer = pool_bufmgr_create_buffer;
239
240   LIST_INITHEAD(&pool->free);
241
242   pool->numTot = numBufs;
243   pool->numFree = numBufs;
244   pool->bufSize = bufSize;
245   pool->bufAlign = desc->alignment;
246
247   _glthread_INIT_MUTEX(pool->mutex);
248
249   pool->buffer = provider->create_buffer(provider, numBufs*bufSize, desc);
250   if (!pool->buffer)
251      goto failure;
252
253   pool->map = pb_map(pool->buffer,
254                          PIPE_BUFFER_USAGE_CPU_READ |
255                          PIPE_BUFFER_USAGE_CPU_WRITE);
256   if(!pool->map)
257      goto failure;
258
259   pool->bufs = (struct pool_buffer *)CALLOC(numBufs, sizeof(*pool->bufs));
260   if (!pool->bufs)
261      goto failure;
262
263   pool_buf = pool->bufs;
264   for (i = 0; i < numBufs; ++i) {
265      pool_buf->base.base.refcount = 0;
266      pool_buf->base.base.alignment = 0;
267      pool_buf->base.base.usage = 0;
268      pool_buf->base.base.size = bufSize;
269      pool_buf->base.vtbl = &pool_buffer_vtbl;
270      pool_buf->mgr = pool;
271      pool_buf->start = i * bufSize;
272      LIST_ADDTAIL(&pool_buf->head, &pool->free);
273      pool_buf++;
274   }
275
276   return SUPER(pool);
277
278failure:
279   if(pool->bufs)
280      FREE(pool->bufs);
281   if(pool->map)
282      pb_unmap(pool->buffer);
283   if(pool->buffer)
284      pb_reference(&pool->buffer, NULL);
285   if(pool)
286      FREE(pool);
287   return NULL;
288}
289