pb_buffer_fenced.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  *
00026  **************************************************************************/
00027 
00037 #include "pipe/p_config.h"
00038 
00039 #if defined(PIPE_OS_LINUX)
00040 #include <unistd.h>
00041 #include <sched.h>
00042 #endif
00043 
00044 #include "pipe/p_compiler.h"
00045 #include "pipe/p_error.h"
00046 #include "pipe/p_debug.h"
00047 #include "pipe/p_winsys.h"
00048 #include "pipe/p_thread.h"
00049 #include "util/u_memory.h"
00050 #include "util/u_double_list.h"
00051 
00052 #include "pb_buffer.h"
00053 #include "pb_buffer_fenced.h"
00054 
00055 
00056 
00060 #define SUPER(__derived) (&(__derived)->base)
00061 
00062 #define PIPE_BUFFER_USAGE_CPU_READ_WRITE \
00063    ( PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE )
00064 #define PIPE_BUFFER_USAGE_GPU_READ_WRITE \
00065    ( PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE )
00066 #define PIPE_BUFFER_USAGE_WRITE \
00067    ( PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_GPU_WRITE )
00068 
00069 
00070 struct fenced_buffer_list
00071 {
00072    pipe_mutex mutex;
00073    
00074    struct pipe_winsys *winsys;
00075    
00076    size_t numDelayed;
00077    struct list_head delayed;
00078    
00079 #ifdef DEBUG
00080    size_t numUnfenced;
00081    struct list_head unfenced;
00082 #endif
00083 };
00084 
00085 
00089 struct fenced_buffer
00090 {
00091    struct pb_buffer base;
00092    
00093    struct pb_buffer *buffer;
00094 
00095    /* FIXME: protect access with mutex */
00096 
00101    unsigned flags;
00102 
00103    unsigned mapcount;
00104    struct pipe_fence_handle *fence;
00105 
00106    struct list_head head;
00107    struct fenced_buffer_list *list;
00108 };
00109 
00110 
00111 static INLINE struct fenced_buffer *
00112 fenced_buffer(struct pb_buffer *buf)
00113 {
00114    assert(buf);
00115    assert(buf->vtbl == &fenced_buffer_vtbl);
00116    return (struct fenced_buffer *)buf;
00117 }
00118 
00119 
00120 static INLINE void
00121 _fenced_buffer_add(struct fenced_buffer *fenced_buf)
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 }
00137 
00138 
00142 static INLINE void
00143 _fenced_buffer_destroy(struct fenced_buffer *fenced_buf)
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 }
00161 
00162 
00163 static INLINE void
00164 _fenced_buffer_remove(struct fenced_buffer_list *fenced_list,
00165                       struct fenced_buffer *fenced_buf)
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 }
00190 
00191 
00192 static INLINE enum pipe_error
00193 _fenced_buffer_finish(struct fenced_buffer *fenced_buf)
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 }
00215 
00216 
00220 static void
00221 _fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 
00222                                int wait)
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 }
00254 
00255 
00256 static void
00257 fenced_buffer_destroy(struct pb_buffer *buf)
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 }
00287 
00288 
00289 static void *
00290 fenced_buffer_map(struct pb_buffer *buf, 
00291                   unsigned flags)
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 }
00332 
00333 
00334 static void
00335 fenced_buffer_unmap(struct pb_buffer *buf)
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 }
00346 
00347 
00348 static void
00349 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
00350                               struct pb_buffer **base_buf,
00351                               unsigned *offset)
00352 {
00353    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
00354    pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
00355 }
00356 
00357 
00358 const struct pb_vtbl 
00359 fenced_buffer_vtbl = {
00360       fenced_buffer_destroy,
00361       fenced_buffer_map,
00362       fenced_buffer_unmap,
00363       fenced_buffer_get_base_buffer
00364 };
00365 
00366 
00367 struct pb_buffer *
00368 fenced_buffer_create(struct fenced_buffer_list *fenced_list, 
00369                      struct pb_buffer *buffer)
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 }
00400 
00401 
00402 void
00403 buffer_fence(struct pb_buffer *buf,
00404              struct pipe_fence_handle *fence)
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 }
00442 
00443 
00444 struct fenced_buffer_list *
00445 fenced_buffer_list_create(struct pipe_winsys *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 }
00467 
00468 
00469 void
00470 fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 
00471                               int wait)
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 }
00477 
00478 
00479 #ifdef DEBUG
00480 void
00481 fenced_buffer_list_dump(struct fenced_buffer_list *fenced_list)
00482 {
00483    struct pipe_winsys *winsys = fenced_list->winsys;
00484    struct list_head *curr, *next;
00485    struct fenced_buffer *fenced_buf;
00486 
00487    pipe_mutex_lock(fenced_list->mutex);
00488 
00489    debug_printf("%10s %7s %10s %s\n",
00490                 "buffer", "refcount", "fence", "signalled");
00491    
00492    curr = fenced_list->unfenced.next;
00493    next = curr->next;
00494    while(curr != &fenced_list->unfenced) {
00495       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00496       assert(!fenced_buf->fence);
00497       debug_printf("%10p %7u\n",
00498                    fenced_buf,
00499                    fenced_buf->base.base.refcount);
00500       curr = next; 
00501       next = curr->next;
00502    }
00503    
00504    curr = fenced_list->delayed.next;
00505    next = curr->next;
00506    while(curr != &fenced_list->delayed) {
00507       int signaled;
00508       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
00509       signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
00510       debug_printf("%10p %7u %10p %s\n",
00511                    fenced_buf,
00512                    fenced_buf->base.base.refcount,
00513                    fenced_buf->fence,
00514                    signaled == 0 ? "y" : "n");
00515       curr = next; 
00516       next = curr->next;
00517    }
00518    
00519    pipe_mutex_unlock(fenced_list->mutex);
00520 }
00521 #endif
00522 
00523 
00524 void
00525 fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list)
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 }
00547 
00548 

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