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