pb_buffer_fenced.c File Reference

Implementation of fenced buffers. More...

Include dependency graph for pb_buffer_fenced.c:

Go to the source code of this file.

Data Structures

struct  fenced_buffer_list
struct  fenced_buffer
 Wrapper around a pipe buffer which adds fencing and reference counting. More...

Defines

#define SUPER(__derived)   (&(__derived)->base)
 Convenience macro (type safe).
#define PIPE_BUFFER_USAGE_CPU_READ_WRITE   ( PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE )
#define PIPE_BUFFER_USAGE_GPU_READ_WRITE   ( PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE )
#define PIPE_BUFFER_USAGE_WRITE   ( PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_GPU_WRITE )

Functions

static struct fenced_bufferfenced_buffer (struct pb_buffer *buf)
static void _fenced_buffer_add (struct fenced_buffer *fenced_buf)
static void _fenced_buffer_destroy (struct fenced_buffer *fenced_buf)
 Actually destroy the buffer.
static void _fenced_buffer_remove (struct fenced_buffer_list *fenced_list, struct fenced_buffer *fenced_buf)
static enum pipe_error _fenced_buffer_finish (struct fenced_buffer *fenced_buf)
static void _fenced_buffer_list_check_free (struct fenced_buffer_list *fenced_list, int wait)
 Free as many fenced buffers from the list head as possible.
static void fenced_buffer_destroy (struct pb_buffer *buf)
static void * fenced_buffer_map (struct pb_buffer *buf, unsigned flags)
static void fenced_buffer_unmap (struct pb_buffer *buf)
static void fenced_buffer_get_base_buffer (struct pb_buffer *buf, struct pb_buffer **base_buf, unsigned *offset)
struct pb_bufferfenced_buffer_create (struct fenced_buffer_list *fenced_list, struct pb_buffer *buffer)
 Wrap a buffer in a fenced buffer.
void buffer_fence (struct pb_buffer *buf, struct pipe_fence_handle *fence)
 Set a buffer's fence.
struct fenced_buffer_listfenced_buffer_list_create (struct pipe_winsys *winsys)
 Create a fenced buffer list.
void fenced_buffer_list_check_free (struct fenced_buffer_list *fenced_list, int wait)
 Walk the fenced buffer list to check and free signalled buffers.
void fenced_buffer_list_destroy (struct fenced_buffer_list *fenced_list)

Variables

struct pb_vtbl fenced_buffer_vtbl
 The fenced buffer's virtual function table.


Detailed Description

Implementation of fenced buffers.

Author:
José Fonseca <jrfonseca-at-tungstengraphics-dot-com>

Thomas Hellström <thomas-at-tungstengraphics-dot-com>

Definition in file pb_buffer_fenced.c.


Define Documentation

#define PIPE_BUFFER_USAGE_CPU_READ_WRITE   ( PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE )

Definition at line 62 of file pb_buffer_fenced.c.

#define PIPE_BUFFER_USAGE_GPU_READ_WRITE   ( PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE )

Definition at line 64 of file pb_buffer_fenced.c.

#define PIPE_BUFFER_USAGE_WRITE   ( PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_GPU_WRITE )

Definition at line 66 of file pb_buffer_fenced.c.

#define SUPER ( __derived   )     (&(__derived)->base)

Convenience macro (type safe).

Definition at line 60 of file pb_buffer_fenced.c.


Function Documentation

static void _fenced_buffer_add ( struct fenced_buffer fenced_buf  )  [static]

Definition at line 121 of file pb_buffer_fenced.c.

References assert, pb_buffer::base, fenced_buffer::base, fenced_buffer_list::delayed, fenced_buffer::fence, fenced_buffer::flags, fenced_buffer::head, fenced_buffer::list, LIST_ADDTAIL, LIST_DEL, fenced_buffer_list::numDelayed, PIPE_BUFFER_USAGE_GPU_READ_WRITE, and pipe_buffer::refcount.

00122 {
00123    struct fenced_buffer_list *fenced_list = fenced_buf->list;
00124 
00125    assert(fenced_buf->base.base.refcount);
00126    assert(fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE);
00127    assert(fenced_buf->fence);
00128 
00129 #ifdef DEBUG
00130    LIST_DEL(&fenced_buf->head);
00131    assert(fenced_list->numUnfenced);
00132    --fenced_list->numUnfenced;
00133 #endif
00134    LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
00135    ++fenced_list->numDelayed;
00136 }

static void _fenced_buffer_destroy ( struct fenced_buffer fenced_buf  )  [static]

