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