Home | History | Annotate | Download | only in pipebuffer
      1 /**************************************************************************
      2  *
      3  * Copyright 2007-2010 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /**
     29  * \file
     30  * Implementation of fenced buffers.
     31  *
     32  * \author Jose Fonseca <jfonseca-at-vmware-dot-com>
     33  * \author Thomas Hellstrm <thellstrom-at-vmware-dot-com>
     34  */
     35 
     36 
     37 #include "pipe/p_config.h"
     38 
     39 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)
     40 #include <unistd.h>
     41 #include <sched.h>
     42 #endif
     43 
     44 #include "pipe/p_compiler.h"
     45 #include "pipe/p_defines.h"
     46 #include "util/u_debug.h"
     47 #include "os/os_thread.h"
     48 #include "util/u_memory.h"
     49 #include "util/u_double_list.h"
     50 
     51 #include "pb_buffer.h"
     52 #include "pb_buffer_fenced.h"
     53 #include "pb_bufmgr.h"
     54 
     55 
     56 
     57 /**
     58  * Convenience macro (type safe).
     59  */
     60 #define SUPER(__derived) (&(__derived)->base)
     61 
     62 
     63 struct fenced_manager
     64 {
     65    struct pb_manager base;
     66    struct pb_manager *provider;
     67    struct pb_fence_ops *ops;
     68 
     69    /**
     70     * Maximum buffer size that can be safely allocated.
     71     */
     72    pb_size max_buffer_size;
     73 
     74    /**
     75     * Maximum cpu memory we can allocate before we start waiting for the
     76     * GPU to idle.
     77     */
     78    pb_size max_cpu_total_size;
     79 
     80    /**
     81     * Following members are mutable and protected by this mutex.
     82     */
     83    pipe_mutex mutex;
     84 
     85    /**
     86     * Fenced buffer list.
     87     *
     88     * All fenced buffers are placed in this listed, ordered from the oldest
     89     * fence to the newest fence.
     90     */
     91    struct list_head fenced;
     92    pb_size num_fenced;
     93 
     94    struct list_head unfenced;
     95    pb_size num_unfenced;
     96 
     97    /**
     98     * How much temporary CPU memory is being used to hold unvalidated buffers.
     99     */
    100    pb_size cpu_total_size;
    101 };
    102 
    103 
    104 /**
    105  * Fenced buffer.
    106  *
    107  * Wrapper around a pipe buffer which adds fencing and reference counting.
    108  */
    109 struct fenced_buffer
    110 {
    111    /*
    112     * Immutable members.
    113     */
    114 
    115    struct pb_buffer base;
    116    struct fenced_manager *mgr;
    117 
    118    /*
    119     * Following members are mutable and protected by fenced_manager::mutex.
    120     */
    121 
    122    struct list_head head;
    123 
    124    /**
    125     * Buffer with storage.
    126     */
    127    struct pb_buffer *buffer;
    128    pb_size size;
    129    struct pb_desc desc;
    130 
    131    /**
    132     * Temporary CPU storage data. Used when there isn't enough GPU memory to
    133     * store the buffer.
    134     */
    135    void *data;
    136 
    137    /**
    138     * A bitmask of PB_USAGE_CPU/GPU_READ/WRITE describing the current
    139     * buffer usage.
    140     */
    141    unsigned flags;
    142 
    143    unsigned mapcount;
    144 
    145    struct pb_validate *vl;
    146    unsigned validation_flags;
    147 
    148    struct pipe_fence_handle *fence;
    149 };
    150 
    151 
    152 static INLINE struct fenced_manager *
    153 fenced_manager(struct pb_manager *mgr)
    154 {
    155    assert(mgr);
    156    return (struct fenced_manager *)mgr;
    157 }
    158 
    159 
    160 static INLINE struct fenced_buffer *
    161 fenced_buffer(struct pb_buffer *buf)
    162 {
    163    assert(buf);
    164    return (struct fenced_buffer *)buf;
    165 }
    166 
    167 
    168 static void
    169 fenced_buffer_destroy_cpu_storage_locked(struct fenced_buffer *fenced_buf);
    170 
    171 static enum pipe_error
    172 fenced_buffer_create_cpu_storage_locked(struct fenced_manager *fenced_mgr,
    173                                         struct fenced_buffer *fenced_buf);
    174 
    175 static void
    176 fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf);
    177 
    178 static enum pipe_error
    179 fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
    180                                         struct fenced_buffer *fenced_buf,
    181                                         boolean wait);
    182 
    183 static enum pipe_error
    184 fenced_buffer_copy_storage_to_gpu_locked(struct fenced_buffer *fenced_buf);
    185 
    186 static enum pipe_error
    187 fenced_buffer_copy_storage_to_cpu_locked(struct fenced_buffer *fenced_buf);
    188 
    189 
    190 /**
    191  * Dump the fenced buffer list.
    192  *
    193  * Useful to understand failures to allocate buffers.
    194  */
    195 static void
    196 fenced_manager_dump_locked(struct fenced_manager *fenced_mgr)
    197 {
    198 #ifdef DEBUG
    199    struct pb_fence_ops *ops = fenced_mgr->ops;
    200    struct list_head *curr, *next;
    201    struct fenced_buffer *fenced_buf;
    202 
    203    debug_printf("%10s %7s %8s %7s %10s %s\n",
    204                 "buffer", "size", "refcount", "storage", "fence", "signalled");
    205 
    206    curr = fenced_mgr->unfenced.next;
    207    next = curr->next;
    208    while(curr != &fenced_mgr->unfenced) {
    209       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
    210       assert(!fenced_buf->fence);
    211       debug_printf("%10p %7u %8u %7s\n",
    212                    (void *) fenced_buf,
    213                    fenced_buf->base.size,
    214                    p_atomic_read(&fenced_buf->base.reference.count),
    215                    fenced_buf->buffer ? "gpu" : (fenced_buf->data ? "cpu" : "none"));
    216       curr = next;
    217       next = curr->next;
    218    }
    219 
    220    curr = fenced_mgr->fenced.next;
    221    next = curr->next;
    222    while(curr != &fenced_mgr->fenced) {
    223       int signaled;
    224       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
    225       assert(fenced_buf->buffer);
    226       signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
    227       debug_printf("%10p %7u %8u %7s %10p %s\n",
    228                    (void *) fenced_buf,
    229                    fenced_buf->base.size,
    230                    p_atomic_read(&fenced_buf->base.reference.count),
    231                    "gpu",
    232                    (void *) fenced_buf->fence,
    233                    signaled == 0 ? "y" : "n");
    234       curr = next;
    235       next = curr->next;
    236    }
    237 #else
    238    (void)fenced_mgr;
    239 #endif
    240 }
    241 
    242 
    243 static INLINE void
    244 fenced_buffer_destroy_locked(struct fenced_manager *fenced_mgr,
    245                              struct fenced_buffer *fenced_buf)
    246 {
    247    assert(!pipe_is_referenced(&fenced_buf->base.reference));
    248 
    249    assert(!fenced_buf->fence);
    250    assert(fenced_buf->head.prev);
    251    assert(fenced_buf->head.next);
    252    LIST_DEL(&fenced_buf->head);
    253    assert(fenced_mgr->num_unfenced);
    254    --fenced_mgr->num_unfenced;
    255 
    256    fenced_buffer_destroy_gpu_storage_locked(fenced_buf);
    257    fenced_buffer_destroy_cpu_storage_locked(fenced_buf);
    258 
    259    FREE(fenced_buf);
    260 }
    261 
    262 
    263 /**
    264  * Add the buffer to the fenced list.
    265  *
    266  * Reference count should be incremented before calling this function.
    267  */
    268 static INLINE void
    269 fenced_buffer_add_locked(struct fenced_manager *fenced_mgr,
    270                          struct fenced_buffer *fenced_buf)
    271 {
    272    assert(pipe_is_referenced(&fenced_buf->base.reference));
    273    assert(fenced_buf->flags & PB_USAGE_GPU_READ_WRITE);
    274    assert(fenced_buf->fence);
    275 
    276    p_atomic_inc(&fenced_buf->base.reference.count);
    277 
    278    LIST_DEL(&fenced_buf->head);
    279    assert(fenced_mgr->num_unfenced);
    280    --fenced_mgr->num_unfenced;
    281    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->fenced);
    282    ++fenced_mgr->num_fenced;
    283 }
    284 
    285 
    286 /**
    287  * Remove the buffer from the fenced list, and potentially destroy the buffer
    288  * if the reference count reaches zero.
    289  *
    290  * Returns TRUE if the buffer was detroyed.
    291  */
    292 static INLINE boolean
    293 fenced_buffer_remove_locked(struct fenced_manager *fenced_mgr,
    294                             struct fenced_buffer *fenced_buf)
    295 {
    296    struct pb_fence_ops *ops = fenced_mgr->ops;
    297 
    298    assert(fenced_buf->fence);
    299    assert(fenced_buf->mgr == fenced_mgr);
    300 
    301    ops->fence_reference(ops, &fenced_buf->fence, NULL);
    302    fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
    303 
    304    assert(fenced_buf->head.prev);
    305    assert(fenced_buf->head.next);
    306 
    307    LIST_DEL(&fenced_buf->head);
    308    assert(fenced_mgr->num_fenced);
    309    --fenced_mgr->num_fenced;
    310 
    311    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
    312    ++fenced_mgr->num_unfenced;
    313 
    314    if (p_atomic_dec_zero(&fenced_buf->base.reference.count)) {
    315       fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
    316       return TRUE;
    317    }
    318 
    319    return FALSE;
    320 }
    321 
    322 
    323 /**
    324  * Wait for the fence to expire, and remove it from the fenced list.
    325  *
    326  * This function will release and re-aquire the mutex, so any copy of mutable
    327  * state must be discarded after calling it.
    328  */
    329 static INLINE enum pipe_error
    330 fenced_buffer_finish_locked(struct fenced_manager *fenced_mgr,
    331                             struct fenced_buffer *fenced_buf)
    332 {
    333    struct pb_fence_ops *ops = fenced_mgr->ops;
    334    enum pipe_error ret = PIPE_ERROR;
    335 
    336 #if 0
    337    debug_warning("waiting for GPU");
    338 #endif
    339 
    340    assert(pipe_is_referenced(&fenced_buf->base.reference));
    341    assert(fenced_buf->fence);
    342 
    343    if(fenced_buf->fence) {
    344       struct pipe_fence_handle *fence = NULL;
    345       int finished;
    346       boolean proceed;
    347 
    348       ops->fence_reference(ops, &fence, fenced_buf->fence);
    349 
    350       pipe_mutex_unlock(fenced_mgr->mutex);
    351 
    352       finished = ops->fence_finish(ops, fenced_buf->fence, 0);
    353 
    354       pipe_mutex_lock(fenced_mgr->mutex);
    355 
    356       assert(pipe_is_referenced(&fenced_buf->base.reference));
    357 
    358       /*
    359        * Only proceed if the fence object didn't change in the meanwhile.
    360        * Otherwise assume the work has been already carried out by another
    361        * thread that re-aquired the lock before us.
    362        */
    363       proceed = fence == fenced_buf->fence ? TRUE : FALSE;
    364 
    365       ops->fence_reference(ops, &fence, NULL);
    366 
    367       if(proceed && finished == 0) {
    368          /*
    369           * Remove from the fenced list
    370           */
    371 
    372          boolean destroyed;
    373 
    374          destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
    375 
    376          /* TODO: remove consequents buffers with the same fence? */
    377 
    378          assert(!destroyed);
    379 
    380          fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
    381 
    382          ret = PIPE_OK;
    383       }
    384    }
    385 
    386    return ret;
    387 }
    388 
    389 
    390 /**
    391  * Remove as many fenced buffers from the fenced list as possible.
    392  *
    393  * Returns TRUE if at least one buffer was removed.
    394  */
    395 static boolean
    396 fenced_manager_check_signalled_locked(struct fenced_manager *fenced_mgr,
    397                                       boolean wait)
    398 {
    399    struct pb_fence_ops *ops = fenced_mgr->ops;
    400    struct list_head *curr, *next;
    401    struct fenced_buffer *fenced_buf;
    402    struct pipe_fence_handle *prev_fence = NULL;
    403    boolean ret = FALSE;
    404 
    405    curr = fenced_mgr->fenced.next;
    406    next = curr->next;
    407    while(curr != &fenced_mgr->fenced) {
    408       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
    409 
    410       if(fenced_buf->fence != prev_fence) {
    411 	 int signaled;
    412 
    413 	 if (wait) {
    414 	    signaled = ops->fence_finish(ops, fenced_buf->fence, 0);
    415 
    416 	    /*
    417 	     * Don't return just now. Instead preemptively check if the
    418 	     * following buffers' fences already expired, without further waits.
    419 	     */
    420 	    wait = FALSE;
    421 	 }
    422 	 else {
    423 	    signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
    424 	 }
    425 
    426 	 if (signaled != 0) {
    427 	    return ret;
    428          }
    429 
    430 	 prev_fence = fenced_buf->fence;
    431       }
    432       else {
    433          /* This buffer's fence object is identical to the previous buffer's
    434           * fence object, so no need to check the fence again.
    435           */
    436 	 assert(ops->fence_signalled(ops, fenced_buf->fence, 0) == 0);
    437       }
    438 
    439       fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
    440 
    441       ret = TRUE;
    442 
    443       curr = next;
    444       next = curr->next;
    445    }
    446 
    447    return ret;
    448 }
    449 
    450 
    451 /**
    452  * Try to free some GPU memory by backing it up into CPU memory.
    453  *
    454  * Returns TRUE if at least one buffer was freed.
    455  */
    456 static boolean
    457 fenced_manager_free_gpu_storage_locked(struct fenced_manager *fenced_mgr)
    458 {
    459    struct list_head *curr, *next;
    460    struct fenced_buffer *fenced_buf;
    461 
    462    curr = fenced_mgr->unfenced.next;
    463    next = curr->next;
    464    while(curr != &fenced_mgr->unfenced) {
    465       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
    466 
    467       /*
    468        * We can only move storage if the buffer is not mapped and not
    469        * validated.
    470        */
    471       if(fenced_buf->buffer &&
    472          !fenced_buf->mapcount &&
    473          !fenced_buf->vl) {
    474          enum pipe_error ret;
    475 
    476          ret = fenced_buffer_create_cpu_storage_locked(fenced_mgr, fenced_buf);
    477          if(ret == PIPE_OK) {
    478             ret = fenced_buffer_copy_storage_to_cpu_locked(fenced_buf);
    479             if(ret == PIPE_OK) {
    480                fenced_buffer_destroy_gpu_storage_locked(fenced_buf);
    481                return TRUE;
    482             }
    483             fenced_buffer_destroy_cpu_storage_locked(fenced_buf);
    484          }
    485       }
    486 
    487       curr = next;
    488       next = curr->next;
    489    }
    490 
    491    return FALSE;
    492 }
    493 
    494 
    495 /**
    496  * Destroy CPU storage for this buffer.
    497  */
    498 static void
    499 fenced_buffer_destroy_cpu_storage_locked(struct fenced_buffer *fenced_buf)
    500 {
    501    if(fenced_buf->data) {
    502       align_free(fenced_buf->data);
    503       fenced_buf->data = NULL;
    504       assert(fenced_buf->mgr->cpu_total_size >= fenced_buf->size);
    505       fenced_buf->mgr->cpu_total_size -= fenced_buf->size;
    506    }
    507 }
    508 
    509 
    510 /**
    511  * Create CPU storage for this buffer.
    512  */
    513 static enum pipe_error
    514 fenced_buffer_create_cpu_storage_locked(struct fenced_manager *fenced_mgr,
    515                                         struct fenced_buffer *fenced_buf)
    516 {
    517    assert(!fenced_buf->data);
    518    if(fenced_buf->data)
    519       return PIPE_OK;
    520 
    521    if (fenced_mgr->cpu_total_size + fenced_buf->size > fenced_mgr->max_cpu_total_size)
    522       return PIPE_ERROR_OUT_OF_MEMORY;
    523 
    524    fenced_buf->data = align_malloc(fenced_buf->size, fenced_buf->desc.alignment);
    525    if(!fenced_buf->data)
    526       return PIPE_ERROR_OUT_OF_MEMORY;
    527 
    528    fenced_mgr->cpu_total_size += fenced_buf->size;
    529 
    530    return PIPE_OK;
    531 }
    532 
    533 
    534 /**
    535  * Destroy the GPU storage.
    536  */
    537 static void
    538 fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf)
    539 {
    540    if(fenced_buf->buffer) {
    541       pb_reference(&fenced_buf->buffer, NULL);
    542    }
    543 }
    544 
    545 
    546 /**
    547  * Try to create GPU storage for this buffer.
    548  *
    549  * This function is a shorthand around pb_manager::create_buffer for
    550  * fenced_buffer_create_gpu_storage_locked()'s benefit.
    551  */
    552 static INLINE boolean
    553 fenced_buffer_try_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
    554                                             struct fenced_buffer *fenced_buf)
    555 {
    556    struct pb_manager *provider = fenced_mgr->provider;
    557 
    558    assert(!fenced_buf->buffer);
    559 
    560    fenced_buf->buffer = provider->create_buffer(fenced_mgr->provider,
    561                                                 fenced_buf->size,
    562                                                 &fenced_buf->desc);
    563    return fenced_buf->buffer ? TRUE : FALSE;
    564 }
    565 
    566 
    567 /**
    568  * Create GPU storage for this buffer.
    569  */
    570 static enum pipe_error
    571 fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
    572                                         struct fenced_buffer *fenced_buf,
    573                                         boolean wait)
    574 {
    575    assert(!fenced_buf->buffer);
    576 
    577    /*
    578     * Check for signaled buffers before trying to allocate.
    579     */
    580    fenced_manager_check_signalled_locked(fenced_mgr, FALSE);
    581 
    582    fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf);
    583 
    584    /*
    585     * Keep trying while there is some sort of progress:
    586     * - fences are expiring,
    587     * - or buffers are being being swapped out from GPU memory into CPU memory.
    588     */
    589    while(!fenced_buf->buffer &&
    590          (fenced_manager_check_signalled_locked(fenced_mgr, FALSE) ||
    591           fenced_manager_free_gpu_storage_locked(fenced_mgr))) {
    592       fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf);
    593    }
    594 
    595    if(!fenced_buf->buffer && wait) {
    596       /*
    597        * Same as before, but this time around, wait to free buffers if
    598        * necessary.
    599        */
    600       while(!fenced_buf->buffer &&
    601             (fenced_manager_check_signalled_locked(fenced_mgr, TRUE) ||
    602              fenced_manager_free_gpu_storage_locked(fenced_mgr))) {
    603          fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf);
    604       }
    605    }
    606 
    607    if(!fenced_buf->buffer) {
    608       if(0)
    609          fenced_manager_dump_locked(fenced_mgr);
    610 
    611       /* give up */
    612       return PIPE_ERROR_OUT_OF_MEMORY;
    613    }
    614 
    615    return PIPE_OK;
    616 }
    617 
    618 
    619 static enum pipe_error
    620 fenced_buffer_copy_storage_to_gpu_locked(struct fenced_buffer *fenced_buf)
    621 {
    622    uint8_t *map;
    623 
    624    assert(fenced_buf->data);
    625    assert(fenced_buf->buffer);
    626 
    627    map = pb_map(fenced_buf->buffer, PB_USAGE_CPU_WRITE, NULL);
    628    if(!map)
    629       return PIPE_ERROR;
    630 
    631    memcpy(map, fenced_buf->data, fenced_buf->size);
    632 
    633    pb_unmap(fenced_buf->buffer);
    634 
    635    return PIPE_OK;
    636 }
    637 
    638 
    639 static enum pipe_error
    640 fenced_buffer_copy_storage_to_cpu_locked(struct fenced_buffer *fenced_buf)
    641 {
    642    const uint8_t *map;
    643 
    644    assert(fenced_buf->data);
    645    assert(fenced_buf->buffer);
    646 
    647    map = pb_map(fenced_buf->buffer, PB_USAGE_CPU_READ, NULL);
    648    if(!map)
    649       return PIPE_ERROR;
    650 
    651    memcpy(fenced_buf->data, map, fenced_buf->size);
    652 
    653    pb_unmap(fenced_buf->buffer);
    654 
    655    return PIPE_OK;
    656 }
    657 
    658 
    659 static void
    660 fenced_buffer_destroy(struct pb_buffer *buf)
    661 {
    662    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    663    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    664 
    665    assert(!pipe_is_referenced(&fenced_buf->base.reference));
    666 
    667    pipe_mutex_lock(fenced_mgr->mutex);
    668 
    669    fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
    670 
    671    pipe_mutex_unlock(fenced_mgr->mutex);
    672 }
    673 
    674 
    675 static void *
    676 fenced_buffer_map(struct pb_buffer *buf,
    677                   unsigned flags, void *flush_ctx)
    678 {
    679    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    680    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    681    struct pb_fence_ops *ops = fenced_mgr->ops;
    682    void *map = NULL;
    683 
    684    pipe_mutex_lock(fenced_mgr->mutex);
    685 
    686    assert(!(flags & PB_USAGE_GPU_READ_WRITE));
    687 
    688    /*
    689     * Serialize writes.
    690     */
    691    while((fenced_buf->flags & PB_USAGE_GPU_WRITE) ||
    692          ((fenced_buf->flags & PB_USAGE_GPU_READ) &&
    693           (flags & PB_USAGE_CPU_WRITE))) {
    694 
    695       /*
    696        * Don't wait for the GPU to finish accessing it, if blocking is forbidden.
    697        */
    698       if((flags & PB_USAGE_DONTBLOCK) &&
    699           ops->fence_signalled(ops, fenced_buf->fence, 0) != 0) {
    700          goto done;
    701       }
    702 
    703       if (flags & PB_USAGE_UNSYNCHRONIZED) {
    704          break;
    705       }
    706 
    707       /*
    708        * Wait for the GPU to finish accessing. This will release and re-acquire
    709        * the mutex, so all copies of mutable state must be discarded.
    710        */
    711       fenced_buffer_finish_locked(fenced_mgr, fenced_buf);
    712    }
    713 
    714    if(fenced_buf->buffer) {
    715       map = pb_map(fenced_buf->buffer, flags, flush_ctx);
    716    }
    717    else {
    718       assert(fenced_buf->data);
    719       map = fenced_buf->data;
    720    }
    721 
    722    if(map) {
    723       ++fenced_buf->mapcount;
    724       fenced_buf->flags |= flags & PB_USAGE_CPU_READ_WRITE;
    725    }
    726 
    727 done:
    728    pipe_mutex_unlock(fenced_mgr->mutex);
    729 
    730    return map;
    731 }
    732 
    733 
    734 static void
    735 fenced_buffer_unmap(struct pb_buffer *buf)
    736 {
    737    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    738    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    739 
    740    pipe_mutex_lock(fenced_mgr->mutex);
    741 
    742    assert(fenced_buf->mapcount);
    743    if(fenced_buf->mapcount) {
    744       if (fenced_buf->buffer)
    745          pb_unmap(fenced_buf->buffer);
    746       --fenced_buf->mapcount;
    747       if(!fenced_buf->mapcount)
    748 	 fenced_buf->flags &= ~PB_USAGE_CPU_READ_WRITE;
    749    }
    750 
    751    pipe_mutex_unlock(fenced_mgr->mutex);
    752 }
    753 
    754 
    755 static enum pipe_error
    756 fenced_buffer_validate(struct pb_buffer *buf,
    757                        struct pb_validate *vl,
    758                        unsigned flags)
    759 {
    760    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    761    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    762    enum pipe_error ret;
    763 
    764    pipe_mutex_lock(fenced_mgr->mutex);
    765 
    766    if(!vl) {
    767       /* invalidate */
    768       fenced_buf->vl = NULL;
    769       fenced_buf->validation_flags = 0;
    770       ret = PIPE_OK;
    771       goto done;
    772    }
    773 
    774    assert(flags & PB_USAGE_GPU_READ_WRITE);
    775    assert(!(flags & ~PB_USAGE_GPU_READ_WRITE));
    776    flags &= PB_USAGE_GPU_READ_WRITE;
    777 
    778    /* Buffer cannot be validated in two different lists */
    779    if(fenced_buf->vl && fenced_buf->vl != vl) {
    780       ret = PIPE_ERROR_RETRY;
    781       goto done;
    782    }
    783 
    784    if(fenced_buf->vl == vl &&
    785       (fenced_buf->validation_flags & flags) == flags) {
    786       /* Nothing to do -- buffer already validated */
    787       ret = PIPE_OK;
    788       goto done;
    789    }
    790 
    791    /*
    792     * Create and update GPU storage.
    793     */
    794    if(!fenced_buf->buffer) {
    795       assert(!fenced_buf->mapcount);
    796 
    797       ret = fenced_buffer_create_gpu_storage_locked(fenced_mgr, fenced_buf, TRUE);
    798       if(ret != PIPE_OK) {
    799          goto done;
    800       }
    801 
    802       ret = fenced_buffer_copy_storage_to_gpu_locked(fenced_buf);
    803       if(ret != PIPE_OK) {
    804          fenced_buffer_destroy_gpu_storage_locked(fenced_buf);
    805          goto done;
    806       }
    807 
    808       if(fenced_buf->mapcount) {
    809          debug_printf("warning: validating a buffer while it is still mapped\n");
    810       }
    811       else {
    812          fenced_buffer_destroy_cpu_storage_locked(fenced_buf);
    813       }
    814    }
    815 
    816    ret = pb_validate(fenced_buf->buffer, vl, flags);
    817    if (ret != PIPE_OK)
    818       goto done;
    819 
    820    fenced_buf->vl = vl;
    821    fenced_buf->validation_flags |= flags;
    822 
    823 done:
    824    pipe_mutex_unlock(fenced_mgr->mutex);
    825 
    826    return ret;
    827 }
    828 
    829 
    830 static void
    831 fenced_buffer_fence(struct pb_buffer *buf,
    832                     struct pipe_fence_handle *fence)
    833 {
    834    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    835    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    836    struct pb_fence_ops *ops = fenced_mgr->ops;
    837 
    838    pipe_mutex_lock(fenced_mgr->mutex);
    839 
    840    assert(pipe_is_referenced(&fenced_buf->base.reference));
    841    assert(fenced_buf->buffer);
    842 
    843    if(fence != fenced_buf->fence) {
    844       assert(fenced_buf->vl);
    845       assert(fenced_buf->validation_flags);
    846 
    847       if (fenced_buf->fence) {
    848          boolean destroyed;
    849          destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
    850          assert(!destroyed);
    851       }
    852       if (fence) {
    853          ops->fence_reference(ops, &fenced_buf->fence, fence);
    854          fenced_buf->flags |= fenced_buf->validation_flags;
    855          fenced_buffer_add_locked(fenced_mgr, fenced_buf);
    856       }
    857 
    858       pb_fence(fenced_buf->buffer, fence);
    859 
    860       fenced_buf->vl = NULL;
    861       fenced_buf->validation_flags = 0;
    862    }
    863 
    864    pipe_mutex_unlock(fenced_mgr->mutex);
    865 }
    866 
    867 
    868 static void
    869 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
    870                               struct pb_buffer **base_buf,
    871                               pb_size *offset)
    872 {
    873    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
    874    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
    875 
    876    pipe_mutex_lock(fenced_mgr->mutex);
    877 
    878    /*
    879     * This should only be called when the buffer is validated. Typically
    880     * when processing relocations.
    881     */
    882    assert(fenced_buf->vl);
    883    assert(fenced_buf->buffer);
    884 
    885    if(fenced_buf->buffer)
    886       pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
    887    else {
    888       *base_buf = buf;
    889       *offset = 0;
    890    }
    891 
    892    pipe_mutex_unlock(fenced_mgr->mutex);
    893 }
    894 
    895 
    896 static const struct pb_vtbl
    897 fenced_buffer_vtbl = {
    898       fenced_buffer_destroy,
    899       fenced_buffer_map,
    900       fenced_buffer_unmap,
    901       fenced_buffer_validate,
    902       fenced_buffer_fence,
    903       fenced_buffer_get_base_buffer
    904 };
    905 
    906 
    907 /**
    908  * Wrap a buffer in a fenced buffer.
    909  */
    910 static struct pb_buffer *
    911 fenced_bufmgr_create_buffer(struct pb_manager *mgr,
    912                             pb_size size,
    913                             const struct pb_desc *desc)
    914 {
    915    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
    916    struct fenced_buffer *fenced_buf;
    917    enum pipe_error ret;
    918 
    919    /*
    920     * Don't stall the GPU, waste time evicting buffers, or waste memory
    921     * trying to create a buffer that will most likely never fit into the
    922     * graphics aperture.
    923     */
    924    if(size > fenced_mgr->max_buffer_size) {
    925       goto no_buffer;
    926    }
    927 
    928    fenced_buf = CALLOC_STRUCT(fenced_buffer);
    929    if(!fenced_buf)
    930       goto no_buffer;
    931 
    932    pipe_reference_init(&fenced_buf->base.reference, 1);
    933    fenced_buf->base.alignment = desc->alignment;
    934    fenced_buf->base.usage = desc->usage;
    935    fenced_buf->base.size = size;
    936    fenced_buf->size = size;
    937    fenced_buf->desc = *desc;
    938 
    939    fenced_buf->base.vtbl = &fenced_buffer_vtbl;
    940    fenced_buf->mgr = fenced_mgr;
    941 
    942    pipe_mutex_lock(fenced_mgr->mutex);
    943 
    944    /*
    945     * Try to create GPU storage without stalling,
    946     */
    947    ret = fenced_buffer_create_gpu_storage_locked(fenced_mgr, fenced_buf, FALSE);
    948 
    949    /*
    950     * Attempt to use CPU memory to avoid stalling the GPU.
    951     */
    952    if(ret != PIPE_OK) {
    953       ret = fenced_buffer_create_cpu_storage_locked(fenced_mgr, fenced_buf);
    954    }
    955 
    956    /*
    957     * Create GPU storage, waiting for some to be available.
    958     */
    959    if(ret != PIPE_OK) {
    960       ret = fenced_buffer_create_gpu_storage_locked(fenced_mgr, fenced_buf, TRUE);
    961    }
    962 
    963    /*
    964     * Give up.
    965     */
    966    if(ret != PIPE_OK) {
    967       goto no_storage;
    968    }
    969 
    970    assert(fenced_buf->buffer || fenced_buf->data);
    971 
    972    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
    973    ++fenced_mgr->num_unfenced;
    974    pipe_mutex_unlock(fenced_mgr->mutex);
    975 
    976    return &fenced_buf->base;
    977 
    978 no_storage:
    979    pipe_mutex_unlock(fenced_mgr->mutex);
    980    FREE(fenced_buf);
    981 no_buffer:
    982    return NULL;
    983 }
    984 
    985 
    986 static void
    987 fenced_bufmgr_flush(struct pb_manager *mgr)
    988 {
    989    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
    990 
    991    pipe_mutex_lock(fenced_mgr->mutex);
    992    while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
    993       ;
    994    pipe_mutex_unlock(fenced_mgr->mutex);
    995 
    996    assert(fenced_mgr->provider->flush);
    997    if(fenced_mgr->provider->flush)
    998       fenced_mgr->provider->flush(fenced_mgr->provider);
    999 }
   1000 
   1001 
   1002 static void
   1003 fenced_bufmgr_destroy(struct pb_manager *mgr)
   1004 {
   1005    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
   1006 
   1007    pipe_mutex_lock(fenced_mgr->mutex);
   1008 
   1009    /* Wait on outstanding fences */
   1010    while (fenced_mgr->num_fenced) {
   1011       pipe_mutex_unlock(fenced_mgr->mutex);
   1012 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)
   1013       sched_yield();
   1014 #endif
   1015       pipe_mutex_lock(fenced_mgr->mutex);
   1016       while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
   1017          ;
   1018    }
   1019 
   1020 #ifdef DEBUG
   1021    /*assert(!fenced_mgr->num_unfenced);*/
   1022 #endif
   1023 
   1024    pipe_mutex_unlock(fenced_mgr->mutex);
   1025    pipe_mutex_destroy(fenced_mgr->mutex);
   1026 
   1027    if(fenced_mgr->provider)
   1028       fenced_mgr->provider->destroy(fenced_mgr->provider);
   1029 
   1030    fenced_mgr->ops->destroy(fenced_mgr->ops);
   1031 
   1032    FREE(fenced_mgr);
   1033 }
   1034 
   1035 
   1036 struct pb_manager *
   1037 fenced_bufmgr_create(struct pb_manager *provider,
   1038                      struct pb_fence_ops *ops,
   1039                      pb_size max_buffer_size,
   1040                      pb_size max_cpu_total_size)
   1041 {
   1042    struct fenced_manager *fenced_mgr;
   1043 
   1044    if(!provider)
   1045       return NULL;
   1046 
   1047    fenced_mgr = CALLOC_STRUCT(fenced_manager);
   1048    if (!fenced_mgr)
   1049       return NULL;
   1050 
   1051    fenced_mgr->base.destroy = fenced_bufmgr_destroy;
   1052    fenced_mgr->base.create_buffer = fenced_bufmgr_create_buffer;
   1053    fenced_mgr->base.flush = fenced_bufmgr_flush;
   1054 
   1055    fenced_mgr->provider = provider;
   1056    fenced_mgr->ops = ops;
   1057    fenced_mgr->max_buffer_size = max_buffer_size;
   1058    fenced_mgr->max_cpu_total_size = max_cpu_total_size;
   1059 
   1060    LIST_INITHEAD(&fenced_mgr->fenced);
   1061    fenced_mgr->num_fenced = 0;
   1062 
   1063    LIST_INITHEAD(&fenced_mgr->unfenced);
   1064    fenced_mgr->num_unfenced = 0;
   1065 
   1066    pipe_mutex_init(fenced_mgr->mutex);
   1067 
   1068    return &fenced_mgr->base;
   1069 }
   1070