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