X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgallium%2Fdrivers%2Fvc4%2Fvc4_bufmgr.c;h=716ca50ea0696ef2f34070bc16336ff569214f54;hb=33886474d646134f9784771a0ded3510a0180515;hp=f7b41f5816d7032f8bfa4d3e1b4ad236228a2374;hpb=ff7896a398f55baefd00e695c8f45f2ffa57bceb;p=mesa.git diff --git a/src/gallium/drivers/vc4/vc4_bufmgr.c b/src/gallium/drivers/vc4/vc4_bufmgr.c index f7b41f5816d..716ca50ea06 100644 --- a/src/gallium/drivers/vc4/vc4_bufmgr.c +++ b/src/gallium/drivers/vc4/vc4_bufmgr.c @@ -28,23 +28,69 @@ #include #include +#include "util/u_hash_table.h" #include "util/u_memory.h" +#include "util/u_string.h" #include "util/ralloc.h" #include "vc4_context.h" #include "vc4_screen.h" +#ifdef HAVE_VALGRIND +#include +#include +#define VG(x) x +#else +#define VG(x) +#endif + static bool dump_stats = false; +static void +vc4_bo_cache_free_all(struct vc4_bo_cache *cache); + +void +vc4_bo_debug_describe(char* buf, const struct vc4_bo *ptr) +{ + util_sprintf(buf, "vc4_bo<%s,%u,%u>", ptr->name ? ptr->name : "?", + ptr->handle, ptr->size); +} + +void +vc4_bo_label(struct vc4_screen *screen, struct vc4_bo *bo, const char *fmt, ...) +{ + /* Perform BO labeling by default on debug builds (so that you get + * whole-system allocation information), or if VC4_DEBUG=surf is set + * (for debugging a single app's allocation). + */ +#ifndef DEBUG + if (!(vc4_debug & VC4_DEBUG_SURFACE)) + return; +#endif + va_list va; + va_start(va, fmt); + char *name = ralloc_vasprintf(NULL, fmt, va); + va_end(va); + + struct drm_vc4_label_bo label = { + .handle = bo->handle, + .len = strlen(name), + .name = (uintptr_t)name, + }; + vc4_ioctl(screen->fd, DRM_IOCTL_VC4_LABEL_BO, &label); + + ralloc_free(name); +} + static void vc4_bo_dump_stats(struct vc4_screen *screen) { struct vc4_bo_cache *cache = &screen->bo_cache; fprintf(stderr, " BOs allocated: %d\n", screen->bo_count); - fprintf(stderr, " BOs size: %dkb\n", screen->bo_size / 102); + fprintf(stderr, " BOs size: %dkb\n", screen->bo_size / 1024); fprintf(stderr, " BOs cached: %d\n", cache->bo_count); - fprintf(stderr, " BOs cached size: %dkb\n", cache->bo_size / 102); + fprintf(stderr, " BOs cached size: %dkb\n", cache->bo_size / 1024); if (!list_empty(&cache->time_list)) { struct vc4_bo *first = LIST_ENTRY(struct vc4_bo, @@ -75,42 +121,115 @@ vc4_bo_remove_from_cache(struct vc4_bo_cache *cache, struct vc4_bo *bo) cache->bo_size -= bo->size; } +static void vc4_bo_purgeable(struct vc4_bo *bo) +{ + struct drm_vc4_gem_madvise arg = { + .handle = bo->handle, + .madv = VC4_MADV_DONTNEED, + }; + + if (bo->screen->has_madvise) + vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg); +} + +static bool vc4_bo_unpurgeable(struct vc4_bo *bo) +{ + struct drm_vc4_gem_madvise arg = { + .handle = bo->handle, + .madv = VC4_MADV_WILLNEED, + }; + + if (!bo->screen->has_madvise) + return true; + + if (vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg)) + return false; + + return arg.retained; +} + +static void +vc4_bo_free(struct vc4_bo *bo) +{ + struct vc4_screen *screen = bo->screen; + + if (bo->map) { + if (using_vc4_simulator && bo->name && + strcmp(bo->name, "winsys") == 0) { + free(bo->map); + } else { + munmap(bo->map, bo->size); + VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); + } + } + + struct drm_gem_close c; + memset(&c, 0, sizeof(c)); + c.handle = bo->handle; + int ret = vc4_ioctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c); + if (ret != 0) + fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno)); + + screen->bo_count--; + screen->bo_size -= bo->size; + + if (dump_stats) { + fprintf(stderr, "Freed %s%s%dkb:\n", + bo->name ? bo->name : "", + bo->name ? " " : "", + bo->size / 1024); + vc4_bo_dump_stats(screen); + } + + free(bo); +} + static struct vc4_bo * vc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name) { struct vc4_bo_cache *cache = &screen->bo_cache; uint32_t page_index = size / 4096 - 1; + struct vc4_bo *iter, *tmp, *bo = NULL; if (cache->size_list_size <= page_index) return NULL; - struct vc4_bo *bo = NULL; - pipe_mutex_lock(cache->lock); - if (!list_empty(&cache->size_list[page_index])) { - bo = LIST_ENTRY(struct vc4_bo, cache->size_list[page_index].next, - size_list); - - /* Check that the BO has gone idle. If not, then we want to - * allocate something new instead, since we assume that the - * user will proceed to CPU map it and fill it with stuff. + mtx_lock(&cache->lock); + LIST_FOR_EACH_ENTRY_SAFE(iter, tmp, &cache->size_list[page_index], + size_list) { + /* Check that the BO has gone idle. If not, then none of the + * other BOs (pushed to the list after later rendering) are + * likely to be idle, either. */ - if (!vc4_bo_wait(bo, 0, NULL)) { - pipe_mutex_unlock(cache->lock); - return NULL; - } + if (!vc4_bo_wait(iter, 0, NULL)) + break; + if (!vc4_bo_unpurgeable(iter)) { + /* The BO has been purged. Free it and try to find + * another one in the cache. + */ + vc4_bo_remove_from_cache(cache, iter); + vc4_bo_free(iter); + continue; + } + + bo = iter; pipe_reference_init(&bo->reference, 1); vc4_bo_remove_from_cache(cache, bo); + vc4_bo_label(screen, bo, "%s", name); bo->name = name; + break; } - pipe_mutex_unlock(cache->lock); + mtx_unlock(&cache->lock); return bo; } struct vc4_bo * vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name) { + bool cleared_and_retried = false; + struct drm_vc4_create_bo create; struct vc4_bo *bo; int ret; @@ -136,29 +255,23 @@ vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name) bo->name = name; bo->private = true; - if (!using_vc4_simulator) { - struct drm_vc4_create_bo create; - memset(&create, 0, sizeof(create)); - - create.size = size; + retry: + memset(&create, 0, sizeof(create)); + create.size = size; - ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_CREATE_BO, &create); - bo->handle = create.handle; - } else { - struct drm_mode_create_dumb create; - memset(&create, 0, sizeof(create)); + ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_CREATE_BO, &create); + bo->handle = create.handle; - create.width = 128; - create.bpp = 8; - create.height = (size + 127) / 128; - - ret = drmIoctl(screen->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); - bo->handle = create.handle; - assert(create.size >= size); - } if (ret != 0) { - fprintf(stderr, "create ioctl failure\n"); - abort(); + if (!list_empty(&screen->bo_cache.time_list) && + !cleared_and_retried) { + cleared_and_retried = true; + vc4_bo_cache_free_all(&screen->bo_cache); + goto retry; + } + + free(bo); + return NULL; } screen->bo_count++; @@ -168,6 +281,8 @@ vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name) vc4_bo_dump_stats(screen); } + vc4_bo_label(screen, bo, "%s", name); + return bo; } @@ -178,45 +293,9 @@ vc4_bo_last_unreference(struct vc4_bo *bo) struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time); - pipe_mutex_lock(screen->bo_cache.lock); + mtx_lock(&screen->bo_cache.lock); vc4_bo_last_unreference_locked_timed(bo, time.tv_sec); - pipe_mutex_unlock(screen->bo_cache.lock); -} - -static void -vc4_bo_free(struct vc4_bo *bo) -{ - struct vc4_screen *screen = bo->screen; - - if (bo->map) { -#ifdef USE_VC4_SIMULATOR - if (bo->simulator_winsys_map) { - free(bo->map); - bo->map = bo->simulator_winsys_map; - } -#endif - munmap(bo->map, bo->size); - } - - struct drm_gem_close c; - memset(&c, 0, sizeof(c)); - c.handle = bo->handle; - int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c); - if (ret != 0) - fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno)); - - screen->bo_count--; - screen->bo_size -= bo->size; - - if (dump_stats) { - fprintf(stderr, "Freed %s%s%dkb:\n", - bo->name ? bo->name : "", - bo->name ? " " : "", - bo->size / 1024); - vc4_bo_dump_stats(screen); - } - - free(bo); + mtx_unlock(&screen->bo_cache.lock); } static void @@ -248,6 +327,18 @@ free_stale_bos(struct vc4_screen *screen, time_t time) } } +static void +vc4_bo_cache_free_all(struct vc4_bo_cache *cache) +{ + mtx_lock(&cache->lock); + list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list, + time_list) { + vc4_bo_remove_from_cache(cache, bo); + vc4_bo_free(bo); + } + mtx_unlock(&cache->lock); +} + void vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time) { @@ -267,17 +358,8 @@ vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time) /* Move old list contents over (since the array has moved, and * therefore the pointers to the list heads have to change). */ - for (int i = 0; i < cache->size_list_size; i++) { - struct list_head *old_head = &cache->size_list[i]; - if (list_empty(old_head)) - list_inithead(&new_list[i]); - else { - new_list[i].next = old_head->next; - new_list[i].prev = old_head->prev; - new_list[i].next->prev = &new_list[i]; - new_list[i].prev->next = &new_list[i]; - } - } + for (int i = 0; i < cache->size_list_size; i++) + list_replace(&cache->size_list[i], &new_list[i]); for (int i = cache->size_list_size; i < page_index + 1; i++) list_inithead(&new_list[i]); @@ -285,6 +367,7 @@ vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time) cache->size_list_size = page_index + 1; } + vc4_bo_purgeable(bo); bo->free_time = time; list_addtail(&bo->size_list, &cache->size_list[page_index]); list_addtail(&bo->time_list, &cache->time_list); @@ -296,19 +379,28 @@ vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time) vc4_bo_dump_stats(screen); } bo->name = NULL; + vc4_bo_label(screen, bo, "mesa cache"); free_stale_bos(screen, time); } static struct vc4_bo * vc4_bo_open_handle(struct vc4_screen *screen, - uint32_t winsys_stride, uint32_t handle, uint32_t size) { - struct vc4_bo *bo = CALLOC_STRUCT(vc4_bo); + struct vc4_bo *bo; assert(size); + mtx_lock(&screen->bo_handles_mutex); + + bo = util_hash_table_get(screen->bo_handles, (void*)(uintptr_t)handle); + if (bo) { + vc4_bo_reference(bo); + goto done; + } + + bo = CALLOC_STRUCT(vc4_bo); pipe_reference_init(&bo->reference, 1); bo->screen = screen; bo->handle = handle; @@ -317,34 +409,35 @@ vc4_bo_open_handle(struct vc4_screen *screen, bo->private = false; #ifdef USE_VC4_SIMULATOR - vc4_bo_map(bo); - bo->simulator_winsys_map = bo->map; - bo->simulator_winsys_stride = winsys_stride; + vc4_simulator_open_from_handle(screen->fd, bo->handle, bo->size); bo->map = malloc(bo->size); #endif + util_hash_table_set(screen->bo_handles, (void *)(uintptr_t)handle, bo); + +done: + mtx_unlock(&screen->bo_handles_mutex); return bo; } struct vc4_bo * -vc4_bo_open_name(struct vc4_screen *screen, uint32_t name, - uint32_t winsys_stride) +vc4_bo_open_name(struct vc4_screen *screen, uint32_t name) { struct drm_gem_open o = { .name = name }; - int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o); + int ret = vc4_ioctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o); if (ret) { fprintf(stderr, "Failed to open bo %d: %s\n", name, strerror(errno)); return NULL; } - return vc4_bo_open_handle(screen, winsys_stride, o.handle, o.size); + return vc4_bo_open_handle(screen, o.handle, o.size); } struct vc4_bo * -vc4_bo_open_dmabuf(struct vc4_screen *screen, int fd, uint32_t winsys_stride) +vc4_bo_open_dmabuf(struct vc4_screen *screen, int fd) { uint32_t handle; int ret = drmPrimeFDToHandle(screen->fd, fd, &handle); @@ -361,7 +454,7 @@ vc4_bo_open_dmabuf(struct vc4_screen *screen, int fd, uint32_t winsys_stride) return NULL; } - return vc4_bo_open_handle(screen, winsys_stride, handle, size); + return vc4_bo_open_handle(screen, handle, size); } int @@ -375,7 +468,11 @@ vc4_bo_get_dmabuf(struct vc4_bo *bo) bo->handle); return -1; } + + mtx_lock(&bo->screen->bo_handles_mutex); bo->private = false; + util_hash_table_set(bo->screen->bo_handles, (void *)(uintptr_t)bo->handle, bo); + mtx_unlock(&bo->screen->bo_handles_mutex); return fd; } @@ -396,30 +493,15 @@ vc4_bo_alloc_shader(struct vc4_screen *screen, const void *data, uint32_t size) bo->name = "code"; bo->private = false; /* Make sure it doesn't go back to the cache. */ - if (!using_vc4_simulator) { - struct drm_vc4_create_shader_bo create = { - .size = size, - .data = (uintptr_t)data, - }; - - ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_CREATE_SHADER_BO, - &create); - bo->handle = create.handle; - } else { - struct drm_mode_create_dumb create; - memset(&create, 0, sizeof(create)); - - create.width = 128; - create.bpp = 8; - create.height = (size + 127) / 128; - - ret = drmIoctl(screen->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); - bo->handle = create.handle; - assert(create.size >= size); - - vc4_bo_map(bo); - memcpy(bo->map, data, size); - } + struct drm_vc4_create_shader_bo create = { + .size = size, + .data = (uintptr_t)data, + }; + + ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_CREATE_SHADER_BO, + &create); + bo->handle = create.handle; + if (ret != 0) { fprintf(stderr, "create shader ioctl failure\n"); abort(); @@ -428,7 +510,7 @@ vc4_bo_alloc_shader(struct vc4_screen *screen, const void *data, uint32_t size) screen->bo_count++; screen->bo_size += bo->size; if (dump_stats) { - fprintf(stderr, "Allocated shader %dkb:\n", size / 1024); + fprintf(stderr, "Allocated shader %dkb:\n", bo->size / 1024); vc4_bo_dump_stats(screen); } @@ -441,7 +523,7 @@ vc4_bo_flink(struct vc4_bo *bo, uint32_t *name) struct drm_gem_flink flink = { .handle = bo->handle, }; - int ret = drmIoctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink); + int ret = vc4_ioctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink); if (ret) { fprintf(stderr, "Failed to flink bo %d: %s\n", bo->handle, strerror(errno)); @@ -457,14 +539,11 @@ vc4_bo_flink(struct vc4_bo *bo, uint32_t *name) static int vc4_wait_seqno_ioctl(int fd, uint64_t seqno, uint64_t timeout_ns) { - if (using_vc4_simulator) - return 0; - struct drm_vc4_wait_seqno wait = { .seqno = seqno, .timeout_ns = timeout_ns, }; - int ret = drmIoctl(fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait); + int ret = vc4_ioctl(fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait); if (ret == -1) return -errno; else @@ -502,14 +581,11 @@ vc4_wait_seqno(struct vc4_screen *screen, uint64_t seqno, uint64_t timeout_ns, static int vc4_wait_bo_ioctl(int fd, uint32_t handle, uint64_t timeout_ns) { - if (using_vc4_simulator) - return 0; - struct drm_vc4_wait_bo wait = { .handle = handle, .timeout_ns = timeout_ns, }; - int ret = drmIoctl(fd, DRM_IOCTL_VC4_WAIT_BO, &wait); + int ret = vc4_ioctl(fd, DRM_IOCTL_VC4_WAIT_BO, &wait); if (ret == -1) return -errno; else @@ -551,19 +627,11 @@ vc4_bo_map_unsynchronized(struct vc4_bo *bo) if (bo->map) return bo->map; - if (!using_vc4_simulator) { - struct drm_vc4_mmap_bo map; - memset(&map, 0, sizeof(map)); - map.handle = bo->handle; - ret = drmIoctl(bo->screen->fd, DRM_IOCTL_VC4_MMAP_BO, &map); - offset = map.offset; - } else { - struct drm_mode_map_dumb map; - memset(&map, 0, sizeof(map)); - map.handle = bo->handle; - ret = drmIoctl(bo->screen->fd, DRM_IOCTL_MODE_MAP_DUMB, &map); - offset = map.offset; - } + struct drm_vc4_mmap_bo map; + memset(&map, 0, sizeof(map)); + map.handle = bo->handle; + ret = vc4_ioctl(bo->screen->fd, DRM_IOCTL_VC4_MMAP_BO, &map); + offset = map.offset; if (ret != 0) { fprintf(stderr, "map ioctl failure\n"); abort(); @@ -576,6 +644,7 @@ vc4_bo_map_unsynchronized(struct vc4_bo *bo) bo->handle, (long long)offset, bo->size); abort(); } + VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, false)); return bo->map; } @@ -600,11 +669,7 @@ vc4_bufmgr_destroy(struct pipe_screen *pscreen) struct vc4_screen *screen = vc4_screen(pscreen); struct vc4_bo_cache *cache = &screen->bo_cache; - list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list, - time_list) { - vc4_bo_remove_from_cache(cache, bo); - vc4_bo_free(bo); - } + vc4_bo_cache_free_all(cache); if (dump_stats) { fprintf(stderr, "BO stats after screen destroy:\n");