1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014-2015 Broadcom 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <errno.h> 25bf215546Sopenharmony_ci#include <err.h> 26bf215546Sopenharmony_ci#include <sys/mman.h> 27bf215546Sopenharmony_ci#include <fcntl.h> 28bf215546Sopenharmony_ci#include <xf86drm.h> 29bf215546Sopenharmony_ci#include <xf86drmMode.h> 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "util/u_hash_table.h" 32bf215546Sopenharmony_ci#include "util/u_memory.h" 33bf215546Sopenharmony_ci#include "util/u_string.h" 34bf215546Sopenharmony_ci#include "util/ralloc.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "vc4_context.h" 37bf215546Sopenharmony_ci#include "vc4_screen.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_cistatic bool dump_stats = false; 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic void 42bf215546Sopenharmony_civc4_bo_cache_free_all(struct vc4_bo_cache *cache); 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_civoid 45bf215546Sopenharmony_civc4_bo_debug_describe(char* buf, const struct vc4_bo *ptr) 46bf215546Sopenharmony_ci{ 47bf215546Sopenharmony_ci sprintf(buf, "vc4_bo<%s,%u,%u>", ptr->name ? ptr->name : "?", 48bf215546Sopenharmony_ci ptr->handle, ptr->size); 49bf215546Sopenharmony_ci} 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_civoid 52bf215546Sopenharmony_civc4_bo_label(struct vc4_screen *screen, struct vc4_bo *bo, const char *fmt, ...) 53bf215546Sopenharmony_ci{ 54bf215546Sopenharmony_ci /* Perform BO labeling by default on debug builds (so that you get 55bf215546Sopenharmony_ci * whole-system allocation information), or if VC4_DEBUG=surf is set 56bf215546Sopenharmony_ci * (for debugging a single app's allocation). 57bf215546Sopenharmony_ci */ 58bf215546Sopenharmony_ci#ifndef DEBUG 59bf215546Sopenharmony_ci if (!(vc4_debug & VC4_DEBUG_SURFACE)) 60bf215546Sopenharmony_ci return; 61bf215546Sopenharmony_ci#endif 62bf215546Sopenharmony_ci va_list va; 63bf215546Sopenharmony_ci va_start(va, fmt); 64bf215546Sopenharmony_ci char *name = ralloc_vasprintf(NULL, fmt, va); 65bf215546Sopenharmony_ci va_end(va); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci struct drm_vc4_label_bo label = { 68bf215546Sopenharmony_ci .handle = bo->handle, 69bf215546Sopenharmony_ci .len = strlen(name), 70bf215546Sopenharmony_ci .name = (uintptr_t)name, 71bf215546Sopenharmony_ci }; 72bf215546Sopenharmony_ci vc4_ioctl(screen->fd, DRM_IOCTL_VC4_LABEL_BO, &label); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci ralloc_free(name); 75bf215546Sopenharmony_ci} 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_cistatic void 78bf215546Sopenharmony_civc4_bo_dump_stats(struct vc4_screen *screen) 79bf215546Sopenharmony_ci{ 80bf215546Sopenharmony_ci struct vc4_bo_cache *cache = &screen->bo_cache; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci fprintf(stderr, " BOs allocated: %d\n", screen->bo_count); 83bf215546Sopenharmony_ci fprintf(stderr, " BOs size: %dkb\n", screen->bo_size / 1024); 84bf215546Sopenharmony_ci fprintf(stderr, " BOs cached: %d\n", cache->bo_count); 85bf215546Sopenharmony_ci fprintf(stderr, " BOs cached size: %dkb\n", cache->bo_size / 1024); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci if (!list_is_empty(&cache->time_list)) { 88bf215546Sopenharmony_ci struct vc4_bo *first = list_entry(cache->time_list.next, 89bf215546Sopenharmony_ci struct vc4_bo, 90bf215546Sopenharmony_ci time_list); 91bf215546Sopenharmony_ci struct vc4_bo *last = list_entry(cache->time_list.prev, 92bf215546Sopenharmony_ci struct vc4_bo, 93bf215546Sopenharmony_ci time_list); 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci fprintf(stderr, " oldest cache time: %ld\n", 96bf215546Sopenharmony_ci (long)first->free_time); 97bf215546Sopenharmony_ci fprintf(stderr, " newest cache time: %ld\n", 98bf215546Sopenharmony_ci (long)last->free_time); 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci struct timespec time; 101bf215546Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &time); 102bf215546Sopenharmony_ci fprintf(stderr, " now: %jd\n", 103bf215546Sopenharmony_ci (intmax_t)time.tv_sec); 104bf215546Sopenharmony_ci } 105bf215546Sopenharmony_ci} 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_cistatic void 108bf215546Sopenharmony_civc4_bo_remove_from_cache(struct vc4_bo_cache *cache, struct vc4_bo *bo) 109bf215546Sopenharmony_ci{ 110bf215546Sopenharmony_ci list_del(&bo->time_list); 111bf215546Sopenharmony_ci list_del(&bo->size_list); 112bf215546Sopenharmony_ci cache->bo_count--; 113bf215546Sopenharmony_ci cache->bo_size -= bo->size; 114bf215546Sopenharmony_ci} 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_cistatic void vc4_bo_purgeable(struct vc4_bo *bo) 117bf215546Sopenharmony_ci{ 118bf215546Sopenharmony_ci struct drm_vc4_gem_madvise arg = { 119bf215546Sopenharmony_ci .handle = bo->handle, 120bf215546Sopenharmony_ci .madv = VC4_MADV_DONTNEED, 121bf215546Sopenharmony_ci }; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci if (bo->screen->has_madvise) 124bf215546Sopenharmony_ci vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg); 125bf215546Sopenharmony_ci} 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic bool vc4_bo_unpurgeable(struct vc4_bo *bo) 128bf215546Sopenharmony_ci{ 129bf215546Sopenharmony_ci struct drm_vc4_gem_madvise arg = { 130bf215546Sopenharmony_ci .handle = bo->handle, 131bf215546Sopenharmony_ci .madv = VC4_MADV_WILLNEED, 132bf215546Sopenharmony_ci }; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci if (!bo->screen->has_madvise) 135bf215546Sopenharmony_ci return true; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci if (vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg)) 138bf215546Sopenharmony_ci return false; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci return arg.retained; 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_cistatic void 144bf215546Sopenharmony_civc4_bo_free(struct vc4_bo *bo) 145bf215546Sopenharmony_ci{ 146bf215546Sopenharmony_ci struct vc4_screen *screen = bo->screen; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci if (bo->map) { 149bf215546Sopenharmony_ci if (using_vc4_simulator && bo->name && 150bf215546Sopenharmony_ci strcmp(bo->name, "winsys") == 0) { 151bf215546Sopenharmony_ci free(bo->map); 152bf215546Sopenharmony_ci } else { 153bf215546Sopenharmony_ci munmap(bo->map, bo->size); 154bf215546Sopenharmony_ci VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); 155bf215546Sopenharmony_ci } 156bf215546Sopenharmony_ci } 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci struct drm_gem_close c; 159bf215546Sopenharmony_ci memset(&c, 0, sizeof(c)); 160bf215546Sopenharmony_ci c.handle = bo->handle; 161bf215546Sopenharmony_ci int ret = vc4_ioctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c); 162bf215546Sopenharmony_ci if (ret != 0) 163bf215546Sopenharmony_ci fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno)); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci screen->bo_count--; 166bf215546Sopenharmony_ci screen->bo_size -= bo->size; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci if (dump_stats) { 169bf215546Sopenharmony_ci fprintf(stderr, "Freed %s%s%dkb:\n", 170bf215546Sopenharmony_ci bo->name ? bo->name : "", 171bf215546Sopenharmony_ci bo->name ? " " : "", 172bf215546Sopenharmony_ci bo->size / 1024); 173bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 174bf215546Sopenharmony_ci } 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci free(bo); 177bf215546Sopenharmony_ci} 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_cistatic struct vc4_bo * 180bf215546Sopenharmony_civc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name) 181bf215546Sopenharmony_ci{ 182bf215546Sopenharmony_ci struct vc4_bo_cache *cache = &screen->bo_cache; 183bf215546Sopenharmony_ci uint32_t page_index = size / 4096 - 1; 184bf215546Sopenharmony_ci struct vc4_bo *iter, *tmp, *bo = NULL; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci if (cache->size_list_size <= page_index) 187bf215546Sopenharmony_ci return NULL; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci mtx_lock(&cache->lock); 190bf215546Sopenharmony_ci LIST_FOR_EACH_ENTRY_SAFE(iter, tmp, &cache->size_list[page_index], 191bf215546Sopenharmony_ci size_list) { 192bf215546Sopenharmony_ci /* Check that the BO has gone idle. If not, then none of the 193bf215546Sopenharmony_ci * other BOs (pushed to the list after later rendering) are 194bf215546Sopenharmony_ci * likely to be idle, either. 195bf215546Sopenharmony_ci */ 196bf215546Sopenharmony_ci if (!vc4_bo_wait(iter, 0, NULL)) 197bf215546Sopenharmony_ci break; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci if (!vc4_bo_unpurgeable(iter)) { 200bf215546Sopenharmony_ci /* The BO has been purged. Free it and try to find 201bf215546Sopenharmony_ci * another one in the cache. 202bf215546Sopenharmony_ci */ 203bf215546Sopenharmony_ci vc4_bo_remove_from_cache(cache, iter); 204bf215546Sopenharmony_ci vc4_bo_free(iter); 205bf215546Sopenharmony_ci continue; 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci bo = iter; 209bf215546Sopenharmony_ci pipe_reference_init(&bo->reference, 1); 210bf215546Sopenharmony_ci vc4_bo_remove_from_cache(cache, bo); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci vc4_bo_label(screen, bo, "%s", name); 213bf215546Sopenharmony_ci bo->name = name; 214bf215546Sopenharmony_ci break; 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci mtx_unlock(&cache->lock); 217bf215546Sopenharmony_ci return bo; 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_cistruct vc4_bo * 221bf215546Sopenharmony_civc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci bool cleared_and_retried = false; 224bf215546Sopenharmony_ci struct drm_vc4_create_bo create; 225bf215546Sopenharmony_ci struct vc4_bo *bo; 226bf215546Sopenharmony_ci int ret; 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci size = align(size, 4096); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci bo = vc4_bo_from_cache(screen, size, name); 231bf215546Sopenharmony_ci if (bo) { 232bf215546Sopenharmony_ci if (dump_stats) { 233bf215546Sopenharmony_ci fprintf(stderr, "Allocated %s %dkb from cache:\n", 234bf215546Sopenharmony_ci name, size / 1024); 235bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci return bo; 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci bo = CALLOC_STRUCT(vc4_bo); 241bf215546Sopenharmony_ci if (!bo) 242bf215546Sopenharmony_ci return NULL; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci pipe_reference_init(&bo->reference, 1); 245bf215546Sopenharmony_ci bo->screen = screen; 246bf215546Sopenharmony_ci bo->size = size; 247bf215546Sopenharmony_ci bo->name = name; 248bf215546Sopenharmony_ci bo->private = true; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci retry: 251bf215546Sopenharmony_ci memset(&create, 0, sizeof(create)); 252bf215546Sopenharmony_ci create.size = size; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_CREATE_BO, &create); 255bf215546Sopenharmony_ci bo->handle = create.handle; 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci if (ret != 0) { 258bf215546Sopenharmony_ci if (!list_is_empty(&screen->bo_cache.time_list) && 259bf215546Sopenharmony_ci !cleared_and_retried) { 260bf215546Sopenharmony_ci cleared_and_retried = true; 261bf215546Sopenharmony_ci vc4_bo_cache_free_all(&screen->bo_cache); 262bf215546Sopenharmony_ci goto retry; 263bf215546Sopenharmony_ci } 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci free(bo); 266bf215546Sopenharmony_ci return NULL; 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci screen->bo_count++; 270bf215546Sopenharmony_ci screen->bo_size += bo->size; 271bf215546Sopenharmony_ci if (dump_stats) { 272bf215546Sopenharmony_ci fprintf(stderr, "Allocated %s %dkb:\n", name, size / 1024); 273bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci vc4_bo_label(screen, bo, "%s", name); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci return bo; 279bf215546Sopenharmony_ci} 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_civoid 282bf215546Sopenharmony_civc4_bo_last_unreference(struct vc4_bo *bo) 283bf215546Sopenharmony_ci{ 284bf215546Sopenharmony_ci struct vc4_screen *screen = bo->screen; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci struct timespec time; 287bf215546Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &time); 288bf215546Sopenharmony_ci mtx_lock(&screen->bo_cache.lock); 289bf215546Sopenharmony_ci vc4_bo_last_unreference_locked_timed(bo, time.tv_sec); 290bf215546Sopenharmony_ci mtx_unlock(&screen->bo_cache.lock); 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_cistatic void 294bf215546Sopenharmony_cifree_stale_bos(struct vc4_screen *screen, time_t time) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci struct vc4_bo_cache *cache = &screen->bo_cache; 297bf215546Sopenharmony_ci bool freed_any = false; 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list, 300bf215546Sopenharmony_ci time_list) { 301bf215546Sopenharmony_ci if (dump_stats && !freed_any) { 302bf215546Sopenharmony_ci fprintf(stderr, "Freeing stale BOs:\n"); 303bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 304bf215546Sopenharmony_ci freed_any = true; 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci /* If it's more than a second old, free it. */ 308bf215546Sopenharmony_ci if (time - bo->free_time > 2) { 309bf215546Sopenharmony_ci vc4_bo_remove_from_cache(cache, bo); 310bf215546Sopenharmony_ci vc4_bo_free(bo); 311bf215546Sopenharmony_ci } else { 312bf215546Sopenharmony_ci break; 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci } 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci if (dump_stats && freed_any) { 317bf215546Sopenharmony_ci fprintf(stderr, "Freed stale BOs:\n"); 318bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci} 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_cistatic void 323bf215546Sopenharmony_civc4_bo_cache_free_all(struct vc4_bo_cache *cache) 324bf215546Sopenharmony_ci{ 325bf215546Sopenharmony_ci mtx_lock(&cache->lock); 326bf215546Sopenharmony_ci list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list, 327bf215546Sopenharmony_ci time_list) { 328bf215546Sopenharmony_ci vc4_bo_remove_from_cache(cache, bo); 329bf215546Sopenharmony_ci vc4_bo_free(bo); 330bf215546Sopenharmony_ci } 331bf215546Sopenharmony_ci mtx_unlock(&cache->lock); 332bf215546Sopenharmony_ci} 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_civoid 335bf215546Sopenharmony_civc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time) 336bf215546Sopenharmony_ci{ 337bf215546Sopenharmony_ci struct vc4_screen *screen = bo->screen; 338bf215546Sopenharmony_ci struct vc4_bo_cache *cache = &screen->bo_cache; 339bf215546Sopenharmony_ci uint32_t page_index = bo->size / 4096 - 1; 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci if (!bo->private) { 342bf215546Sopenharmony_ci vc4_bo_free(bo); 343bf215546Sopenharmony_ci return; 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci if (cache->size_list_size <= page_index) { 347bf215546Sopenharmony_ci struct list_head *new_list = 348bf215546Sopenharmony_ci ralloc_array(screen, struct list_head, page_index + 1); 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci /* Move old list contents over (since the array has moved, and 351bf215546Sopenharmony_ci * therefore the pointers to the list heads have to change). 352bf215546Sopenharmony_ci */ 353bf215546Sopenharmony_ci for (int i = 0; i < cache->size_list_size; i++) 354bf215546Sopenharmony_ci list_replace(&cache->size_list[i], &new_list[i]); 355bf215546Sopenharmony_ci for (int i = cache->size_list_size; i < page_index + 1; i++) 356bf215546Sopenharmony_ci list_inithead(&new_list[i]); 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci cache->size_list = new_list; 359bf215546Sopenharmony_ci cache->size_list_size = page_index + 1; 360bf215546Sopenharmony_ci } 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci vc4_bo_purgeable(bo); 363bf215546Sopenharmony_ci bo->free_time = time; 364bf215546Sopenharmony_ci list_addtail(&bo->size_list, &cache->size_list[page_index]); 365bf215546Sopenharmony_ci list_addtail(&bo->time_list, &cache->time_list); 366bf215546Sopenharmony_ci cache->bo_count++; 367bf215546Sopenharmony_ci cache->bo_size += bo->size; 368bf215546Sopenharmony_ci if (dump_stats) { 369bf215546Sopenharmony_ci fprintf(stderr, "Freed %s %dkb to cache:\n", 370bf215546Sopenharmony_ci bo->name, bo->size / 1024); 371bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci bo->name = NULL; 374bf215546Sopenharmony_ci vc4_bo_label(screen, bo, "mesa cache"); 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci free_stale_bos(screen, time); 377bf215546Sopenharmony_ci} 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_cistatic struct vc4_bo * 380bf215546Sopenharmony_civc4_bo_open_handle(struct vc4_screen *screen, 381bf215546Sopenharmony_ci uint32_t handle, uint32_t size) 382bf215546Sopenharmony_ci{ 383bf215546Sopenharmony_ci struct vc4_bo *bo; 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci assert(size); 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci mtx_lock(&screen->bo_handles_mutex); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci bo = util_hash_table_get(screen->bo_handles, (void*)(uintptr_t)handle); 390bf215546Sopenharmony_ci if (bo) { 391bf215546Sopenharmony_ci vc4_bo_reference(bo); 392bf215546Sopenharmony_ci goto done; 393bf215546Sopenharmony_ci } 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci bo = CALLOC_STRUCT(vc4_bo); 396bf215546Sopenharmony_ci pipe_reference_init(&bo->reference, 1); 397bf215546Sopenharmony_ci bo->screen = screen; 398bf215546Sopenharmony_ci bo->handle = handle; 399bf215546Sopenharmony_ci bo->size = size; 400bf215546Sopenharmony_ci bo->name = "winsys"; 401bf215546Sopenharmony_ci bo->private = false; 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci#ifdef USE_VC4_SIMULATOR 404bf215546Sopenharmony_ci vc4_simulator_open_from_handle(screen->fd, bo->handle, bo->size); 405bf215546Sopenharmony_ci bo->map = malloc(bo->size); 406bf215546Sopenharmony_ci#endif 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci _mesa_hash_table_insert(screen->bo_handles, (void *)(uintptr_t)handle, bo); 409bf215546Sopenharmony_ci 410bf215546Sopenharmony_cidone: 411bf215546Sopenharmony_ci mtx_unlock(&screen->bo_handles_mutex); 412bf215546Sopenharmony_ci return bo; 413bf215546Sopenharmony_ci} 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_cistruct vc4_bo * 416bf215546Sopenharmony_civc4_bo_open_name(struct vc4_screen *screen, uint32_t name) 417bf215546Sopenharmony_ci{ 418bf215546Sopenharmony_ci struct drm_gem_open o = { 419bf215546Sopenharmony_ci .name = name 420bf215546Sopenharmony_ci }; 421bf215546Sopenharmony_ci int ret = vc4_ioctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o); 422bf215546Sopenharmony_ci if (ret) { 423bf215546Sopenharmony_ci fprintf(stderr, "Failed to open bo %d: %s\n", 424bf215546Sopenharmony_ci name, strerror(errno)); 425bf215546Sopenharmony_ci return NULL; 426bf215546Sopenharmony_ci } 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci return vc4_bo_open_handle(screen, o.handle, o.size); 429bf215546Sopenharmony_ci} 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_cistruct vc4_bo * 432bf215546Sopenharmony_civc4_bo_open_dmabuf(struct vc4_screen *screen, int fd) 433bf215546Sopenharmony_ci{ 434bf215546Sopenharmony_ci uint32_t handle; 435bf215546Sopenharmony_ci int ret = drmPrimeFDToHandle(screen->fd, fd, &handle); 436bf215546Sopenharmony_ci int size; 437bf215546Sopenharmony_ci if (ret) { 438bf215546Sopenharmony_ci fprintf(stderr, "Failed to get vc4 handle for dmabuf %d\n", fd); 439bf215546Sopenharmony_ci return NULL; 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci /* Determine the size of the bo we were handed. */ 443bf215546Sopenharmony_ci size = lseek(fd, 0, SEEK_END); 444bf215546Sopenharmony_ci if (size == -1) { 445bf215546Sopenharmony_ci fprintf(stderr, "Couldn't get size of dmabuf fd %d.\n", fd); 446bf215546Sopenharmony_ci return NULL; 447bf215546Sopenharmony_ci } 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci return vc4_bo_open_handle(screen, handle, size); 450bf215546Sopenharmony_ci} 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ciint 453bf215546Sopenharmony_civc4_bo_get_dmabuf(struct vc4_bo *bo) 454bf215546Sopenharmony_ci{ 455bf215546Sopenharmony_ci int fd; 456bf215546Sopenharmony_ci int ret = drmPrimeHandleToFD(bo->screen->fd, bo->handle, 457bf215546Sopenharmony_ci O_CLOEXEC, &fd); 458bf215546Sopenharmony_ci if (ret != 0) { 459bf215546Sopenharmony_ci fprintf(stderr, "Failed to export gem bo %d to dmabuf\n", 460bf215546Sopenharmony_ci bo->handle); 461bf215546Sopenharmony_ci return -1; 462bf215546Sopenharmony_ci } 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci mtx_lock(&bo->screen->bo_handles_mutex); 465bf215546Sopenharmony_ci bo->private = false; 466bf215546Sopenharmony_ci _mesa_hash_table_insert(bo->screen->bo_handles, (void *)(uintptr_t)bo->handle, bo); 467bf215546Sopenharmony_ci mtx_unlock(&bo->screen->bo_handles_mutex); 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci return fd; 470bf215546Sopenharmony_ci} 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_cistruct vc4_bo * 473bf215546Sopenharmony_civc4_bo_alloc_shader(struct vc4_screen *screen, const void *data, uint32_t size) 474bf215546Sopenharmony_ci{ 475bf215546Sopenharmony_ci struct vc4_bo *bo; 476bf215546Sopenharmony_ci int ret; 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci bo = CALLOC_STRUCT(vc4_bo); 479bf215546Sopenharmony_ci if (!bo) 480bf215546Sopenharmony_ci return NULL; 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci pipe_reference_init(&bo->reference, 1); 483bf215546Sopenharmony_ci bo->screen = screen; 484bf215546Sopenharmony_ci bo->size = align(size, 4096); 485bf215546Sopenharmony_ci bo->name = "code"; 486bf215546Sopenharmony_ci bo->private = false; /* Make sure it doesn't go back to the cache. */ 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci struct drm_vc4_create_shader_bo create = { 489bf215546Sopenharmony_ci .size = size, 490bf215546Sopenharmony_ci .data = (uintptr_t)data, 491bf215546Sopenharmony_ci }; 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_CREATE_SHADER_BO, 494bf215546Sopenharmony_ci &create); 495bf215546Sopenharmony_ci bo->handle = create.handle; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci if (ret != 0) { 498bf215546Sopenharmony_ci fprintf(stderr, "create shader ioctl failure\n"); 499bf215546Sopenharmony_ci abort(); 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_ci screen->bo_count++; 503bf215546Sopenharmony_ci screen->bo_size += bo->size; 504bf215546Sopenharmony_ci if (dump_stats) { 505bf215546Sopenharmony_ci fprintf(stderr, "Allocated shader %dkb:\n", bo->size / 1024); 506bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 507bf215546Sopenharmony_ci } 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_ci return bo; 510bf215546Sopenharmony_ci} 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_cibool 513bf215546Sopenharmony_civc4_bo_flink(struct vc4_bo *bo, uint32_t *name) 514bf215546Sopenharmony_ci{ 515bf215546Sopenharmony_ci struct drm_gem_flink flink = { 516bf215546Sopenharmony_ci .handle = bo->handle, 517bf215546Sopenharmony_ci }; 518bf215546Sopenharmony_ci int ret = vc4_ioctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink); 519bf215546Sopenharmony_ci if (ret) { 520bf215546Sopenharmony_ci fprintf(stderr, "Failed to flink bo %d: %s\n", 521bf215546Sopenharmony_ci bo->handle, strerror(errno)); 522bf215546Sopenharmony_ci free(bo); 523bf215546Sopenharmony_ci return false; 524bf215546Sopenharmony_ci } 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci bo->private = false; 527bf215546Sopenharmony_ci *name = flink.name; 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci return true; 530bf215546Sopenharmony_ci} 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_cistatic int vc4_wait_seqno_ioctl(int fd, uint64_t seqno, uint64_t timeout_ns) 533bf215546Sopenharmony_ci{ 534bf215546Sopenharmony_ci struct drm_vc4_wait_seqno wait = { 535bf215546Sopenharmony_ci .seqno = seqno, 536bf215546Sopenharmony_ci .timeout_ns = timeout_ns, 537bf215546Sopenharmony_ci }; 538bf215546Sopenharmony_ci int ret = vc4_ioctl(fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait); 539bf215546Sopenharmony_ci if (ret == -1) 540bf215546Sopenharmony_ci return -errno; 541bf215546Sopenharmony_ci else 542bf215546Sopenharmony_ci return 0; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci} 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_cibool 547bf215546Sopenharmony_civc4_wait_seqno(struct vc4_screen *screen, uint64_t seqno, uint64_t timeout_ns, 548bf215546Sopenharmony_ci const char *reason) 549bf215546Sopenharmony_ci{ 550bf215546Sopenharmony_ci if (screen->finished_seqno >= seqno) 551bf215546Sopenharmony_ci return true; 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci if (unlikely(vc4_debug & VC4_DEBUG_PERF) && timeout_ns && reason) { 554bf215546Sopenharmony_ci if (vc4_wait_seqno_ioctl(screen->fd, seqno, 0) == -ETIME) { 555bf215546Sopenharmony_ci fprintf(stderr, "Blocking on seqno %lld for %s\n", 556bf215546Sopenharmony_ci (long long)seqno, reason); 557bf215546Sopenharmony_ci } 558bf215546Sopenharmony_ci } 559bf215546Sopenharmony_ci 560bf215546Sopenharmony_ci int ret = vc4_wait_seqno_ioctl(screen->fd, seqno, timeout_ns); 561bf215546Sopenharmony_ci if (ret) { 562bf215546Sopenharmony_ci if (ret != -ETIME) { 563bf215546Sopenharmony_ci fprintf(stderr, "wait failed: %d\n", ret); 564bf215546Sopenharmony_ci abort(); 565bf215546Sopenharmony_ci } 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci return false; 568bf215546Sopenharmony_ci } 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci screen->finished_seqno = seqno; 571bf215546Sopenharmony_ci return true; 572bf215546Sopenharmony_ci} 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_cistatic int vc4_wait_bo_ioctl(int fd, uint32_t handle, uint64_t timeout_ns) 575bf215546Sopenharmony_ci{ 576bf215546Sopenharmony_ci struct drm_vc4_wait_bo wait = { 577bf215546Sopenharmony_ci .handle = handle, 578bf215546Sopenharmony_ci .timeout_ns = timeout_ns, 579bf215546Sopenharmony_ci }; 580bf215546Sopenharmony_ci int ret = vc4_ioctl(fd, DRM_IOCTL_VC4_WAIT_BO, &wait); 581bf215546Sopenharmony_ci if (ret == -1) 582bf215546Sopenharmony_ci return -errno; 583bf215546Sopenharmony_ci else 584bf215546Sopenharmony_ci return 0; 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci} 587bf215546Sopenharmony_ci 588bf215546Sopenharmony_cibool 589bf215546Sopenharmony_civc4_bo_wait(struct vc4_bo *bo, uint64_t timeout_ns, const char *reason) 590bf215546Sopenharmony_ci{ 591bf215546Sopenharmony_ci struct vc4_screen *screen = bo->screen; 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci if (unlikely(vc4_debug & VC4_DEBUG_PERF) && timeout_ns && reason) { 594bf215546Sopenharmony_ci if (vc4_wait_bo_ioctl(screen->fd, bo->handle, 0) == -ETIME) { 595bf215546Sopenharmony_ci fprintf(stderr, "Blocking on %s BO for %s\n", 596bf215546Sopenharmony_ci bo->name, reason); 597bf215546Sopenharmony_ci } 598bf215546Sopenharmony_ci } 599bf215546Sopenharmony_ci 600bf215546Sopenharmony_ci int ret = vc4_wait_bo_ioctl(screen->fd, bo->handle, timeout_ns); 601bf215546Sopenharmony_ci if (ret) { 602bf215546Sopenharmony_ci if (ret != -ETIME) { 603bf215546Sopenharmony_ci fprintf(stderr, "wait failed: %d\n", ret); 604bf215546Sopenharmony_ci abort(); 605bf215546Sopenharmony_ci } 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci return false; 608bf215546Sopenharmony_ci } 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci return true; 611bf215546Sopenharmony_ci} 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_civoid * 614bf215546Sopenharmony_civc4_bo_map_unsynchronized(struct vc4_bo *bo) 615bf215546Sopenharmony_ci{ 616bf215546Sopenharmony_ci uint64_t offset; 617bf215546Sopenharmony_ci int ret; 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci if (bo->map) 620bf215546Sopenharmony_ci return bo->map; 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_ci struct drm_vc4_mmap_bo map; 623bf215546Sopenharmony_ci memset(&map, 0, sizeof(map)); 624bf215546Sopenharmony_ci map.handle = bo->handle; 625bf215546Sopenharmony_ci ret = vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_MMAP_BO, &map); 626bf215546Sopenharmony_ci offset = map.offset; 627bf215546Sopenharmony_ci if (ret != 0) { 628bf215546Sopenharmony_ci fprintf(stderr, "map ioctl failure\n"); 629bf215546Sopenharmony_ci abort(); 630bf215546Sopenharmony_ci } 631bf215546Sopenharmony_ci 632bf215546Sopenharmony_ci bo->map = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 633bf215546Sopenharmony_ci bo->screen->fd, offset); 634bf215546Sopenharmony_ci if (bo->map == MAP_FAILED) { 635bf215546Sopenharmony_ci fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n", 636bf215546Sopenharmony_ci bo->handle, (long long)offset, bo->size); 637bf215546Sopenharmony_ci abort(); 638bf215546Sopenharmony_ci } 639bf215546Sopenharmony_ci VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, false)); 640bf215546Sopenharmony_ci 641bf215546Sopenharmony_ci return bo->map; 642bf215546Sopenharmony_ci} 643bf215546Sopenharmony_ci 644bf215546Sopenharmony_civoid * 645bf215546Sopenharmony_civc4_bo_map(struct vc4_bo *bo) 646bf215546Sopenharmony_ci{ 647bf215546Sopenharmony_ci void *map = vc4_bo_map_unsynchronized(bo); 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci bool ok = vc4_bo_wait(bo, PIPE_TIMEOUT_INFINITE, "bo map"); 650bf215546Sopenharmony_ci if (!ok) { 651bf215546Sopenharmony_ci fprintf(stderr, "BO wait for map failed\n"); 652bf215546Sopenharmony_ci abort(); 653bf215546Sopenharmony_ci } 654bf215546Sopenharmony_ci 655bf215546Sopenharmony_ci return map; 656bf215546Sopenharmony_ci} 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_civoid 659bf215546Sopenharmony_civc4_bufmgr_destroy(struct pipe_screen *pscreen) 660bf215546Sopenharmony_ci{ 661bf215546Sopenharmony_ci struct vc4_screen *screen = vc4_screen(pscreen); 662bf215546Sopenharmony_ci struct vc4_bo_cache *cache = &screen->bo_cache; 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_ci vc4_bo_cache_free_all(cache); 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci if (dump_stats) { 667bf215546Sopenharmony_ci fprintf(stderr, "BO stats after screen destroy:\n"); 668bf215546Sopenharmony_ci vc4_bo_dump_stats(screen); 669bf215546Sopenharmony_ci } 670bf215546Sopenharmony_ci} 671