diff options
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 68 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.h | 4 |
2 files changed, 69 insertions, 3 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b61abd4ed06..2192e9a378f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -68,6 +68,7 @@ #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_mempool.h" +#include "BLI_mmap.h" #include "BLI_threads.h" #include "BLT_translation.h" @@ -1179,6 +1180,53 @@ static ssize_t fd_read_from_memory(FileData *filedata, return readsize; } +/* Memory-mapped file reading. + * By using mmap(), we can map a file so that it can be treated like normal memory, + * meaning that we can just read from it with memcpy() etc. + * This avoids system call overhead and can significantly speed up file loading. + */ + +static ssize_t fd_read_from_mmap(FileData *filedata, + void *buffer, + size_t size, + bool *UNUSED(r_is_memchunck_identical)) +{ + /* don't read more bytes than there are available in the buffer */ + size_t readsize = MIN2(size, (size_t)(filedata->buffersize - filedata->file_offset)); + + if (!BLI_mmap_read(filedata->mmap_file, buffer, filedata->file_offset, readsize)) { + return 0; + } + + filedata->file_offset += readsize; + + return readsize; +} + +static off64_t fd_seek_from_mmap(FileData *filedata, off64_t offset, int whence) +{ + off64_t new_pos; + if (whence == SEEK_CUR) { + new_pos = filedata->file_offset + offset; + } + else if (whence == SEEK_SET) { + new_pos = offset; + } + else if (whence == SEEK_END) { + new_pos = filedata->buffersize + offset; + } + else { + return -1; + } + + if (new_pos < 0 || new_pos > filedata->buffersize) { + return -1; + } + + filedata->file_offset = new_pos; + return filedata->file_offset; +} + /* MemFile reading. */ static ssize_t fd_read_from_memfile(FileData *filedata, @@ -1306,6 +1354,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath, { FileDataReadFn *read_fn = NULL; FileDataSeekFn *seek_fn = NULL; /* Optional. */ + size_t buffersize = 0; + BLI_mmap_file *mmap_file = NULL; gzFile gzfile = (gzFile)Z_NULL; @@ -1322,14 +1372,21 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath, return NULL; } - BLI_lseek(file, 0, SEEK_SET); - /* Regular file. */ if (memcmp(header, "BLENDER", sizeof(header)) == 0) { read_fn = fd_read_data_from_file; seek_fn = fd_seek_data_from_file; + + mmap_file = BLI_mmap_open(file); + if (mmap_file != NULL) { + read_fn = fd_read_from_mmap; + seek_fn = fd_seek_from_mmap; + buffersize = BLI_lseek(file, 0, SEEK_END); + } } + BLI_lseek(file, 0, SEEK_SET); + /* Gzip file. */ errno = 0; if ((read_fn == NULL) && @@ -1363,6 +1420,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath, fd->read = read_fn; fd->seek = seek_fn; + fd->mmap_file = mmap_file; + fd->buffersize = buffersize; return fd; } @@ -1531,6 +1590,11 @@ void blo_filedata_free(FileData *fd) fd->buffer = NULL; } + if (fd->mmap_file) { + BLI_mmap_free(fd->mmap_file); + fd->mmap_file = NULL; + } + /* Free all BHeadN data blocks */ #ifndef NDEBUG BLI_freelistN(&fd->bhead_list); diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index c724cc32051..86f05eda7b7 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -41,6 +41,7 @@ struct Object; struct OldNewMap; struct ReportList; struct UserDef; +struct BLI_mmap_file; typedef struct IDNameLib_Map IDNameLib_Map; @@ -83,8 +84,9 @@ typedef struct FileData { /** Regular file reading. */ int filedes; - /** Variables needed for reading from memory / stream. */ + /** Variables needed for reading from memory / stream / memory-mapped files. */ const char *buffer; + struct BLI_mmap_file *mmap_file; /** Variables needed for reading from memfile (undo). */ struct MemFile *memfile; /** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use |