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