Actually destroy the buffer.

Definition at line 143 of file pb_buffer_fenced.c.

References assert, pb_buffer::base, fenced_buffer::base, fenced_buffer::buffer, fenced_buffer::fence, FREE, fenced_buffer::head, fenced_buffer::list, LIST_DEL, list_head::next, pb_reference(), list_head::prev, and pipe_buffer::refcount.

00144 {
00145    struct fenced_buffer_list *fenced_list = fenced_buf->list;
00146    
00147    assert(!fenced_buf->base.base.refcount);
00148    assert(!fenced_buf->fence);
00149 #ifdef DEBUG
00150    assert(fenced_buf->head.prev);
00151    assert(fenced_buf->head.next);
00152    LIST_DEL(&fenced_buf->head);
00153    assert(fenced_list->numUnfenced);
00154    --fenced_list->numUnfenced;
00155 #else
00156    (void)fenced_list;
00157 #endif
00158    pb_reference(&fenced_buf->buffer, NULL);
00159    FREE(fenced_buf);
00160 }

static enum pipe_error _fenced_buffer_finish ( struct fenced_buffer fenced_buf  )  [static]

Definition at line 193 of file pb_buffer_fenced.c.

References _fenced_buffer_remove(), assert, debug_warning, fenced_buffer::fence, pipe_winsys::fence_finish, fenced_buffer::flags, fenced_buffer::list, PIPE_BUFFER_USAGE_GPU_READ_WRITE, PIPE_ERROR, PIPE_OK, and fenced_buffer_list::winsys.

00194 {
00195    struct fenced_buffer_list *fenced_list = fenced_buf->list;
00196    struct pipe_winsys *winsys = fenced_list->winsys;
00197 
00198 #if 0
00199    debug_warning("waiting for GPU");
00200 #endif
00201 
00202    assert(fenced_buf->fence);
00203    if(fenced_buf->fence) {
00204       if(winsys->fence_finish(winsys, fenced_buf->fence, 0) != 0) {
00205          return PIPE_ERROR;
00206       }
00207       /* Remove from the fenced list */
00208       /* TODO: remove consequents */
00209       _fenced_buffer_remove(fenced_list, fenced_buf);
00210    }
00211 
00212    fenced_buf->flags &= ~PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00213    return PIPE_OK;
00214 }

static void _fenced_buffer_list_check_free ( struct fenced_buffer_list fenced_list,
int  wait 
) [static]

Free as many fenced buffers from the list head as possible.

Definition at line 221 of file pb_buffer_fenced.c.

References _fenced_buffer_remove(), assert, fenced_buffer_list::delayed, fenced_buffer::fence, pipe_winsys::fence_finish, pipe_winsys::fence_signalled, LIST_ENTRY, list_head::next, and fenced_buffer_list::winsys.

00223 {
00224    struct pipe_winsys *winsys = fenced_list->winsys;
00225    struct list_head *curr, *next;
00226    struct fenced_buffer *fenced_buf;
00227    struct pipe_fence_handle *prev_fence = NULL;
00228 
00229    curr = fenced_list->delayed.next;
00230    next = curr->next;
00231    while(curr != &fenced_list->delayed) {
00232       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00233 
00234       if(fenced_buf->fence != prev_fence) {
00235          int signaled;
00236          if (wait)
00237             signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
00238          else
00239             signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
00240          if (signaled != 0)
00241             break;
00242          prev_fence = fenced_buf->fence;
00243       }
00244       else {
00245          assert(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0);
00246       }
00247 
00248       _fenced_buffer_remove(fenced_list, fenced_buf);
00249 
00250       curr = next; 
00251       next = curr->next;
00252    }
00253 }

static void _fenced_buffer_remove ( struct fenced_buffer_list fenced_list,
struct fenced_buffer fenced_buf 
) [static]

Definition at line 164 of file pb_buffer_fenced.c.

References _fenced_buffer_destroy(), assert, pb_buffer::base, fenced_buffer::base, fenced_buffer::fence, pipe_winsys::fence_reference, fenced_buffer::flags, fenced_buffer::head, fenced_buffer::list, LIST_ADDTAIL, LIST_DEL, list_head::next, fenced_buffer_list::numDelayed, PIPE_BUFFER_USAGE_GPU_READ_WRITE, list_head::prev, pipe_buffer::refcount, and fenced_buffer_list::winsys.

