diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/util/bufpool.c')
-rw-r--r-- | src/VBox/GuestHost/OpenGL/util/bufpool.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/util/bufpool.c b/src/VBox/GuestHost/OpenGL/util/bufpool.c new file mode 100644 index 00000000..ed8dcde6 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/bufpool.c @@ -0,0 +1,194 @@ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include "cr_mem.h" +#include "cr_error.h" +#include "cr_bufpool.h" +#include <limits.h> + +/* + * New (version 1.4) buffer pool implementation. + * + * Now, each buffer in the pool can be a different size. + * We only return a buffer from crBufferPoolPop() if we have exactly + * the right size buffer. + * + * Note: the old implementation had a 'max buffers' parameter but it + * really wasn't good for anything since we always grew the buffer pool + * if we pushed a new buffer that would cause use to exceed the limit. + * That's gone now. + * + * We're just using a simple linked list here. Since we seldom have + * more than about 10-15 buffers in the pool, that's OK. A binary tree + * would be nicer though. + * + * MCH: BufferPoolPop will now return the smallest buffer in the pool that + * is >= to the size required. This fixes BufferPool overruns with lots + * of MTUs. + */ + + +#ifndef NULL +#define NULL ((void *) 0) +#endif + + +typedef struct buffer +{ + void *address; + unsigned int size; + struct buffer *next; +} Buffer; + + +struct CRBufferPool_t +{ + unsigned int maxBuffers; + int numBuffers; + struct buffer *head; +}; + + +int +crBufferPoolGetNumBuffers( CRBufferPool *pool ) +{ + if ( pool ) + return pool->numBuffers; + return 0; +} + +int +crBufferPoolGetMaxBuffers( CRBufferPool *pool ) +{ + if ( pool ) + return pool->maxBuffers; + return 0; +} + +CRBufferPool * +crBufferPoolInit( unsigned int maxBuffers ) +{ + CRBufferPool *pool = crCalloc(sizeof(CRBufferPool)); + if (pool) { + pool->head = NULL; + pool->maxBuffers = maxBuffers; + pool->numBuffers = 0; + } + return pool; +} + +void +crBufferPoolFree( CRBufferPool *pool ) +{ + Buffer *b, *next; + + for (b = pool->head; b; b = next) { + next = b->next; + crFree(b->address); + crFree(b); + } +} + +void +crBufferPoolCallbackFree(CRBufferPool *pool, CRBufferPoolDeleteCallback pfnDelete) +{ + Buffer *b, *next; + + CRASSERT(pfnDelete); + + for (b = pool->head; b; b = next) { + next = b->next; + (*pfnDelete)(b->address); + crFree(b); + } +} + +void +crBufferPoolPush( CRBufferPool *pool, void *buf, unsigned int bytes ) +{ + Buffer *b = crCalloc(sizeof(Buffer)); + if (b) { +#ifdef DEBUG + /* check that the buffer to push isn't already in the pool! */ + { + const Buffer *bd; + for (bd = pool->head; bd; bd = bd->next) { + CRASSERT(bd->address != buf); + } + } +#endif + + b->address = buf; + b->size = bytes; + b->next = pool->head; + pool->head = b; + pool->numBuffers++; + } +} + +void * +crBufferPoolPop( CRBufferPool *pool, unsigned int bytes ) +{ + Buffer *b, *prev, *prev_smallest; + unsigned int smallest = UINT_MAX; /* size of smallest buffer >= bytes */ + int i; + + prev = NULL; + prev_smallest = NULL; + for (b = pool->head, i=0; i<pool->numBuffers; b = b->next, i++) { + if (b->size == bytes) { + /* we found an exact size match! */ + void *p = b->address; + if (prev) { + prev->next = b->next; + } + else { + pool->head = b->next; + } + crFree(b); + pool->numBuffers--; + CRASSERT(pool->numBuffers >= 0); + return p; + } + else if (b->size >= bytes){ + /* We found a buffer that's large enough, but keep looking + * for a smaller one that's large enough. + */ + if (b->size < smallest) { + prev_smallest = prev; /* save ptr to previous! */ + smallest = b->size; + } + } + prev = b; + } + + if (smallest < UINT_MAX) { + /* we found the smallest buffer whose size is > bytes */ + void *p; + if (prev_smallest) { + b = prev_smallest->next; + } + else { + b = pool->head; + } + CRASSERT(b->size == smallest); + CRASSERT(b->size >= bytes); + p = b->address; + if (prev_smallest) { + prev_smallest->next = b->next; + } + else { + pool->head = b->next; + } + crFree(b); + pool->numBuffers--; + CRASSERT(pool->numBuffers >= 0); + return p; + } + + /* found no buffer large enough */ + return NULL; +} |