pb_bufmgr_pool.c revision ea4ca10b1bec67c8a60db0e4e5581318ce9f62f9
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 "pipe/p_compiler.h"
39#include "pipe/p_debug.h"
40#include "pipe/p_thread.h"
41#include "pipe/p_defines.h"
42#include "pipe/p_util.h"
43#include "util/u_double_list.h"
44
45#include "pb_buffer.h"
46#include "pb_bufmgr.h"
47
48
49/**
50 * Convenience macro (type safe).
51 */
52#define SUPER(__derived) (&(__derived)->base)
53
54
55struct pool_pb_manager
56{
57   struct pb_manager base;
58
59   _glthread_Mutex mutex;
60
61   size_t bufSize;
62   size_t bufAlign;
63
64   size_t numFree;
65   size_t numTot;
66
67   struct list_head free;
68
69   struct pb_buffer *buffer;
70   void *map;
71
72   struct pool_buffer *bufs;
73};
74
75
76static INLINE struct pool_pb_manager *
77pool_pb_manager(struct pb_manager *mgr)
78{
79   assert(mgr);
80   return (struct pool_pb_manager *)mgr;
81}
82
83
84struct pool_buffer
85{
86   struct pb_buffer base;
87
88   struct pool_pb_manager *mgr;
89
90   struct list_head head;
91
92   size_t start;
93};
94
95
96static INLINE struct pool_buffer *
97pool_buffer(struct pb_buffer *buf)
98{
99   assert(buf);
100   return (struct pool_buffer *)buf;
101}
102
103
104
105static void
106pool_buffer_destroy(struct pb_buffer *buf)
107{
108   struct pool_buffer *pool_buf = pool_buffer(buf);
109   struct pool_pb_manager *pool = pool_buf->mgr;
110
111   assert(pool_buf->base.base.refcount == 0);
112
113   _glthread_LOCK_MUTEX(pool->mutex);
114   LIST_ADD(&pool_buf->head, &pool->free);
115   pool->numFree++;
116   _glthread_UNLOCK_MUTEX(pool->mutex);
117}
118
119
120static void *
121pool_buffer_map(struct pb_buffer *buf, unsigned flags)
122{
123   struct pool_buffer *pool_buf = pool_buffer(buf);
124   struct pool_pb_manager *pool = pool_buf->mgr;
125   void *map;
126
127   _glthread_LOCK_MUTEX(pool->mutex);
128   map = (unsigned char *) pool->map + pool_buf->start;
129   _glthread_UNLOCK_MUTEX(pool->mutex);
130   return map;
131}
132
133
134static void
135pool_buffer_unmap(struct pb_buffer *buf)
136{
137   /* No-op */
138}
139
140
141static void
142pool_buffer_get_base_buffer(struct pb_buffer *buf,
143                            struct pb_buffer **base_buf,
144                            unsigned *offset)
145{
146   struct pool_buffer *pool_buf = pool_buffer(buf);
147   struct pool_pb_manager *pool = pool_buf->mgr;
148   pb_get_base_buffer(pool->buffer, base_buf, offset);
149   *offset += pool_buf->start;
150}
151
152
153static const struct pb_vtbl
154pool_buffer_vtbl = {
155      pool_buffer_destroy,
156      pool_buffer_map,
157      pool_buffer_unmap,
158      pool_buffer_get_base_buffer
159};
160
161
162static struct pb_buffer *
163pool_bufmgr_create_buffer(struct pb_manager *mgr,
164                          size_t size,
165                          const struct pb_desc *desc)
166{
167   struct pool_pb_manager *pool = pool_pb_manager(mgr);
168   struct pool_buffer *pool_buf;
169   struct list_head *item;
170
171   assert(size == pool->bufSize);
172   assert(pool->bufAlign % desc->alignment == 0);
173
174   _glthread_LOCK_MUTEX(pool->mutex);
175
176   if (pool->numFree == 0) {
177      _glthread_UNLOCK_MUTEX(pool->mutex);
178      debug_printf("warning: out of fixed size buffer objects\n");
179      return NULL;
180   }
181
182   item = pool->free.next;
183
184   if (item == &pool->free) {
185      _glthread_UNLOCK_MUTEX(pool->mutex);
186      debug_printf("error: fixed size buffer pool corruption\n");
187      return NULL;
188   }
189
190   LIST_DEL(item);
191   --pool->numFree;
192
193   _glthread_UNLOCK_MUTEX(pool->mutex);
194
195   pool_buf = LIST_ENTRY(struct pool_buffer, item, head);
196   assert(pool_buf->base.base.refcount == 0);
197   pool_buf->base.base.refcount = 1;
198   pool_buf->base.base.alignment = desc->alignment;
199   pool_buf->base.base.usage = desc->usage;
200
201   return SUPER(pool_buf);
202}
203
204
205static void
206pool_bufmgr_destroy(struct pb_manager *mgr)
207{
208   struct pool_pb_manager *pool = pool_pb_manager(mgr);
209   _glthread_LOCK_MUTEX(pool->mutex);
210
211   FREE(pool->bufs);
212
213   pb_unmap(pool->buffer);
214   pb_reference(&pool->buffer, NULL);
215
216   _glthread_UNLOCK_MUTEX(pool->mutex);
217
218   FREE(mgr);
219}
220
221
222struct pb_manager *
223pool_bufmgr_create(struct pb_manager *provider,
224                   size_t numBufs,
225                   size_t bufSize,
226                   const struct pb_desc *desc)
227{
228   struct pool_pb_manager *pool;
229   struct pool_buffer *pool_buf;
230   size_t i;
231
232   if(!provider)
233      return NULL;
234
235   pool = CALLOC_STRUCT(pool_pb_manager);
236   if (!pool)
237      return NULL;
238
239   pool->base.destroy = pool_bufmgr_destroy;
240   pool->base.create_buffer = pool_bufmgr_create_buffer;
241
242   LIST_INITHEAD(&pool->free);
243
244   pool->numTot = numBufs;
245   pool->numFree = numBufs;
246   pool->bufSize = bufSize;
247   pool->bufAlign = desc->alignment;
248
249   _glthread_INIT_MUTEX(pool->mutex);
250
251   pool->buffer = provider->create_buffer(provider, numBufs*bufSize, desc);
252   if (!pool->buffer)
253      goto failure;
254
255   pool->map = pb_map(pool->buffer,
256                          PIPE_BUFFER_USAGE_CPU_READ |
257                          PIPE_BUFFER_USAGE_CPU_WRITE);
258   if(!pool->map)
259      goto failure;
260
261   pool->bufs = (struct pool_buffer *)CALLOC(numBufs, sizeof(*pool->bufs));
262   if (!pool->bufs)
263      goto failure;
264
265   pool_buf = pool->bufs;
266   for (i = 0; i < numBufs; ++i) {
267      pool_buf->base.base.refcount = 0;
268      pool_buf->base.base.alignment = 0;
269      pool_buf->base.base.usage = 0;
270      pool_buf->base.base.size = bufSize;
271      pool_buf->base.vtbl = &pool_buffer_vtbl;
272      pool_buf->mgr = pool;
273      pool_buf->start = i * bufSize;
274      LIST_ADDTAIL(&pool_buf->head, &pool->free);
275      pool_buf++;
276   }
277
278   return SUPER(pool);
279
280failure:
281   if(pool->bufs)
282      FREE(pool->bufs);
283   if(pool->map)
284      pb_unmap(pool->buffer);
285   if(pool->buffer)
286      pb_reference(&pool->buffer, NULL);
287   if(pool)
288      FREE(pool);
289   return NULL;
290}
291