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