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