00166 {
00167    struct pipe_winsys *winsys = fenced_list->winsys;
00168 
00169    assert(fenced_buf->fence);
00170    assert(fenced_buf->list == fenced_list);
00171    
00172    winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
00173    fenced_buf->flags &= ~PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00174    
00175    assert(fenced_buf->head.prev);
00176    assert(fenced_buf->head.next);
00177    
00178    LIST_DEL(&fenced_buf->head);
00179    assert(fenced_list->numDelayed);
00180    --fenced_list->numDelayed;
00181    
00182 #ifdef DEBUG
00183    LIST_ADDTAIL(&fenced_buf->head, &fenced_list->unfenced);
00184    ++fenced_list->numUnfenced;
00185 #endif
00186    
00187    if(!fenced_buf->base.base.refcount)
00188       _fenced_buffer_destroy(fenced_buf);
00189 }

void buffer_fence ( struct pb_buffer buf,
struct pipe_fence_handle *  fence 
)

Set a buffer's fence.

NOTE: Although it takes a generic pb_buffer argument, it will fail on everything but buffers returned by fenced_buffer_create.

Definition at line 403 of file pb_buffer_fenced.c.

References _fenced_buffer_add(), _fenced_buffer_remove(), assert, fenced_buffer::fence, pipe_winsys::fence_reference, fenced_buffer(), fenced_buffer::flags, fenced_buffer::list, fenced_buffer_list::mutex, PIPE_BUFFER_USAGE_GPU_READ_WRITE, pipe_mutex_lock, pipe_mutex_unlock, pb_buffer::vtbl, and fenced_buffer_list::winsys.

00405 {
00406    struct fenced_buffer *fenced_buf;
00407    struct fenced_buffer_list *fenced_list;
00408    struct pipe_winsys *winsys;
00409    /* FIXME: receive this as a parameter */
00410    unsigned flags = fence ? PIPE_BUFFER_USAGE_GPU_READ_WRITE : 0;
00411 
00412    /* This is a public function, so be extra cautious with the buffer passed, 
00413     * as happens frequently to receive null buffers, or pointer to buffers 
00414     * other than fenced buffers. */
00415    assert(buf);
00416    if(!buf)
00417       return;
00418    assert(buf->vtbl == &fenced_buffer_vtbl);
00419    if(buf->vtbl != &fenced_buffer_vtbl)
00420       return;
00421    
00422    if(!fence)
00423       return;
00424 
00425    fenced_buf = fenced_buffer(buf);
00426    fenced_list = fenced_buf->list;
00427    winsys = fenced_list->winsys;
00428    
00429    if(fence == fenced_buf->fence) {
00430       fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00431       return;
00432    }
00433    
00434    pipe_mutex_lock(fenced_list->mutex);
00435    if (fenced_buf->fence)
00436       _fenced_buffer_remove(fenced_list, fenced_buf);
00437    winsys->fence_reference(winsys, &fenced_buf->fence, fence);
00438    fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE;
00439    _fenced_buffer_add(fenced_buf);
00440    pipe_mutex_unlock(fenced_list->mutex);
00441 }

static struct fenced_buffer* fenced_buffer ( struct pb_buffer buf  )  [static, read]

Definition at line 112 of file pb_buffer_fenced.c.

References assert, fenced_buffer_vtbl, and pb_buffer::vtbl.

00113 {
00114    assert(buf);
00115    assert(buf->vtbl == &fenced_buffer_vtbl);
00116    return (struct fenced_buffer *)buf;
00117 }

struct pb_buffer* fenced_buffer_create ( struct fenced_buffer_list fenced,
struct pb_buffer buffer 
) [read]

Wrap a buffer in a fenced buffer.

NOTE: this will not increase the buffer reference count.

Definition at line 368 of file pb_buffer_fenced.c.

References pipe_buffer::alignment, pb_buffer::base, fenced_buffer::base, fenced_buffer::buffer, CALLOC_STRUCT, fenced_buffer::head, fenced_buffer::list, LIST_ADDTAIL, fenced_buffer_list::mutex, pb_reference(), pipe_mutex_lock, pipe_mutex_unlock, pipe_buffer::refcount, pipe_buffer::size, pipe_buffer::usage, and pb_buffer::vtbl.

