diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 293240580b8..7054fb31a29 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -43,6 +43,7 @@ #include "util/os_misc.h" #include "util/os_time.h" #include "util/u_helpers.h" +#include "util/anon_file.h" #include "lp_texture.h" #include "lp_fence.h" #include "lp_jit.h" @@ -929,6 +930,10 @@ llvmpipe_destroy_screen(struct pipe_screen *_screen) close(screen->udmabuf_fd); #endif + util_vma_heap_finish(&screen->mem_heap); + + close(screen->fd_mem_alloc); + mtx_destroy(&screen->mem_mutex); mtx_destroy(&screen->rast_mutex); mtx_destroy(&screen->cs_mutex); FREE(screen); @@ -1170,6 +1175,16 @@ llvmpipe_create_screen(struct sw_winsys *winsys) screen->udmabuf_fd = open("/dev/udmabuf", O_RDWR); #endif + screen->fd_mem_alloc = os_create_anonymous_file(0, "allocation fd"); + (void) mtx_init(&screen->mem_mutex, mtx_plain); + + uint64_t alignment; + if (!os_get_page_size(&alignment)) + alignment = 256; + + util_vma_heap_init(&screen->mem_heap, alignment, UINT64_MAX - alignment); + screen->mem_heap.alloc_high = false; + snprintf(screen->renderer_string, sizeof(screen->renderer_string), "llvmpipe (LLVM " MESA_LLVM_VERSION_STRING ", %u bits)", lp_build_init_native_width() ); diff --git a/src/gallium/drivers/llvmpipe/lp_screen.h b/src/gallium/drivers/llvmpipe/lp_screen.h index 9caac73bf1d..766e64d80e6 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.h +++ b/src/gallium/drivers/llvmpipe/lp_screen.h @@ -38,6 +38,7 @@ #include "pipe/p_defines.h" #include "util/u_thread.h" #include "util/list.h" +#include "util/vma.h" #include "gallivm/lp_bld.h" #include "gallivm/lp_bld_misc.h" @@ -77,6 +78,11 @@ struct llvmpipe_screen #ifdef HAVE_LIBDRM int udmabuf_fd; #endif + + int fd_mem_alloc; + mtx_t mem_mutex; + uint64_t mem_file_size; + struct util_vma_heap mem_heap; }; diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c index 8da39ef1874..a5713230f16 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.c +++ b/src/gallium/drivers/llvmpipe/lp_texture.c @@ -35,6 +35,7 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" +#include "util/detect_os.h" #include "util/simple_mtx.h" #include "util/u_inlines.h" #include "util/u_cpu_detect.h" @@ -43,6 +44,10 @@ #include "util/u_memory.h" #include "util/u_transfer.h" +#if DETECT_OS_POSIX +#include "util/os_mman.h" +#endif + #include "lp_context.h" #include "lp_flush.h" #include "lp_screen.h" @@ -1101,22 +1106,60 @@ llvmpipe_memory_barrier(struct pipe_context *pipe, static struct pipe_memory_allocation * -llvmpipe_allocate_memory(struct pipe_screen *screen, uint64_t size) +llvmpipe_allocate_memory(struct pipe_screen *_screen, uint64_t size) { + struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct llvmpipe_memory_allocation *mem = CALLOC_STRUCT(llvmpipe_memory_allocation); uint64_t alignment; if (!os_get_page_size(&alignment)) alignment = 256; - mem->cpu_addr = os_malloc_aligned(size, alignment); + + mem->fd = screen->fd_mem_alloc; + mem->size = align64(size, alignment); + +#if DETECT_OS_LINUX + mem->cpu_addr = MAP_FAILED; + + mtx_lock(&screen->mem_mutex); + + mem->offset = util_vma_heap_alloc(&screen->mem_heap, mem->size, alignment); + + if (mem->offset + mem->size > screen->mem_file_size) { + /* expand the anonymous file */ + screen->mem_file_size = mem->offset + mem->size; + ftruncate(screen->fd_mem_alloc, screen->mem_file_size); + } + + mtx_unlock(&screen->mem_mutex); +#else + mem->cpu_addr = malloc(mem->size); +#endif + return (struct pipe_memory_allocation *)mem; } static void -llvmpipe_free_memory(struct pipe_screen *screen, +llvmpipe_free_memory(struct pipe_screen *pscreen, struct pipe_memory_allocation *pmem) { - os_free_aligned(pmem); + struct llvmpipe_screen *screen = llvmpipe_screen(pscreen); + struct llvmpipe_memory_allocation *mem = (struct llvmpipe_memory_allocation *)pmem; + + if (mem->fd) { + mtx_lock(&screen->mem_mutex); + util_vma_heap_free(&screen->mem_heap, mem->offset, mem->size); + mtx_unlock(&screen->mem_mutex); + } + +#if DETECT_OS_LINUX + if (mem->cpu_addr != MAP_FAILED) + munmap(mem->cpu_addr, mem->size); +#else + free(mem->cpu_addr); +#endif + + FREE(mem); } @@ -1300,6 +1343,17 @@ llvmpipe_map_memory(struct pipe_screen *screen, struct pipe_memory_allocation *pmem) { struct llvmpipe_memory_allocation *mem = (struct llvmpipe_memory_allocation *)pmem; + +#if DETECT_OS_LINUX + if (mem->cpu_addr != MAP_FAILED) + return mem->cpu_addr; + + /* create a "CPU" mapping */ + mem->cpu_addr = mmap(NULL, mem->size, PROT_READ|PROT_WRITE, MAP_SHARED, + mem->fd, mem->offset); + assert(mem->cpu_addr != MAP_FAILED); +#endif + return mem->cpu_addr; } diff --git a/src/gallium/drivers/llvmpipe/lp_texture.h b/src/gallium/drivers/llvmpipe/lp_texture.h index ebce156f33d..eda7bc81b7c 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.h +++ b/src/gallium/drivers/llvmpipe/lp_texture.h @@ -126,6 +126,8 @@ struct llvmpipe_transfer struct llvmpipe_memory_allocation { + int fd; + uint64_t offset; void *cpu_addr; uint64_t size; enum llvmpipe_memory_fd_type type;