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