diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mesa/pipe/Makefile | 5 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/Makefile | 27 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/linked_list.h | 91 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer.c | 52 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer.h | 175 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_client.c | 123 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_fenced.c | 340 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_fenced.h | 138 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_handle.c | 182 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_handle.h | 120 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_malloc.c | 132 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_buffer_null.c | 98 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_bufmgr.h | 114 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c | 128 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c | 265 | ||||
| -rw-r--r-- | src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c | 279 | 
16 files changed, 2266 insertions, 3 deletions
| diff --git a/src/mesa/pipe/Makefile b/src/mesa/pipe/Makefile index a9dc393417..2bf7318d59 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 0000000000..061d8a060f --- /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 0000000000..e99817fb13 --- /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 <stddef.h> + + +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 0000000000..99c960b697 --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#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 0000000000..0523531395 --- /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 <jrfonseca@tungstengraphics.com> + */ + +#ifndef PB_BUFFER_H_ +#define PB_BUFFER_H_ + + +#include <assert.h> +#include <stdlib.h> + + +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 0000000000..bb7f5a9a94 --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#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 0000000000..c5a06c545e --- /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 <jrfonseca-at-tungstengraphics-dot-com> + * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#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 0000000000..d12428e216 --- /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 <jrfonseca@tungstengraphics.com> + */ + +#ifndef PB_BUFFER_FENCED_H_ +#define PB_BUFFER_FENCED_H_ + + +#include <assert.h> + + +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 0000000000..5a5eaee7ac --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#include <assert.h> +#include <stdlib.h> + +#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 0000000000..076eec2fdc --- /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 <jrfonseca@tungstengraphics.com> + */ + +#ifndef PB_BUFFER_HANDLE_H_ +#define PB_BUFFER_HANDLE_H_ + + +#include <assert.h> + +#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 0000000000..65ad51e1e7 --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#include <assert.h> +#include <stdlib.h> + +#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 0000000000..a356c6b2d5 --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#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 0000000000..0e6c3a8d37 --- /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 <jrfonseca@tungstengraphics.com> + */ + +#ifndef PB_BUFMGR_H_ +#define PB_BUFMGR_H_ + + +#include <stddef.h> + + +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 0000000000..defd8e4df7 --- /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 <jrfonseca@tungstengraphics.dot.com> + */ + + +#include <assert.h> +#include <stdlib.h> + +#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 0000000000..8e6dcf1116 --- /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 <jrfonseca@tungstengraphics.com> + */ + + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#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 0000000000..ee6fa62500 --- /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 <jrfonseca-at-tungstengraphics-dot-com> + * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#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; +} | 
