• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007-2015 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 Hellström <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 "pipebuffer/pb_buffer.h"
53 #include "pipebuffer/pb_bufmgr.h"
54 #include "pipebuffer/pb_buffer_fenced.h"
55 #include "vmw_screen.h"
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     * Following members are mutable and protected by this mutex.
72     */
73    mtx_t mutex;
74 
75    /**
76     * Fenced buffer list.
77     *
78     * All fenced buffers are placed in this listed, ordered from the oldest
79     * fence to the newest fence.
80     */
81    struct list_head fenced;
82    pb_size num_fenced;
83 
84    struct list_head unfenced;
85    pb_size num_unfenced;
86 
87 };
88 
89 
90 /**
91  * Fenced buffer.
92  *
93  * Wrapper around a pipe buffer which adds fencing and reference counting.
94  */
95 struct fenced_buffer
96 {
97    /*
98     * Immutable members.
99     */
100 
101    struct pb_buffer base;
102    struct fenced_manager *mgr;
103 
104    /*
105     * Following members are mutable and protected by fenced_manager::mutex.
106     */
107 
108    struct list_head head;
109 
110    /**
111     * Buffer with storage.
112     */
113    struct pb_buffer *buffer;
114    pb_size size;
115 
116    /**
117     * A bitmask of PB_USAGE_CPU/GPU_READ/WRITE describing the current
118     * buffer usage.
119     */
120    unsigned flags;
121 
122    unsigned mapcount;
123 
124    struct pb_validate *vl;
125    unsigned validation_flags;
126 
127    struct pipe_fence_handle *fence;
128 };
129 
130 
131 static inline struct fenced_manager *
fenced_manager(struct pb_manager * mgr)132 fenced_manager(struct pb_manager *mgr)
133 {
134    assert(mgr);
135    return (struct fenced_manager *)mgr;
136 }
137 
138 
139 static inline struct fenced_buffer *
fenced_buffer(struct pb_buffer * buf)140 fenced_buffer(struct pb_buffer *buf)
141 {
142    assert(buf);
143    return (struct fenced_buffer *)buf;
144 }
145 
146 
147 static void
148 fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf);
149 
150 static enum pipe_error
151 fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
152                                         struct fenced_buffer *fenced_buf,
153                                         const struct pb_desc *desc,
154                                         boolean wait);
155 /**
156  * Dump the fenced buffer list.
157  *
158  * Useful to understand failures to allocate buffers.
159  */
160 static void
fenced_manager_dump_locked(struct fenced_manager * fenced_mgr)161 fenced_manager_dump_locked(struct fenced_manager *fenced_mgr)
162 {
163 #ifdef DEBUG
164    struct pb_fence_ops *ops = fenced_mgr->ops;
165    struct list_head *curr, *next;
166    struct fenced_buffer *fenced_buf;
167 
168    debug_printf("%10s %7s %8s %7s %10s %s\n",
169                 "buffer", "size", "refcount", "storage", "fence", "signalled");
170 
171    curr = fenced_mgr->unfenced.next;
172    next = curr->next;
173    while(curr != &fenced_mgr->unfenced) {
174       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
175       assert(!fenced_buf->fence);
176       debug_printf("%10p %"PRIu64" %8u %7s\n",
177                    (void *) fenced_buf,
178                    fenced_buf->base.size,
179                    p_atomic_read(&fenced_buf->base.reference.count),
180                    fenced_buf->buffer ? "gpu" : "none");
181       curr = next;
182       next = curr->next;
183    }
184 
185    curr = fenced_mgr->fenced.next;
186    next = curr->next;
187    while(curr != &fenced_mgr->fenced) {
188       int signaled;
189       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
190       assert(fenced_buf->buffer);
191       signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
192       debug_printf("%10p %"PRIu64" %8u %7s %10p %s\n",
193                    (void *) fenced_buf,
194                    fenced_buf->base.size,
195                    p_atomic_read(&fenced_buf->base.reference.count),
196                    "gpu",
197                    (void *) fenced_buf->fence,
198                    signaled == 0 ? "y" : "n");
199       curr = next;
200       next = curr->next;
201    }
202 #else
203    (void)fenced_mgr;
204 #endif
205 }
206 
207 
208 static inline void
fenced_buffer_destroy_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf)209 fenced_buffer_destroy_locked(struct fenced_manager *fenced_mgr,
210                              struct fenced_buffer *fenced_buf)
211 {
212    assert(!pipe_is_referenced(&fenced_buf->base.reference));
213 
214    assert(!fenced_buf->fence);
215    assert(fenced_buf->head.prev);
216    assert(fenced_buf->head.next);
217    LIST_DEL(&fenced_buf->head);
218    assert(fenced_mgr->num_unfenced);
219    --fenced_mgr->num_unfenced;
220 
221    fenced_buffer_destroy_gpu_storage_locked(fenced_buf);
222 
223    FREE(fenced_buf);
224 }
225 
226 
227 /**
228  * Add the buffer to the fenced list.
229  *
230  * Reference count should be incremented before calling this function.
231  */
232 static inline void
fenced_buffer_add_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf)233 fenced_buffer_add_locked(struct fenced_manager *fenced_mgr,
234                          struct fenced_buffer *fenced_buf)
235 {
236    assert(pipe_is_referenced(&fenced_buf->base.reference));
237    assert(fenced_buf->flags & PB_USAGE_GPU_READ_WRITE);
238    assert(fenced_buf->fence);
239 
240    p_atomic_inc(&fenced_buf->base.reference.count);
241 
242    LIST_DEL(&fenced_buf->head);
243    assert(fenced_mgr->num_unfenced);
244    --fenced_mgr->num_unfenced;
245    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->fenced);
246    ++fenced_mgr->num_fenced;
247 }
248 
249 
250 /**
251  * Remove the buffer from the fenced list, and potentially destroy the buffer
252  * if the reference count reaches zero.
253  *
254  * Returns TRUE if the buffer was detroyed.
255  */
256 static inline boolean
fenced_buffer_remove_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf)257 fenced_buffer_remove_locked(struct fenced_manager *fenced_mgr,
258                             struct fenced_buffer *fenced_buf)
259 {
260    struct pb_fence_ops *ops = fenced_mgr->ops;
261 
262    assert(fenced_buf->fence);
263    assert(fenced_buf->mgr == fenced_mgr);
264 
265    ops->fence_reference(ops, &fenced_buf->fence, NULL);
266    fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
267 
268    assert(fenced_buf->head.prev);
269    assert(fenced_buf->head.next);
270 
271    LIST_DEL(&fenced_buf->head);
272    assert(fenced_mgr->num_fenced);
273    --fenced_mgr->num_fenced;
274 
275    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
276    ++fenced_mgr->num_unfenced;
277 
278    if (p_atomic_dec_zero(&fenced_buf->base.reference.count)) {
279       fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
280       return TRUE;
281    }
282 
283    return FALSE;
284 }
285 
286 
287 /**
288  * Wait for the fence to expire, and remove it from the fenced list.
289  *
290  * This function will release and re-acquire the mutex, so any copy of mutable
291  * state must be discarded after calling it.
292  */
293 static inline enum pipe_error
fenced_buffer_finish_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf)294 fenced_buffer_finish_locked(struct fenced_manager *fenced_mgr,
295                             struct fenced_buffer *fenced_buf)
296 {
297    struct pb_fence_ops *ops = fenced_mgr->ops;
298    enum pipe_error ret = PIPE_ERROR;
299 
300 #if 0
301    debug_warning("waiting for GPU");
302 #endif
303 
304    assert(pipe_is_referenced(&fenced_buf->base.reference));
305    assert(fenced_buf->fence);
306 
307    if(fenced_buf->fence) {
308       struct pipe_fence_handle *fence = NULL;
309       int finished;
310       boolean proceed;
311 
312       ops->fence_reference(ops, &fence, fenced_buf->fence);
313 
314       mtx_unlock(&fenced_mgr->mutex);
315 
316       finished = ops->fence_finish(ops, fenced_buf->fence, 0);
317 
318       mtx_lock(&fenced_mgr->mutex);
319 
320       assert(pipe_is_referenced(&fenced_buf->base.reference));
321 
322       /*
323        * Only proceed if the fence object didn't change in the meanwhile.
324        * Otherwise assume the work has been already carried out by another
325        * thread that re-acquired the lock before us.
326        */
327       proceed = fence == fenced_buf->fence ? TRUE : FALSE;
328 
329       ops->fence_reference(ops, &fence, NULL);
330 
331       if(proceed && finished == 0) {
332          /*
333           * Remove from the fenced list
334           */
335 
336          boolean destroyed;
337 
338          destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
339 
340          /* TODO: remove consequents buffers with the same fence? */
341 
342          assert(!destroyed);
343          (void) destroyed;
344 
345          fenced_buf->flags &= ~PB_USAGE_GPU_READ_WRITE;
346 
347          ret = PIPE_OK;
348       }
349    }
350 
351    return ret;
352 }
353 
354 
355 /**
356  * Remove as many fenced buffers from the fenced list as possible.
357  *
358  * Returns TRUE if at least one buffer was removed.
359  */
360 static boolean
fenced_manager_check_signalled_locked(struct fenced_manager * fenced_mgr,boolean wait)361 fenced_manager_check_signalled_locked(struct fenced_manager *fenced_mgr,
362                                       boolean wait)
363 {
364    struct pb_fence_ops *ops = fenced_mgr->ops;
365    struct list_head *curr, *next;
366    struct fenced_buffer *fenced_buf;
367    struct pipe_fence_handle *prev_fence = NULL;
368    boolean ret = FALSE;
369 
370    curr = fenced_mgr->fenced.next;
371    next = curr->next;
372    while(curr != &fenced_mgr->fenced) {
373       fenced_buf = LIST_ENTRY(struct fenced_buffer, curr, head);
374 
375       if(fenced_buf->fence != prev_fence) {
376          int signaled;
377 
378          if (wait) {
379             signaled = ops->fence_finish(ops, fenced_buf->fence, 0);
380 
381             /*
382              * Don't return just now. Instead preemptively check if the
383              * following buffers' fences already expired,
384              * without further waits.
385              */
386             wait = FALSE;
387          }
388          else {
389             signaled = ops->fence_signalled(ops, fenced_buf->fence, 0);
390          }
391 
392          if (signaled != 0) {
393             return ret;
394          }
395 
396          prev_fence = fenced_buf->fence;
397       }
398       else {
399          /* This buffer's fence object is identical to the previous buffer's
400           * fence object, so no need to check the fence again.
401           */
402          assert(ops->fence_signalled(ops, fenced_buf->fence, 0) == 0);
403       }
404 
405       fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
406 
407       ret = TRUE;
408 
409       curr = next;
410       next = curr->next;
411    }
412 
413    return ret;
414 }
415 
416 
417 /**
418  * Destroy the GPU storage.
419  */
420 static void
fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer * fenced_buf)421 fenced_buffer_destroy_gpu_storage_locked(struct fenced_buffer *fenced_buf)
422 {
423    if(fenced_buf->buffer) {
424       pb_reference(&fenced_buf->buffer, NULL);
425    }
426 }
427 
428 
429 /**
430  * Try to create GPU storage for this buffer.
431  *
432  * This function is a shorthand around pb_manager::create_buffer for
433  * fenced_buffer_create_gpu_storage_locked()'s benefit.
434  */
435 static inline boolean
fenced_buffer_try_create_gpu_storage_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf,const struct pb_desc * desc)436 fenced_buffer_try_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
437                                             struct fenced_buffer *fenced_buf,
438                                             const struct pb_desc *desc)
439 {
440    struct pb_manager *provider = fenced_mgr->provider;
441 
442    assert(!fenced_buf->buffer);
443 
444    fenced_buf->buffer = provider->create_buffer(fenced_mgr->provider,
445                                                 fenced_buf->size, desc);
446    return fenced_buf->buffer ? TRUE : FALSE;
447 }
448 
449 
450 /**
451  * Create GPU storage for this buffer.
452  */
453 static enum pipe_error
fenced_buffer_create_gpu_storage_locked(struct fenced_manager * fenced_mgr,struct fenced_buffer * fenced_buf,const struct pb_desc * desc,boolean wait)454 fenced_buffer_create_gpu_storage_locked(struct fenced_manager *fenced_mgr,
455                                         struct fenced_buffer *fenced_buf,
456                                         const struct pb_desc *desc,
457                                         boolean wait)
458 {
459    assert(!fenced_buf->buffer);
460 
461    /*
462     * Check for signaled buffers before trying to allocate.
463     */
464    fenced_manager_check_signalled_locked(fenced_mgr, FALSE);
465 
466    fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf, desc);
467 
468    /*
469     * Keep trying while there is some sort of progress:
470     * - fences are expiring,
471     * - or buffers are being being swapped out from GPU memory into CPU memory.
472     */
473    while(!fenced_buf->buffer &&
474          (fenced_manager_check_signalled_locked(fenced_mgr, FALSE))) {
475      fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf,
476                                                  desc);
477    }
478 
479    if(!fenced_buf->buffer && wait) {
480       /*
481        * Same as before, but this time around, wait to free buffers if
482        * necessary.
483        */
484       while(!fenced_buf->buffer &&
485             (fenced_manager_check_signalled_locked(fenced_mgr, TRUE))) {
486         fenced_buffer_try_create_gpu_storage_locked(fenced_mgr, fenced_buf,
487                                                     desc);
488       }
489    }
490 
491    if(!fenced_buf->buffer) {
492       if(0)
493          fenced_manager_dump_locked(fenced_mgr);
494 
495       /* give up */
496       return PIPE_ERROR_OUT_OF_MEMORY;
497    }
498 
499    return PIPE_OK;
500 }
501 
502 
503 static void
fenced_buffer_destroy(struct pb_buffer * buf)504 fenced_buffer_destroy(struct pb_buffer *buf)
505 {
506    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
507    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
508 
509    assert(!pipe_is_referenced(&fenced_buf->base.reference));
510 
511    mtx_lock(&fenced_mgr->mutex);
512 
513    fenced_buffer_destroy_locked(fenced_mgr, fenced_buf);
514 
515    mtx_unlock(&fenced_mgr->mutex);
516 }
517 
518 
519 static void *
fenced_buffer_map(struct pb_buffer * buf,unsigned flags,void * flush_ctx)520 fenced_buffer_map(struct pb_buffer *buf,
521                   unsigned flags, void *flush_ctx)
522 {
523    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
524    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
525    struct pb_fence_ops *ops = fenced_mgr->ops;
526    void *map = NULL;
527 
528    mtx_lock(&fenced_mgr->mutex);
529 
530    assert(!(flags & PB_USAGE_GPU_READ_WRITE));
531 
532    /*
533     * Serialize writes.
534     */
535    while((fenced_buf->flags & PB_USAGE_GPU_WRITE) ||
536          ((fenced_buf->flags & PB_USAGE_GPU_READ) &&
537           (flags & PB_USAGE_CPU_WRITE))) {
538 
539       /*
540        * Don't wait for the GPU to finish accessing it,
541        * if blocking is forbidden.
542        */
543       if((flags & PB_USAGE_DONTBLOCK) &&
544           ops->fence_signalled(ops, fenced_buf->fence, 0) != 0) {
545          goto done;
546       }
547 
548       if (flags & PB_USAGE_UNSYNCHRONIZED) {
549          break;
550       }
551 
552       /*
553        * Wait for the GPU to finish accessing. This will release and re-acquire
554        * the mutex, so all copies of mutable state must be discarded.
555        */
556       fenced_buffer_finish_locked(fenced_mgr, fenced_buf);
557    }
558 
559    map = pb_map(fenced_buf->buffer, flags, flush_ctx);
560 
561    if(map) {
562       ++fenced_buf->mapcount;
563       fenced_buf->flags |= flags & PB_USAGE_CPU_READ_WRITE;
564    }
565 
566 done:
567    mtx_unlock(&fenced_mgr->mutex);
568 
569    return map;
570 }
571 
572 
573 static void
fenced_buffer_unmap(struct pb_buffer * buf)574 fenced_buffer_unmap(struct pb_buffer *buf)
575 {
576    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
577    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
578 
579    mtx_lock(&fenced_mgr->mutex);
580 
581    assert(fenced_buf->mapcount);
582    if(fenced_buf->mapcount) {
583       if (fenced_buf->buffer)
584          pb_unmap(fenced_buf->buffer);
585       --fenced_buf->mapcount;
586       if(!fenced_buf->mapcount)
587          fenced_buf->flags &= ~PB_USAGE_CPU_READ_WRITE;
588    }
589 
590    mtx_unlock(&fenced_mgr->mutex);
591 }
592 
593 
594 static enum pipe_error
fenced_buffer_validate(struct pb_buffer * buf,struct pb_validate * vl,unsigned flags)595 fenced_buffer_validate(struct pb_buffer *buf,
596                        struct pb_validate *vl,
597                        unsigned flags)
598 {
599    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
600    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
601    enum pipe_error ret;
602 
603    mtx_lock(&fenced_mgr->mutex);
604 
605    if(!vl) {
606       /* invalidate */
607       fenced_buf->vl = NULL;
608       fenced_buf->validation_flags = 0;
609       ret = PIPE_OK;
610       goto done;
611    }
612 
613    assert(flags & PB_USAGE_GPU_READ_WRITE);
614    assert(!(flags & ~PB_USAGE_GPU_READ_WRITE));
615    flags &= PB_USAGE_GPU_READ_WRITE;
616 
617    /* Buffer cannot be validated in two different lists */
618    if(fenced_buf->vl && fenced_buf->vl != vl) {
619       ret = PIPE_ERROR_RETRY;
620       goto done;
621    }
622 
623    if(fenced_buf->vl == vl &&
624       (fenced_buf->validation_flags & flags) == flags) {
625       /* Nothing to do -- buffer already validated */
626       ret = PIPE_OK;
627       goto done;
628    }
629 
630    ret = pb_validate(fenced_buf->buffer, vl, flags);
631    if (ret != PIPE_OK)
632       goto done;
633 
634    fenced_buf->vl = vl;
635    fenced_buf->validation_flags |= flags;
636 
637 done:
638    mtx_unlock(&fenced_mgr->mutex);
639 
640    return ret;
641 }
642 
643 
644 static void
fenced_buffer_fence(struct pb_buffer * buf,struct pipe_fence_handle * fence)645 fenced_buffer_fence(struct pb_buffer *buf,
646                     struct pipe_fence_handle *fence)
647 {
648    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
649    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
650    struct pb_fence_ops *ops = fenced_mgr->ops;
651 
652    mtx_lock(&fenced_mgr->mutex);
653 
654    assert(pipe_is_referenced(&fenced_buf->base.reference));
655    assert(fenced_buf->buffer);
656 
657    if(fence != fenced_buf->fence) {
658       assert(fenced_buf->vl);
659       assert(fenced_buf->validation_flags);
660 
661       if (fenced_buf->fence) {
662          boolean destroyed;
663          destroyed = fenced_buffer_remove_locked(fenced_mgr, fenced_buf);
664          assert(!destroyed);
665          (void) destroyed;
666       }
667       if (fence) {
668          ops->fence_reference(ops, &fenced_buf->fence, fence);
669          fenced_buf->flags |= fenced_buf->validation_flags;
670          fenced_buffer_add_locked(fenced_mgr, fenced_buf);
671       }
672 
673       pb_fence(fenced_buf->buffer, fence);
674 
675       fenced_buf->vl = NULL;
676       fenced_buf->validation_flags = 0;
677    }
678 
679    mtx_unlock(&fenced_mgr->mutex);
680 }
681 
682 
683 static void
fenced_buffer_get_base_buffer(struct pb_buffer * buf,struct pb_buffer ** base_buf,pb_size * offset)684 fenced_buffer_get_base_buffer(struct pb_buffer *buf,
685                               struct pb_buffer **base_buf,
686                               pb_size *offset)
687 {
688    struct fenced_buffer *fenced_buf = fenced_buffer(buf);
689    struct fenced_manager *fenced_mgr = fenced_buf->mgr;
690 
691    mtx_lock(&fenced_mgr->mutex);
692 
693    assert(fenced_buf->buffer);
694 
695    if(fenced_buf->buffer)
696       pb_get_base_buffer(fenced_buf->buffer, base_buf, offset);
697    else {
698       *base_buf = buf;
699       *offset = 0;
700    }
701 
702    mtx_unlock(&fenced_mgr->mutex);
703 }
704 
705 
706 static const struct pb_vtbl
707 fenced_buffer_vtbl = {
708       fenced_buffer_destroy,
709       fenced_buffer_map,
710       fenced_buffer_unmap,
711       fenced_buffer_validate,
712       fenced_buffer_fence,
713       fenced_buffer_get_base_buffer
714 };
715 
716 
717 /**
718  * Wrap a buffer in a fenced buffer.
719  */
720 static struct pb_buffer *
fenced_bufmgr_create_buffer(struct pb_manager * mgr,pb_size size,const struct pb_desc * desc)721 fenced_bufmgr_create_buffer(struct pb_manager *mgr,
722                             pb_size size,
723                             const struct pb_desc *desc)
724 {
725    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
726    struct fenced_buffer *fenced_buf;
727    enum pipe_error ret;
728 
729    fenced_buf = CALLOC_STRUCT(fenced_buffer);
730    if(!fenced_buf)
731       goto no_buffer;
732 
733    pipe_reference_init(&fenced_buf->base.reference, 1);
734    fenced_buf->base.alignment = desc->alignment;
735    fenced_buf->base.usage = desc->usage;
736    fenced_buf->base.size = size;
737    fenced_buf->size = size;
738 
739    fenced_buf->base.vtbl = &fenced_buffer_vtbl;
740    fenced_buf->mgr = fenced_mgr;
741 
742    mtx_lock(&fenced_mgr->mutex);
743 
744    /*
745     * Try to create GPU storage without stalling,
746     */
747    ret = fenced_buffer_create_gpu_storage_locked(fenced_mgr, fenced_buf,
748                                                  desc, TRUE);
749 
750    /*
751     * Give up.
752     */
753    if(ret != PIPE_OK) {
754       goto no_storage;
755    }
756 
757    assert(fenced_buf->buffer);
758 
759    LIST_ADDTAIL(&fenced_buf->head, &fenced_mgr->unfenced);
760    ++fenced_mgr->num_unfenced;
761    mtx_unlock(&fenced_mgr->mutex);
762 
763    return &fenced_buf->base;
764 
765 no_storage:
766    mtx_unlock(&fenced_mgr->mutex);
767    FREE(fenced_buf);
768 no_buffer:
769    return NULL;
770 }
771 
772 
773 static void
fenced_bufmgr_flush(struct pb_manager * mgr)774 fenced_bufmgr_flush(struct pb_manager *mgr)
775 {
776    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
777 
778    mtx_lock(&fenced_mgr->mutex);
779    while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
780       ;
781    mtx_unlock(&fenced_mgr->mutex);
782 
783    assert(fenced_mgr->provider->flush);
784    if(fenced_mgr->provider->flush)
785       fenced_mgr->provider->flush(fenced_mgr->provider);
786 }
787 
788 
789 static void
fenced_bufmgr_destroy(struct pb_manager * mgr)790 fenced_bufmgr_destroy(struct pb_manager *mgr)
791 {
792    struct fenced_manager *fenced_mgr = fenced_manager(mgr);
793 
794    mtx_lock(&fenced_mgr->mutex);
795 
796    /* Wait on outstanding fences */
797    while (fenced_mgr->num_fenced) {
798       mtx_unlock(&fenced_mgr->mutex);
799 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)
800       sched_yield();
801 #endif
802       mtx_lock(&fenced_mgr->mutex);
803       while(fenced_manager_check_signalled_locked(fenced_mgr, TRUE))
804          ;
805    }
806 
807 #ifdef DEBUG
808    /*assert(!fenced_mgr->num_unfenced);*/
809 #endif
810 
811    mtx_unlock(&fenced_mgr->mutex);
812    mtx_destroy(&fenced_mgr->mutex);
813 
814    FREE(fenced_mgr);
815 }
816 
817 
818 struct pb_manager *
simple_fenced_bufmgr_create(struct pb_manager * provider,struct pb_fence_ops * ops)819 simple_fenced_bufmgr_create(struct pb_manager *provider,
820                             struct pb_fence_ops *ops)
821 {
822    struct fenced_manager *fenced_mgr;
823 
824    if(!provider)
825       return NULL;
826 
827    fenced_mgr = CALLOC_STRUCT(fenced_manager);
828    if (!fenced_mgr)
829       return NULL;
830 
831    fenced_mgr->base.destroy = fenced_bufmgr_destroy;
832    fenced_mgr->base.create_buffer = fenced_bufmgr_create_buffer;
833    fenced_mgr->base.flush = fenced_bufmgr_flush;
834 
835    fenced_mgr->provider = provider;
836    fenced_mgr->ops = ops;
837 
838    LIST_INITHEAD(&fenced_mgr->fenced);
839    fenced_mgr->num_fenced = 0;
840 
841    LIST_INITHEAD(&fenced_mgr->unfenced);
842    fenced_mgr->num_unfenced = 0;
843 
844    (void) mtx_init(&fenced_mgr->mutex, mtx_plain);
845 
846    return &fenced_mgr->base;
847 }
848