From b47836225185c8d2e2ccf3e191230304709d0a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fonseca?= Date: Fri, 23 Nov 2007 17:22:54 +0000 Subject: [PATCH] gallium: Reusable pipe buffer library. This is an optional library that winsys drivers can use to simplify memory management, and help meet the winsys interface requirements. --- src/mesa/pipe/Makefile | 5 +- src/mesa/pipe/pipebuffer/Makefile | 27 ++ src/mesa/pipe/pipebuffer/linked_list.h | 91 ++++++ src/mesa/pipe/pipebuffer/pb_buffer.c | 52 +++ src/mesa/pipe/pipebuffer/pb_buffer.h | 175 ++++++++++ src/mesa/pipe/pipebuffer/pb_buffer_client.c | 123 +++++++ src/mesa/pipe/pipebuffer/pb_buffer_fenced.c | 340 ++++++++++++++++++++ src/mesa/pipe/pipebuffer/pb_buffer_fenced.h | 138 ++++++++ src/mesa/pipe/pipebuffer/pb_buffer_handle.c | 182 +++++++++++ src/mesa/pipe/pipebuffer/pb_buffer_handle.h | 120 +++++++ src/mesa/pipe/pipebuffer/pb_buffer_malloc.c | 132 ++++++++ src/mesa/pipe/pipebuffer/pb_buffer_null.c | 98 ++++++ src/mesa/pipe/pipebuffer/pb_bufmgr.h | 114 +++++++ src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c | 128 ++++++++ src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c | 265 +++++++++++++++ src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c | 279 ++++++++++++++++ 16 files changed, 2266 insertions(+), 3 deletions(-) create mode 100644 src/mesa/pipe/pipebuffer/Makefile create mode 100644 src/mesa/pipe/pipebuffer/linked_list.h create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer.c create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer.h create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_client.c create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_fenced.c create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_fenced.h create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_handle.c create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_handle.h create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_malloc.c create mode 100644 src/mesa/pipe/pipebuffer/pb_buffer_null.c create mode 100644 src/mesa/pipe/pipebuffer/pb_bufmgr.h create mode 100644 src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c create mode 100644 src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c create mode 100644 src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c diff --git a/src/mesa/pipe/Makefile b/src/mesa/pipe/Makefile index a9dc393417d..2bf7318d59a 100644 --- a/src/mesa/pipe/Makefile +++ b/src/mesa/pipe/Makefile @@ -1,4 +1,3 @@ - TOP = ../../.. include $(TOP)/configs/current @@ -7,7 +6,7 @@ ifeq ($(CONFIG_NAME), linux-cell) CELL_DIR = cell endif -SUBDIRS = softpipe i915simple failover $(CELL_DIR) +SUBDIRS = softpipe i915simple failover pipebuffer $(CELL_DIR) default: subdirs @@ -22,4 +21,4 @@ subdirs: clean: - rm -f `find . -name \*.[oa]` \ No newline at end of file + rm -f `find . -name \*.[oa]` diff --git a/src/mesa/pipe/pipebuffer/Makefile b/src/mesa/pipe/pipebuffer/Makefile new file mode 100644 index 00000000000..061d8a060fe --- /dev/null +++ b/src/mesa/pipe/pipebuffer/Makefile @@ -0,0 +1,27 @@ + +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = pipebuffer + + +DRIVER_SOURCES = \ + pb_buffer.c \ + pb_buffer_client.c \ + pb_buffer_handle.c \ + pb_buffer_fenced.c \ + pb_buffer_malloc.c \ + pb_buffer_null.c \ + pb_bufmgr_fenced.c \ + pb_bufmgr_mm.c \ + pb_bufmgr_pool.c + +C_SOURCES = \ + $(DRIVER_SOURCES) + +ASM_SOURCES = + +include ../Makefile.template + +symlinks: + diff --git a/src/mesa/pipe/pipebuffer/linked_list.h b/src/mesa/pipe/pipebuffer/linked_list.h new file mode 100644 index 00000000000..e99817fb130 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/linked_list.h @@ -0,0 +1,91 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ + +#ifndef LINKED_LIST_H_ +#define LINKED_LIST_H_ + + +#include + + +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + + +#define LIST_INITHEAD(__item) \ + do { \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define LIST_ADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define LIST_ADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define LIST_DEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define LIST_DELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + + +#endif /*LINKED_LIST_H_*/ diff --git a/src/mesa/pipe/pipebuffer/pb_buffer.c b/src/mesa/pipe/pipebuffer/pb_buffer.c new file mode 100644 index 00000000000..99c960b6979 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer.c @@ -0,0 +1,52 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Buffer implementation. + * + * \author José Fonseca + */ + + +#include "pb_buffer.h" + + +void +buffer_reference(struct pipe_buffer **dst, + struct pipe_buffer *src) +{ + if(*dst != src) { + if (src) + src->vtbl->reference(src); + + if (*dst) + (*dst)->vtbl->release(*dst); + + *dst = src; + } +} diff --git a/src/mesa/pipe/pipebuffer/pb_buffer.h b/src/mesa/pipe/pipebuffer/pb_buffer.h new file mode 100644 index 00000000000..05235313953 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer.h @@ -0,0 +1,175 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Generic code for buffers. + * + * Behind a pipe buffle handle there can be DMA buffers, client (or user) + * buffers, regular malloced buffers, etc. This file provides an abstract base + * buffer handle that allows the driver to cope with all those kinds of buffers + * in a more flexible way. + * + * There is no obligation of a winsys driver to use this library. And a pipe + * driver should be completly agnostic about it. + * + * \author José Fonseca + */ + +#ifndef PB_BUFFER_H_ +#define PB_BUFFER_H_ + + +#include +#include + + +struct pipe_buffer_vtbl; + + +/** + * Base class for all pipe buffers. + */ +struct pipe_buffer +{ + /** + * Pointer to the virtual function table. + * + * Avoid accessing this table directly. Use the inline functions below + * instead to avoid mistakes. + */ + const struct pipe_buffer_vtbl *vtbl; +}; + + +/** + * Virtual function table for the buffer storage operations. + * + * Note that creation is not done through this table. + */ +struct pipe_buffer_vtbl +{ + /** + * Add a reference to the buffer. + * + * This method can be a no-op for buffers that don't need reference + * counting. + */ + void (*reference)( struct pipe_buffer *buf ); + + /** + * Release a reference to this buffer and destroy it. + */ + void (*release)( struct pipe_buffer *buf ); + + /** + * Map the entire data store of a buffer object into the client's address. + * flags is bitmask of PIPE_BUFFER_FLAG_READ/WRITE. + */ + void *(*map)( struct pipe_buffer *buf, + unsigned flags ); + + void (*unmap)( struct pipe_buffer *buf ); + + /** + * Get the base buffer and the offset. + * + * A buffer can be subdivided in smaller buffers. This method should return + * the underlaying buffer, and the relative offset. + * + * Buffers without an underlaying base buffer should return themselves, with + * a zero offset. + * + * Note that this will increase the reference count of the base buffer. + */ + void (*get_base_buffer)( struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset ); +}; + + +/** *dst = src with reference counting */ +void +buffer_reference(struct pipe_buffer **dst, + struct pipe_buffer *src); + + +static inline void +buffer_release(struct pipe_buffer *buf) +{ + assert(buf); + buf->vtbl->release(buf); +} + + +static inline void * +buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + assert(buf); + return buf->vtbl->map(buf, flags); +} + + +static inline void +buffer_unmap(struct pipe_buffer *buf) +{ + assert(buf); + buf->vtbl->unmap(buf); +} + + +static inline void +buffer_get_base_buffer( struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset ) +{ + buf->vtbl->get_base_buffer(buf, base_buf, offset); +} + + +/** Placeholder for empty buffers. */ +extern struct pipe_buffer null_buffer; + + +/** + * Client buffers (also designated as user buffers) are just for convenience + * of the state tracker, so that it can masquerade its own data as a buffer. + */ +struct pipe_buffer * +client_buffer_create(void *data); + + +/** + * Malloc-based buffer to store data that can't be used by the graphics + * hardware. + */ +struct pipe_buffer * +malloc_buffer_create(unsigned size); + + +#endif /*PB_BUFFER_H_*/ diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_client.c b/src/mesa/pipe/pipebuffer/pb_buffer_client.c new file mode 100644 index 00000000000..bb7f5a9a947 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_client.c @@ -0,0 +1,123 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Implementation of client buffer (also designated as "user buffers"), which + * are just state-tracker owned data masqueraded as buffers. + * + * \author José Fonseca + */ + + +#include "pb_buffer.h" + + +struct client_buffer +{ + struct pipe_buffer base; + void *data; +}; + + +extern const struct pipe_buffer_vtbl client_buffer_vtbl; + + +static inline struct client_buffer * +client_buffer(struct pipe_buffer *buf) +{ + assert(buf); + assert(buf->vtbl == &client_buffer_vtbl); + return (struct client_buffer *)buf; +} + + +static void +client_buffer_reference(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +client_buffer_release(struct pipe_buffer *buf) +{ + assert(buf); + free(buf); +} + + +static void * +client_buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + return client_buffer(buf)->data; +} + + +static void +client_buffer_unmap(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +client_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + *base_buf = buf; + *offset = 0; +} + + +const struct pipe_buffer_vtbl +client_buffer_vtbl = { + client_buffer_reference, + client_buffer_release, + client_buffer_map, + client_buffer_unmap, + client_buffer_get_base_buffer +}; + + +struct pipe_buffer * +client_buffer_create(void *data) +{ + struct client_buffer *buf; + + buf = (struct client_buffer *)malloc(sizeof(struct client_buffer)); + if(!buf) + return NULL; + + buf->base.vtbl = &client_buffer_vtbl; + + buf->data = data; + + return &buf->base; +} diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_fenced.c b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.c new file mode 100644 index 00000000000..c5a06c545e1 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.c @@ -0,0 +1,340 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Implementation of fenced buffers. + * + * \author José Fonseca + * \author Thomas Hellström + */ + + +#include +#include +#include + +#include "main/imports.h" +#include "glapi/glthread.h" +#include "linked_list.h" + +#include "p_winsys.h" + +#include "pb_buffer.h" +#include "pb_buffer_fenced.h" + + +/** + * Convenience macro (type safe). + */ +#define SUPER(__derived) (&(__derived)->base) + + +struct fenced_buffer_list +{ + _glthread_Mutex mutex; + + struct pipe_winsys *winsys; + + size_t numDelayed; + size_t checkDelayed; + + struct list_head delayed; +}; + + +/** + * Wrapper around a pipe buffer which adds fencing and reference counting. + */ +struct fenced_buffer +{ + struct pipe_buffer base; + + struct pipe_buffer *buffer; + + unsigned refcount; + struct pipe_fence_handle *fence; + + struct list_head head; + struct fenced_buffer_list *list; +}; + + +static inline struct fenced_buffer * +fenced_buffer(struct pipe_buffer *buf) +{ + assert(buf); + assert(buf->vtbl == &fenced_buffer_vtbl); + return (struct fenced_buffer *)buf; +} + + +static void +_fenced_buffer_destroy(struct fenced_buffer *fenced_buf) +{ + buffer_release(fenced_buf->buffer); + free(fenced_buf); +} + + +static void +_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, + int wait) +{ + struct pipe_winsys *winsys = fenced_list->winsys; + struct fenced_buffer *fenced_buf; + struct list_head *list, *prev; + int signaled = -1; + int i; + + list = fenced_list->delayed.next; + + if (fenced_list->numDelayed > 3) { + for (i = 0; i < fenced_list->numDelayed; i += 3) { + list = list->next; + } + } + + prev = list->prev; + for (; list != &fenced_list->delayed; list = prev, prev = list->prev) { + + fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head); + + if (signaled != 0) { + if (wait) { + signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0); + } + else { + signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0); + } + } + + if (signaled != 0) + /* XXX: we are assuming that buffers are freed in the same order they + * are fenced which may not always be true... + */ + break; + + winsys->fence_reference(winsys, &fenced_buf->fence, NULL); + + LIST_DEL(list); + fenced_list->numDelayed--; + + _fenced_buffer_destroy(fenced_buf); + } +} + + +static void +fenced_buffer_reference(struct pipe_buffer *buf) +{ + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + struct fenced_buffer_list *fenced_list = fenced_buf->list; + + _glthread_LOCK_MUTEX(fenced_list->mutex); + fenced_buf->refcount++; + _glthread_UNLOCK_MUTEX(fenced_list->mutex); +} + + +static void +fenced_buffer_release(struct pipe_buffer *buf) +{ + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + struct fenced_buffer_list *fenced_list = fenced_buf->list; + + _glthread_LOCK_MUTEX(fenced_list->mutex); + + fenced_buf->refcount--; + if(!fenced_buf->refcount) { + if (fenced_buf->fence) { + LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed); + fenced_list->numDelayed++; + } + else { + _fenced_buffer_destroy(fenced_buf); + } + + if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0) + _fenced_buffer_list_check_free(fenced_list, 0); + } + + _glthread_UNLOCK_MUTEX(fenced_list->mutex); +} + + +static void * +fenced_buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + return buffer_map(fenced_buf->buffer, flags); +} + + +static void +fenced_buffer_unmap(struct pipe_buffer *buf) +{ + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + buffer_unmap(fenced_buf->buffer); +} + + +static void +fenced_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + buffer_get_base_buffer(fenced_buf->buffer, base_buf, offset); +} + + +const struct pipe_buffer_vtbl +fenced_buffer_vtbl = { + fenced_buffer_reference, + fenced_buffer_release, + fenced_buffer_map, + fenced_buffer_unmap, + fenced_buffer_get_base_buffer +}; + + +struct pipe_buffer * +fenced_buffer_create(struct fenced_buffer_list *fenced_list, + struct pipe_buffer *buffer) +{ + struct fenced_buffer *buf; + + buf = (struct fenced_buffer *)calloc(1, sizeof(struct fenced_buffer)); + if(!buf) + return NULL; + + buf->base.vtbl = &fenced_buffer_vtbl; + buf->buffer = buffer; + buf->refcount = 1; + buf->list = fenced_list; + + return &buf->base; +} + + +void +buffer_fence(struct pipe_buffer *buf, + struct pipe_fence_handle *fence) +{ + if(buf->vtbl == &fenced_buffer_vtbl) { + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + struct fenced_buffer_list *fenced_list = fenced_buf->list; + struct pipe_winsys *winsys = fenced_list->winsys; + + _glthread_LOCK_MUTEX(fenced_list->mutex); + winsys->fence_reference(winsys, &fenced_buf->fence, fence); + _glthread_UNLOCK_MUTEX(fenced_list->mutex); + } + else + assert(0); +} + + +void +buffer_unfence(struct pipe_buffer *buf) +{ + buffer_fence(buf, NULL); +} + + +int +buffer_finish(struct pipe_buffer *buf, + unsigned flag) +{ + if(buf->vtbl == &fenced_buffer_vtbl) { + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + if(fenced_buf->fence) { + struct fenced_buffer_list *fenced_list = fenced_buf->list; + struct pipe_winsys *winsys = fenced_list->winsys; + return winsys->fence_finish(winsys, fenced_buf->fence, flag); + } + } + + return 0; +} + + +struct fenced_buffer_list * +fenced_buffer_list_create(struct pipe_winsys *winsys) +{ + struct fenced_buffer_list *fenced_list; + + fenced_list = (struct fenced_buffer_list *)calloc(1, sizeof(*fenced_list)); + if (!fenced_list) + return NULL; + + fenced_list->winsys = winsys; + + LIST_INITHEAD(&fenced_list->delayed); + + fenced_list->numDelayed = 0; + + /* TODO: don't hard code this */ + fenced_list->checkDelayed = 5; + + _glthread_INIT_MUTEX(fenced_list->mutex); + + return fenced_list; +} + + +void +fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, + int wait) +{ + _glthread_LOCK_MUTEX(fenced_list->mutex); + _fenced_buffer_list_check_free(fenced_list, wait); + _glthread_UNLOCK_MUTEX(fenced_list->mutex); +} + + +void +fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list) +{ + _glthread_LOCK_MUTEX(fenced_list->mutex); + + /* Wait on outstanding fences */ + while (fenced_list->numDelayed) { + _glthread_UNLOCK_MUTEX(fenced_list->mutex); + sched_yield(); + _fenced_buffer_list_check_free(fenced_list, GL_TRUE); + _glthread_LOCK_MUTEX(fenced_list->mutex); + } + + _glthread_UNLOCK_MUTEX(fenced_list->mutex); + + free(fenced_list); +} + + diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_fenced.h b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.h new file mode 100644 index 00000000000..d12428e216b --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.h @@ -0,0 +1,138 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Buffer fencing. + * + * "Fenced buffers" is actually a misnomer. They should be referred as + * "fenceable buffers", i.e, buffers that can be fenced, but I couldn't find + * the word "fenceable" in the dictionary. + * + * A "fenced buffer" is a decorator around a normal buffer, which adds two + * special properties: + * - the ability for the destruction to be delayed by a fence; + * - reference counting. + * + * Usually DMA buffers have a life-time that will extend the life-time of its + * handle. The end-of-life is dictated by the fence signalling. + * + * Between the handle's destruction, and the fence signalling, the buffer is + * stored in a fenced buffer list. + * + * \author José Fonseca + */ + +#ifndef PB_BUFFER_FENCED_H_ +#define PB_BUFFER_FENCED_H_ + + +#include + + +struct pipe_winsys; +struct pipe_buffer; +struct pipe_fence_handle; + + +/** + * List of buffers which are awaiting fence signalling. + */ +struct fenced_buffer_list; + + +/** + * The fenced buffer's virtual function table. + * + * NOTE: Made public for debugging purposes. + */ +extern const struct pipe_buffer_vtbl fenced_buffer_vtbl; + + +/** + * Create a fenced buffer list. + * + * See also fenced_bufmgr_create for a more convenient way to use this. + */ +struct fenced_buffer_list * +fenced_buffer_list_create(struct pipe_winsys *winsys); + + +/** + * Walk the fenced buffer list to check and free signalled buffers. + */ +void +fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, + int wait); + +void +fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list); + + +/** + * Wrap a buffer in a fenced buffer. + * + * NOTE: this will not increase the buffer reference count. + */ +struct pipe_buffer * +fenced_buffer_create(struct fenced_buffer_list *fenced, + struct pipe_buffer *buffer); + + +/** + * Set a buffer's fence. + * + * NOTE: Although it takes a generic pipe buffer argument, it will fail + * on everything but buffers returned by fenced_buffer_create. + */ +void +buffer_fence(struct pipe_buffer *buf, + struct pipe_fence_handle *fence); + + +/** + * Remove the buffer's fence. + * + * NOTE: Although it takes a generic pipe buffer argument, it will fail + * on everything but buffers returned by fenced_buffer_create. + */ +void +buffer_unfence(struct pipe_buffer *buf); + + +/** + * Wait for the buffer fence to signal. + * + * See also pipe_winsys::fence_finish(). + */ +int +buffer_finish(struct pipe_buffer *buf, + unsigned flag); + + + +#endif /*PB_BUFFER_FENCED_H_*/ diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_handle.c b/src/mesa/pipe/pipebuffer/pb_buffer_handle.c new file mode 100644 index 00000000000..5a5eaee7ac7 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_handle.c @@ -0,0 +1,182 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Drop-in implementation of the winsys driver functions for buffer handles. + * + * \author José Fonseca + */ + + +#include +#include + +#include "pipe/p_winsys.h" +#include "pipe/p_defines.h" + +#include "pb_buffer.h" +#include "pb_buffer_handle.h" + + +static struct pipe_buffer_handle * +buffer_handle_create(struct pipe_winsys *winsys, + unsigned alignment, + unsigned flags, + unsigned hint) +{ + struct pipe_buffer_handle *handle; + + handle = (struct pipe_buffer_handle *)malloc(sizeof(struct pipe_buffer_handle)); + if(!handle) + return NULL; + + handle->refcount = 1; + handle->alignment = alignment; + handle->flags = flags; + handle->hint = hint; + + handle->buf = &null_buffer; + + return handle; +} + + +static struct pipe_buffer_handle * +buffer_handle_create_user(struct pipe_winsys *winsys, + void *data, unsigned size) +{ + struct pipe_buffer_handle *handle; + struct pipe_buffer *buf; + + handle = buffer_handle_create(winsys, 1, 0, 0); + if(!handle) + return NULL; + + buf = client_buffer_create(data); + if(!buf) { + free(handle); + return NULL; + } + + buffer_handle_data(handle, buf); + + return handle; +} + + +static void * +buffer_handle_map(struct pipe_winsys *winsys, + struct pipe_buffer_handle *handle, + unsigned flags) +{ + return buffer_map(handle->buf, flags); +} + + +static void +buffer_handle_unmap(struct pipe_winsys *winsys, + struct pipe_buffer_handle *handle) +{ + buffer_unmap(handle->buf); +} + + +static void +buffer_handle_reference(struct pipe_winsys *winsys, + struct pipe_buffer_handle **dst, + struct pipe_buffer_handle *src) +{ + /* XXX: should this be thread safe? */ + + if (src) { + src->refcount++; + } + + if (*dst) { + (*dst)->refcount--; + if ((*dst)->refcount == 0) { + buffer_release((*dst)->buf); + free(*dst); + } + } + + *dst = src; +} + + +static int +buffer_handle_subdata(struct pipe_winsys *winsys, + struct pipe_buffer_handle *handle, + unsigned long offset, + unsigned long size, + const void *data) +{ + void *map; + assert(handle); + assert(data); + map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_WRITE); + if(map) { + memcpy((char *)map + offset, data, size); + buffer_handle_unmap(winsys, handle); + return 0; + } + return -1; +} + + +static int +buffer_handle_get_subdata(struct pipe_winsys *winsys, + struct pipe_buffer_handle *handle, + unsigned long offset, + unsigned long size, + void *data) +{ + void *map; + assert(handle); + assert(data); + map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_READ); + if(map) { + memcpy(data, (char *)map + offset, size); + buffer_handle_unmap(winsys, handle); + return 0; + } + return -1; +} + + +void +buffer_handle_init_winsys(struct pipe_winsys *winsys) +{ + winsys->buffer_create = buffer_handle_create; + winsys->user_buffer_create = buffer_handle_create_user; + winsys->buffer_map = buffer_handle_map; + winsys->buffer_unmap = buffer_handle_unmap; + winsys->buffer_reference = buffer_handle_reference; + winsys->buffer_subdata = buffer_handle_subdata; + winsys->buffer_get_subdata = buffer_handle_get_subdata; +} diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_handle.h b/src/mesa/pipe/pipebuffer/pb_buffer_handle.h new file mode 100644 index 00000000000..076eec2fdc6 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_handle.h @@ -0,0 +1,120 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Buffer handle interface. + * + * \author José Fonseca + */ + +#ifndef PB_BUFFER_HANDLE_H_ +#define PB_BUFFER_HANDLE_H_ + + +#include + +#include "pb_buffer.h" + + +/** + * Buffer handle. + * + * The buffer handle and the buffer data storage are separate entities. This + * is modelled after ARB_vertex_buffer_object, which is the interface that + * Gallium requires. See p_winsys.h for more information. + */ +struct pipe_buffer_handle +{ + /** Reference count */ + unsigned refcount; + + /** Allocation characteristics */ + unsigned alignment; + unsigned flags; + unsigned hint; + + /** + * The actual buffer. + * + * It should never be NULL. Use null_buffer instead. + */ + struct pipe_buffer *buf; +}; + + +/** + * Set buffer storage. + * + * NOTE: this will not increase the buffer reference count. + */ +static inline void +buffer_handle_data(struct pipe_buffer_handle *handle, + struct pipe_buffer *buf) +{ + assert(handle); + assert(handle->buf); + buffer_release(handle->buf); + assert(buf); + handle->buf = buf; +} + + +static inline void +buffer_handle_clear(struct pipe_buffer_handle *handle) +{ + buffer_handle_data(handle, &null_buffer); +} + + +static inline int +buffer_handle_has_data(struct pipe_buffer_handle *handle) { + assert(handle); + assert(handle->buf); + return handle->buf != &null_buffer; +} + + +/** + * Fill in the pipe_winsys' buffer-related callbacks. + * + * Specifically, the fullfilled functions are: + * - buffer_create + * - user_buffer_create + * - buffer_map + * - buffer_unmap + * - buffer_reference + * - buffer_subdata + * - buffer_get_subdata + * + * NOTE: buffer_data is left untouched. + */ +void +buffer_handle_init_winsys(struct pipe_winsys *winsys); + + +#endif /*PB_BUFFER_HANDLE_H_*/ diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_malloc.c b/src/mesa/pipe/pipebuffer/pb_buffer_malloc.c new file mode 100644 index 00000000000..65ad51e1e7e --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_malloc.c @@ -0,0 +1,132 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Implementation of malloc-based buffers to store data that can't be processed + * by the hardware. + * + * \author José Fonseca + */ + + +#include +#include + +#include "pb_buffer.h" + + +struct malloc_buffer +{ + struct pipe_buffer base; + void *data; +}; + + +extern const struct pipe_buffer_vtbl malloc_buffer_vtbl; + +static inline struct malloc_buffer * +malloc_buffer(struct pipe_buffer *buf) +{ + assert(buf); + assert(buf->vtbl == &malloc_buffer_vtbl); + return (struct malloc_buffer *)buf; +} + + +static void +malloc_buffer_reference(struct pipe_buffer *buf) +{ + /* no-op */ +} + + +static void +malloc_buffer_release(struct pipe_buffer *buf) +{ + free(malloc_buffer(buf)->data); + free(buf); +} + + +static void * +malloc_buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + return malloc_buffer(buf)->data; +} + + +static void +malloc_buffer_unmap(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +malloc_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + *base_buf = buf; + *offset = 0; +} + + +const struct pipe_buffer_vtbl +malloc_buffer_vtbl = { + malloc_buffer_reference, + malloc_buffer_release, + malloc_buffer_map, + malloc_buffer_unmap, + malloc_buffer_get_base_buffer +}; + + +struct pipe_buffer * +malloc_buffer_create(unsigned size) +{ + struct malloc_buffer *buf; + + /* TODO: accept an alignment parameter */ + /* TODO: do a single allocation */ + + buf = (struct malloc_buffer *)malloc(sizeof(struct malloc_buffer)); + if(!buf) + return NULL; + + buf->base.vtbl = &malloc_buffer_vtbl; + + buf->data = malloc(size); + if(!buf->data) { + free(buf); + return NULL; + } + + return &buf->base; +} diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_null.c b/src/mesa/pipe/pipebuffer/pb_buffer_null.c new file mode 100644 index 00000000000..a356c6b2d5c --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_buffer_null.c @@ -0,0 +1,98 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Null buffer implementation. + * + * We have a special null buffer object so that we can safely call buffer + * operations without having to check whether the buffer pointer is null or not. + * + * \author José Fonseca + */ + + +#include "pipe/p_winsys.h" +#include "pipe/p_defines.h" + +#include "pb_buffer.h" + + +static void +null_buffer_reference(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +null_buffer_release(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void * +null_buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + assert(0); + return NULL; +} + + +static void +null_buffer_unmap(struct pipe_buffer *buf) +{ + assert(0); +} + + +static void +null_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + *base_buf = buf; + *offset = 0; +} + + +const struct pipe_buffer_vtbl +pipe_buffer_vtbl = { + null_buffer_reference, + null_buffer_release, + null_buffer_map, + null_buffer_unmap, + null_buffer_get_base_buffer +}; + + +struct pipe_buffer +null_buffer = { + &pipe_buffer_vtbl +}; diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr.h b/src/mesa/pipe/pipebuffer/pb_bufmgr.h new file mode 100644 index 00000000000..0e6c3a8d371 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_bufmgr.h @@ -0,0 +1,114 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Buffer management. + * + * A buffer manager does only one basic thing: it creates buffers. Actually, + * "buffer factory" would probably a more accurate description. + * + * You can chain buffer managers so that you can have a finer grained memory + * management and pooling. + * + * For example, for a simple batch buffer manager you would chain: + * - the native buffer manager, which provides DMA memory from the graphics + * memory space; + * - the pool buffer manager, which keep around a pool of equally sized buffers + * to avoid latency associated with the native buffer manager; + * - the fenced buffer manager, which will delay buffer destruction until the + * the moment the card finishing processing it. + * + * \author José Fonseca + */ + +#ifndef PB_BUFMGR_H_ +#define PB_BUFMGR_H_ + + +#include + + +struct pipe_buffer; +struct pipe_winsys; + + +/** + * Abstract base class for all buffer managers. + */ +struct buffer_manager +{ + /* XXX: we will likely need more allocation flags */ + struct pipe_buffer * + (*create_buffer)( struct buffer_manager *mgr, + size_t size); + + void + (*destroy)( struct buffer_manager *mgr ); +}; + + +/** + * Static buffer pool manager. + * + * Manages the allocation of equally sized buffers. It does so by allocating + * a single big buffer and divide it equally sized buffers. + * + * It is meant to manage the allocation of batch buffer pools. + */ +struct buffer_manager * +pool_bufmgr_create(struct buffer_manager *provider, + size_t n, size_t size); + + +/** + * Wraper around the old memory manager. + * + * It managers buffers of different sizes. It does so by allocating a buffer + * with the size of the heap, and then using the old mm memory manager to manage + * that heap. + */ +struct buffer_manager * +mm_bufmgr_create(struct buffer_manager *provider, + size_t size, size_t align2); + + +/** + * Fenced buffer manager. + * + * This manager is just meant for convenience. It wraps the buffers returned + * by another manager in fenced buffers, so that + * + * NOTE: the buffer manager that provides the buffers will be destroyed + * at the same time. + */ +struct buffer_manager * +fenced_bufmgr_create(struct buffer_manager *provider, + struct pipe_winsys *winsys); + + +#endif /*PB_BUFMGR_H_*/ diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c new file mode 100644 index 00000000000..defd8e4df78 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c @@ -0,0 +1,128 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +/** + * \file + * A buffer manager that wraps buffers in fenced buffers. + * + * \author José Fonseca + */ + + +#include +#include + +#include "pb_buffer.h" +#include "pb_buffer_fenced.h" +#include "pb_bufmgr.h" + + +struct fenced_buffer_manager +{ + struct buffer_manager base; + + struct buffer_manager *provider; + + struct fenced_buffer_list *fenced_list; +}; + + +static inline struct fenced_buffer_manager * +fenced_buffer_manager(struct buffer_manager *mgr) +{ + assert(mgr); + return (struct fenced_buffer_manager *)mgr; +} + + +static struct pipe_buffer * +fenced_bufmgr_create_buffer(struct buffer_manager *mgr, size_t size) +{ + struct fenced_buffer_manager *fenced_mgr = fenced_buffer_manager(mgr); + struct pipe_buffer *buf; + struct pipe_buffer *fenced_buf; + + /* check for free buffers before allocating new ones */ + fenced_buffer_list_check_free(fenced_mgr->fenced_list, 0); + + buf = fenced_mgr->provider->create_buffer(fenced_mgr->provider, size); + if(!buf) { + /* try harder to get a buffer */ + fenced_buffer_list_check_free(fenced_mgr->fenced_list, 1); + + buf = fenced_mgr->provider->create_buffer(fenced_mgr->provider, size); + if(!buf) { + /* give up */ + return NULL; + } + } + + fenced_buf = fenced_buffer_create(fenced_mgr->fenced_list, buf); + if(!fenced_buf) { + buffer_release(buf); + } + + return fenced_buf; +} + + +static void +fenced_bufmgr_destroy(struct buffer_manager *mgr) +{ + struct fenced_buffer_manager *fenced_mgr = fenced_buffer_manager(mgr); + + fenced_buffer_list_destroy(fenced_mgr->fenced_list); + + fenced_mgr->provider->destroy(fenced_mgr->provider); + + free(fenced_mgr); +} + + +struct buffer_manager * +fenced_bufmgr_create(struct buffer_manager *provider, + struct pipe_winsys *winsys) +{ + struct fenced_buffer_manager *fenced_mgr; + + fenced_mgr = (struct fenced_buffer_manager *)calloc(1, sizeof(*fenced_mgr)); + if (!fenced_mgr) + return NULL; + + fenced_mgr->base.destroy = fenced_bufmgr_destroy; + fenced_mgr->base.create_buffer = fenced_bufmgr_create_buffer; + + fenced_mgr->provider = provider; + fenced_mgr->fenced_list = fenced_buffer_list_create(winsys); + if(!fenced_mgr->fenced_list) { + free(fenced_mgr); + return NULL; + } + + return &fenced_mgr->base; +} diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c new file mode 100644 index 00000000000..8e6dcf1116b --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c @@ -0,0 +1,265 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \file + * Buffer manager using the old texture memory manager. + * + * \author José Fonseca + */ + + +#include +#include +#include + +#include "main/imports.h" +#include "glapi/glthread.h" +#include "main/mm.h" +#include "linked_list.h" + +#include "p_defines.h" +#include "pb_buffer.h" +#include "pb_bufmgr.h" + + +/** + * Convenience macro (type safe). + */ +#define SUPER(__derived) (&(__derived)->base) + + +struct mm_buffer_manager +{ + struct buffer_manager base; + + _glthread_Mutex mutex; + + size_t size; + struct mem_block *heap; + + size_t align2; + + struct pipe_buffer *buffer; + void *map; +}; + + +static inline struct mm_buffer_manager * +mm_buffer_manager(struct buffer_manager *mgr) +{ + assert(mgr); + return (struct mm_buffer_manager *)mgr; +} + + +struct mm_buffer +{ + struct pipe_buffer base; + + struct mm_buffer_manager *mgr; + + struct mem_block *block; +}; + + +static inline struct mm_buffer * +mm_buffer(struct pipe_buffer *buf) +{ + assert(buf); + return (struct mm_buffer *)buf; +} + + +static void +mm_buffer_reference(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +mm_buffer_release(struct pipe_buffer *buf) +{ + struct mm_buffer *mm_buf = mm_buffer(buf); + struct mm_buffer_manager *mm = mm_buf->mgr; + + _glthread_LOCK_MUTEX(mm->mutex); + mmFreeMem(mm_buf->block); + free(buf); + _glthread_UNLOCK_MUTEX(mm->mutex); +} + + +static void * +mm_buffer_map(struct pipe_buffer *buf, + unsigned flags) +{ + struct mm_buffer *mm_buf = mm_buffer(buf); + struct mm_buffer_manager *mm = mm_buf->mgr; + + return (unsigned char *) mm->map + mm_buf->block->ofs; +} + + +static void +mm_buffer_unmap(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +mm_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + struct mm_buffer *mm_buf = mm_buffer(buf); + struct mm_buffer_manager *mm = mm_buf->mgr; + buffer_get_base_buffer(mm->buffer, base_buf, offset); + *offset += mm_buf->block->ofs; +} + + +static const struct pipe_buffer_vtbl +mm_buffer_vtbl = { + mm_buffer_reference, + mm_buffer_release, + mm_buffer_map, + mm_buffer_unmap, + mm_buffer_get_base_buffer +}; + + +static struct pipe_buffer * +mm_bufmgr_create_buffer(struct buffer_manager *mgr, + size_t size) +{ + struct mm_buffer_manager *mm = mm_buffer_manager(mgr); + struct mm_buffer *mm_buf; + + _glthread_LOCK_MUTEX(mm->mutex); + + mm_buf = (struct mm_buffer *)malloc(sizeof(*mm_buf)); + if (!mm_buf) { + _glthread_UNLOCK_MUTEX(mm->mutex); + return NULL; + } + + mm_buf->base.vtbl = &mm_buffer_vtbl; + + mm_buf->mgr = mm; + + mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0); + if(!mm_buf->block) { + fprintf(stderr, "warning: heap full\n"); +#if 0 + mmDumpMemInfo(mm->heap); +#endif + + mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0); + if(!mm_buf->block) { + assert(0); + free(mm_buf); + _glthread_UNLOCK_MUTEX(mm->mutex); + return NULL; + } + } + + /* Some sanity checks */ + assert(0 <= mm_buf->block->ofs && mm_buf->block->ofs < mm->size); + assert(size <= mm_buf->block->size && mm_buf->block->ofs + mm_buf->block->size <= mm->size); + + _glthread_UNLOCK_MUTEX(mm->mutex); + return SUPER(mm_buf); +} + + +static void +mm_bufmgr_destroy(struct buffer_manager *mgr) +{ + struct mm_buffer_manager *mm = mm_buffer_manager(mgr); + + _glthread_LOCK_MUTEX(mm->mutex); + + mmDestroy(mm->heap); + + buffer_unmap(mm->buffer); + buffer_release(mm->buffer); + + _glthread_UNLOCK_MUTEX(mm->mutex); + + free(mgr); +} + + +struct buffer_manager * +mm_bufmgr_create(struct buffer_manager *provider, + size_t size, size_t align2) +{ + struct mm_buffer_manager *mm; + + mm = (struct mm_buffer_manager *)calloc(1, sizeof(*mm)); + if (!mm) + return NULL; + + assert(provider); + assert(provider->create_buffer); + mm->base.create_buffer = mm_bufmgr_create_buffer; + mm->base.destroy = mm_bufmgr_destroy; + + mm->size = size; + mm->align2 = align2; /* 64-byte alignment */ + + _glthread_INIT_MUTEX(mm->mutex); + + mm->buffer = provider->create_buffer(provider, size); + if (!mm->buffer) + goto failure; + + mm->map = buffer_map(mm->buffer, + PIPE_BUFFER_FLAG_READ | PIPE_BUFFER_FLAG_WRITE ); + if(!mm->map) + goto failure; + + mm->heap = mmInit(0, size); + if (!mm->heap) + goto failure; + + return SUPER(mm); + +failure: +if(mm->heap) + mmDestroy(mm->heap); + if(mm->map) + buffer_unmap(mm->buffer); + if(mm->buffer) + buffer_release(mm->buffer); + if(mm) + free(mm); + return NULL; +} diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c new file mode 100644 index 00000000000..ee6fa625004 --- /dev/null +++ b/src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c @@ -0,0 +1,279 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +/** + * \file + * Batch buffer pool management. + * + * \author José Fonseca + * \author Thomas Hellström + */ + + +#include +#include +#include + +#include "main/imports.h" +#include "glapi/glthread.h" +#include "linked_list.h" + +#include "p_defines.h" + +#include "pb_buffer.h" +#include "pb_bufmgr.h" + + +/** + * Convenience macro (type safe). + */ +#define SUPER(__derived) (&(__derived)->base) + + +struct pool_buffer_manager +{ + struct buffer_manager base; + + _glthread_Mutex mutex; + + size_t bufSize; + + size_t numFree; + size_t numTot; + + struct list_head free; + + struct pipe_buffer *buffer; + void *map; + + struct pool_buffer *bufs; +}; + + +static inline struct pool_buffer_manager * +pool_buffer_manager(struct buffer_manager *mgr) +{ + assert(mgr); + return (struct pool_buffer_manager *)mgr; +} + + +struct pool_buffer +{ + struct pipe_buffer base; + + struct pool_buffer_manager *mgr; + + struct list_head head; + + size_t start; +}; + + +static inline struct pool_buffer * +pool_buffer(struct pipe_buffer *buf) +{ + assert(buf); + return (struct pool_buffer *)buf; +} + + +static void +pool_buffer_reference(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +pool_buffer_release(struct pipe_buffer *buf) +{ + struct pool_buffer *pool_buf = pool_buffer(buf); + struct pool_buffer_manager *pool = pool_buf->mgr; + + _glthread_LOCK_MUTEX(pool->mutex); + LIST_ADD(&pool_buf->head, &pool->free); + pool->numFree++; + _glthread_UNLOCK_MUTEX(pool->mutex); +} + + +static void * +pool_buffer_map(struct pipe_buffer *buf, unsigned flags) +{ + struct pool_buffer *pool_buf = pool_buffer(buf); + struct pool_buffer_manager *pool = pool_buf->mgr; + void *map; + + _glthread_LOCK_MUTEX(pool->mutex); + map = (unsigned char *) pool->map + pool_buf->start; + _glthread_UNLOCK_MUTEX(pool->mutex); + return map; +} + + +static void +pool_buffer_unmap(struct pipe_buffer *buf) +{ + /* No-op */ +} + + +static void +pool_buffer_get_base_buffer(struct pipe_buffer *buf, + struct pipe_buffer **base_buf, + unsigned *offset) +{ + struct pool_buffer *pool_buf = pool_buffer(buf); + struct pool_buffer_manager *pool = pool_buf->mgr; + buffer_get_base_buffer(pool->buffer, base_buf, offset); + *offset += pool_buf->start; +} + + +static const struct pipe_buffer_vtbl +pool_buffer_vtbl = { + pool_buffer_reference, + pool_buffer_release, + pool_buffer_map, + pool_buffer_unmap, + pool_buffer_get_base_buffer +}; + + +static struct pipe_buffer * +pool_bufmgr_create_buffer(struct buffer_manager *mgr, size_t size) +{ + struct pool_buffer_manager *pool = pool_buffer_manager(mgr); + struct pool_buffer *pool_buf; + struct list_head *item; + + assert(size == pool->bufSize); + + _glthread_LOCK_MUTEX(pool->mutex); + + if (pool->numFree == 0) { + _glthread_UNLOCK_MUTEX(pool->mutex); + fprintf(stderr, "warning: out of fixed size buffer objects\n"); + return NULL; + } + + item = pool->free.next; + + if (item == &pool->free) { + _glthread_UNLOCK_MUTEX(pool->mutex); + fprintf(stderr, "error: fixed size buffer pool corruption\n"); + return NULL; + } + + LIST_DEL(item); + --pool->numFree; + + _glthread_UNLOCK_MUTEX(pool->mutex); + pool_buf = LIST_ENTRY(struct pool_buffer, item, head); + return SUPER(pool_buf); +} + + +static void +pool_bufmgr_destroy(struct buffer_manager *mgr) +{ + struct pool_buffer_manager *pool = pool_buffer_manager(mgr); + _glthread_LOCK_MUTEX(pool->mutex); + + free(pool->bufs); + + buffer_unmap(pool->buffer); + buffer_release(pool->buffer); + + _glthread_UNLOCK_MUTEX(pool->mutex); + + free(mgr); +} + + +struct buffer_manager * +pool_bufmgr_create(struct buffer_manager *provider, + size_t numBufs, + size_t bufSize) +{ + struct pool_buffer_manager *pool; + struct pool_buffer *pool_buf; + int i; + + pool = (struct pool_buffer_manager *)calloc(1, sizeof(*pool)); + if (!pool) + return NULL; + + pool->base.destroy = pool_bufmgr_destroy; + pool->base.create_buffer = pool_bufmgr_create_buffer; + + LIST_INITHEAD(&pool->free); + + pool->numTot = numBufs; + pool->numFree = numBufs; + pool->bufSize = bufSize; + + _glthread_INIT_MUTEX(pool->mutex); + + pool->buffer = provider->create_buffer(provider, numBufs*bufSize); + if (!pool->buffer) + goto failure; + + pool->map = buffer_map(pool->buffer, + PIPE_BUFFER_FLAG_READ | + PIPE_BUFFER_FLAG_WRITE ); + if(!pool->map) + goto failure; + + pool->bufs = (struct pool_buffer *) malloc(numBufs * sizeof(*pool->bufs)); + if (!pool->bufs) + goto failure; + + pool_buf = pool->bufs; + for (i = 0; i < numBufs; ++i) { + pool_buf->base.vtbl = &pool_buffer_vtbl; + pool_buf->mgr = pool; + pool_buf->start = i * bufSize; + LIST_ADDTAIL(&pool_buf->head, &pool->free); + pool_buf++; + } + + return SUPER(pool); + +failure: + if(pool->bufs) + free(pool->bufs); + if(pool->map) + buffer_unmap(pool->buffer); + if(pool->buffer) + buffer_release(pool->buffer); + if(pool) + free(pool); + return NULL; +}