00370 {
00371    struct fenced_buffer *buf;
00372    
00373    if(!buffer)
00374       return NULL;
00375    
00376    buf = CALLOC_STRUCT(fenced_buffer);
00377    if(!buf) {
00378       pb_reference(&buffer, NULL);
00379       return NULL;
00380    }
00381    
00382    buf->base.base.refcount = 1;
00383    buf->base.base.alignment = buffer->base.alignment;
00384    buf->base.base.usage = buffer->base.usage;
00385    buf->base.base.size = buffer->base.size;
00386    
00387    buf->base.vtbl = &fenced_buffer_vtbl;
00388    buf->buffer = buffer;
00389    buf->list = fenced_list;
00390    
00391 #ifdef DEBUG
00392    pipe_mutex_lock(fenced_list->mutex);
00393    LIST_ADDTAIL(&buf->head, &fenced_list->unfenced);
00394    ++fenced_list->numUnfenced;
00395    pipe_mutex_unlock(fenced_list->mutex);
00396 #endif
00397 
00398    return &buf->base;
00399 }

static void fenced_buffer_destroy ( struct pb_buffer buf  )  [static]

Definition at line 257 of file pb_buffer_fenced.c.

References _fenced_buffer_destroy(), _fenced_buffer_remove(), assert, pb_buffer::base, fenced_buffer::base, fenced_buffer_list::delayed, fenced_buffer::fence, pipe_winsys::fence_signalled, fenced_buffer(), fenced_buffer::head, fenced_buffer::list, LIST_ENTRY, fenced_buffer_list::mutex, pipe_mutex_lock, pipe_mutex_unlock, list_head::prev, pipe_buffer::refcount, and fenced_buffer_list::winsys.

00258 {
00259    struct fenced_buffer *fenced_buf = fenced_buffer(buf);   
00260    struct fenced_buffer_list *fenced_list = fenced_buf->list;
00261 
00262    pipe_mutex_lock(fenced_list->mutex);
00263    assert(fenced_buf->base.base.refcount == 0);
00264    if (fenced_buf->fence) {
00265       struct pipe_winsys *winsys = fenced_list->winsys;
00266       if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0) {
00267          struct list_head *curr, *prev;
00268          curr = &fenced_buf->head;
00269          prev = curr->prev;
00270          do {
00271             fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00272             assert(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0);
00273             _fenced_buffer_remove(fenced_list, fenced_buf);
00274             curr = prev;
00275             prev = curr->prev;
00276          } while (curr != &fenced_list->delayed);
00277       }   
00278       else {
00279          /* delay destruction */
00280       }
00281    }
00282    else {
00283       _fenced_buffer_destroy(fenced_buf);
00284    }
00285    pipe_mutex_unlock(fenced_list->mutex);
00286 }

static void fenced_buffer_get_base_buffer ( struct pb_buffer buf,
struct pb_buffer **  base_buf,
unsigned *  offset 
) [static]

Definition at line 349 of file pb_buffer_fenced.c.

References fenced_buffer::buffer, fenced_buffer(), and pb_get_base_buffer().

00352 {
00353    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00354    pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
00355 }

void fenced_buffer_list_check_free ( struct fenced_buffer_list fenced_list,
int  wait 
)

Walk the fenced buffer list to check and free signalled buffers.

Definition at line 470 of file pb_buffer_fenced.c.

References _fenced_buffer_list_check_free(), fenced_buffer_list::mutex, pipe_mutex_lock, and pipe_mutex_unlock.

00472 {
00473    pipe_mutex_lock(fenced_list->mutex);
00474    _fenced_buffer_list_check_free(fenced_list, wait);
00475    pipe_mutex_unlock(fenced_list->mutex);
00476 }

struct fenced_buffer_list* fenced_buffer_list_create ( struct pipe_winsys winsys  )  [read]

Create a fenced buffer list.

See also fenced_bufmgr_create for a more convenient way to use this.

Definition at line 445 of file pb_buffer_fenced.c.

References CALLOC_STRUCT, fenced_buffer_list::delayed, LIST_INITHEAD, fenced_buffer_list::mutex, fenced_buffer_list::numDelayed, pipe_mutex_init, and fenced_buffer_list::winsys.

00446 {
00447    struct fenced_buffer_list *fenced_list;
00448 
00449    fenced_list = CALLOC_STRUCT(fenced_buffer_list);
00450    if (!fenced_list)
00451       return NULL;
00452 
00453    fenced_list->winsys = winsys;
00454 
00455    LIST_INITHEAD(&fenced_list->delayed);
00456    fenced_list->numDelayed = 0;
00457    
00458 #ifdef DEBUG
00459    LIST_INITHEAD(&fenced_list->unfenced);
00460    fenced_list->numUnfenced = 0;
00461 #endif
00462 
00463    pipe_mutex_init(fenced_list->mutex);
00464 
00465    return fenced_list;
00466 }

void fenced_buffer_list_destroy ( struct fenced_buffer_list fenced_list  ) 

Definition at line 525 of file pb_buffer_fenced.c.

References _fenced_buffer_list_check_free(), FREE, fenced_buffer_list::mutex, fenced_buffer_list::numDelayed, pipe_mutex_lock, and pipe_mutex_unlock.

00526 {
00527    pipe_mutex_lock(fenced_list->mutex);
00528 
00529    /* Wait on outstanding fences */
00530    while (fenced_list->numDelayed) {
00531       pipe_mutex_unlock(fenced_list->mutex);
00532 #if defined(PIPE_OS_LINUX)
00533       sched_yield();
00534 #endif
00535       _fenced_buffer_list_check_free(fenced_list, 1);
00536       pipe_mutex_lock(fenced_list->mutex);
00537    }
00538 
00539 #ifdef DEBUG
00540    //assert(!fenced_list->numUnfenced);
00541 #endif
00542       
00543    pipe_mutex_unlock(fenced_list->mutex);
00544    
00545    FREE(fenced_list);
00546 }

static void* fenced_buffer_map ( struct pb_buffer buf,
unsigned  flags 
) [static]

Definition at line 290 of file pb_buffer_fenced.c.

References _fenced_buffer_finish(), _fenced_buffer_remove(), assert, fenced_buffer::buffer, debug_warning, fenced_buffer::fence, pipe_winsys::fence_signalled, fenced_buffer(), fenced_buffer::flags, fenced_buffer::list, fenced_buffer::mapcount, pb_map(), PIPE_BUFFER_USAGE_CPU_READ_WRITE, PIPE_BUFFER_USAGE_CPU_WRITE, PIPE_BUFFER_USAGE_DONTBLOCK, PIPE_BUFFER_USAGE_GPU_READ, PIPE_BUFFER_USAGE_GPU_READ_WRITE, PIPE_BUFFER_USAGE_GPU_WRITE, and fenced_buffer_list::winsys.

00292 {
00293    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00294    struct fenced_buffer_list *fenced_list = fenced_buf->list;
00295    struct pipe_winsys *winsys = fenced_list->winsys;
00296    void *map;
00297 
00298    assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE));
00299    
00300    /* Serialize writes */
00301    if((fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_WRITE) ||
00302       ((fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_READ) && (flags & PIPE_BUFFER_USAGE_CPU_WRITE))) {
00303       if(flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
00304          /* Don't wait for the GPU to finish writing */
00305          if(winsys->fence_signalled(winsys, fenced_buf->fence, 0) == 0)
00306             _fenced_buffer_remove(fenced_list, fenced_buf);
00307          else
00308             return NULL;
00309       }
00310       else {
00311          /* Wait for the GPU to finish writing */
00312          _fenced_buffer_finish(fenced_buf);
00313       }
00314    }
00315 
00316 #if 0
00317    /* Check for CPU write access (read is OK) */
00318    if(fenced_buf->flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) {
00319       /* this is legal -- just for debugging */
00320       debug_warning("concurrent CPU writes");
00321    }
00322 #endif
00323    
00324    map = pb_map(fenced_buf->buffer, flags);
00325    if(map) {
00326       ++fenced_buf->mapcount;
00327       fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE;
00328    }
00329 
00330    return map;
00331 }

static void fenced_buffer_unmap ( struct pb_buffer buf  )  [static]

Definition at line 335 of file pb_buffer_fenced.c.

References assert, fenced_buffer::buffer, fenced_buffer(), fenced_buffer::flags, fenced_buffer::mapcount, pb_unmap(), and PIPE_BUFFER_USAGE_CPU_READ_WRITE.

00336 {
00337    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00338    assert(fenced_buf->mapcount);
00339    if(fenced_buf->mapcount) {
00340       pb_unmap(fenced_buf->buffer);
00341       --fenced_buf->mapcount;
00342       if(!fenced_buf->mapcount)
00343          fenced_buf->flags &= ~PIPE_BUFFER_USAGE_CPU_READ_WRITE;
00344    }
00345 }


Variable Documentation

struct pb_vtbl fenced_buffer_vtbl

Initial value:

The fenced buffer's virtual function table.

NOTE: Made public for debugging purposes.

Definition at line 359 of file pb_buffer_fenced.c.


Generated on Tue Sep 29 06:25:24 2009 for Gallium3D by  doxygen 1.5.4