Skip to content

Instantly share code, notes, and snippets.

@JohnnyonFlame
Created February 17, 2024 20:23
Show Gist options
  • Save JohnnyonFlame/525468ffd197a67d068fa18f165c35d9 to your computer and use it in GitHub Desktop.
Save JohnnyonFlame/525468ffd197a67d068fa18f165c35d9 to your computer and use it in GitHub Desktop.
VVVVVV mmaped music.
diff --git a/desktop_version/CMakeLists.txt b/desktop_version/CMakeLists.txt
index 9e60db8b..4d522961 100644
--- a/desktop_version/CMakeLists.txt
+++ b/desktop_version/CMakeLists.txt
@@ -22,7 +22,7 @@ if(OFFICIAL_BUILD AND NOT MAKEANDPLAY)
endif()
option(REMOVE_ABSOLUTE_PATHS "If supported by the compiler, replace all absolute paths to source directories compiled into the binary (if any) with relative paths" ON)
-
+option(USE_MMAP "Use memory mapped blobs where possible, lowering physical memory requirements." OFF)
# Architecture Flags
if(APPLE)
@@ -396,6 +396,10 @@ if(REMOVE_ABSOLUTE_PATHS)
endif()
endif()
+if(USE_MMAP)
+ message(STATUS "Using memory mapped blobs")
+ target_compile_definitions(VVVVVV PRIVATE -DUSE_MMAP=1)
+endif()
target_compile_options(VVVVVV PRIVATE ${GLOBAL_COMPILE_FLAGS})
diff --git a/desktop_version/src/BinaryBlob.cpp b/desktop_version/src/BinaryBlob.cpp
index 62d99f19..996328a3 100644
--- a/desktop_version/src/BinaryBlob.cpp
+++ b/desktop_version/src/BinaryBlob.cpp
@@ -18,6 +18,10 @@ binaryBlob::binaryBlob(void)
#endif
SDL_zeroa(m_headers);
SDL_zeroa(m_memblocks);
+#ifdef USE_MMAP
+ m_mmap = MAP_FAILED;
+ m_fd = -1;
+#endif
}
#ifdef VVV_COMPILEMUSIC
@@ -83,20 +87,41 @@ void binaryBlob::writeBinaryBlob(const char* _name)
bool binaryBlob::unPackBinary(const char* name)
{
- return FILESYSTEM_loadBinaryBlob(this, name);
+ if (FILESYSTEM_mapBinaryBlob(this, name))
+ return true;
+ if (FILESYSTEM_loadBinaryBlob(this, name))
+ return true;
+
+ vlog_error("%s: Failed to read blob", name);
+ return false;
}
void binaryBlob::clear(void)
{
- for (size_t i = 0; i < SDL_arraysize(m_headers); i += 1)
+#ifdef USE_MMAP
+ if (m_fd >= 0)
{
- if (m_memblocks[i] != NULL)
+ munmap(m_mmap, m_mapsz);
+ close(m_fd);
+ m_mmap = MAP_FAILED;
+ m_mapsz = 0;
+ m_fd = -1;
+ SDL_zeroa(m_memblocks);
+ SDL_zeroa(m_headers);
+ }
+ else
+#endif //USE_MMAP
+ {
+ for (size_t i = 0; i < SDL_arraysize(m_headers); i += 1)
{
- VVV_free(m_memblocks[i]);
+ if (m_memblocks[i] != NULL)
+ {
+ VVV_free(m_memblocks[i]);
+ }
}
+ SDL_zeroa(m_memblocks);
+ SDL_zeroa(m_headers);
}
- SDL_zeroa(m_memblocks);
- SDL_zeroa(m_headers);
}
int binaryBlob::getIndex(const char* _name)
diff --git a/desktop_version/src/BinaryBlob.h b/desktop_version/src/BinaryBlob.h
index f8089930..ea4c95d2 100644
--- a/desktop_version/src/BinaryBlob.h
+++ b/desktop_version/src/BinaryBlob.h
@@ -1,6 +1,13 @@
#ifndef BINARYBLOB_H
#define BINARYBLOB_H
+#ifdef USE_MMAP
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif //USE_MMAP
#include <stddef.h>
#include <stdint.h>
@@ -63,6 +70,11 @@ public:
#endif
resourceheader m_headers[max_headers];
char* m_memblocks[max_headers];
+#ifdef USE_MMAP
+ void *m_mmap;
+ long long unsigned m_mapsz;
+ int m_fd;
+#endif //USE_MMAP
};
diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp
index 5643182d..83fe6047 100644
--- a/desktop_version/src/FileSystemUtils.cpp
+++ b/desktop_version/src/FileSystemUtils.cpp
@@ -1071,6 +1071,88 @@ fail:
return true;
}
+#ifdef USE_MMAP
+bool FILESYSTEM_mapBinaryBlob(binaryBlob *blob, const char *filename)
+{
+ int valid = 0;
+ uintptr_t offset = 0;
+ const char *fs_realdir;
+ char fs_path[MAX_PATH];
+ struct stat s_stat;
+
+ fs_realdir = PHYSFS_getRealDir(filename);
+ if (fs_realdir == NULL)
+ {
+ vlog_warn("%s: Unable to find file", filename);
+ return false;
+ }
+ snprintf(fs_path, sizeof(fs_path)-1, "%s%s%s", fs_realdir, pathSep, filename);
+
+ blob->m_fd = open(fs_path, O_RDONLY);
+ if (blob->m_fd < 0)
+ {
+ vlog_warn("%s: Unable to open file", fs_path);
+ return false;
+ }
+
+ fstat(blob->m_fd, &s_stat);
+ blob->m_mapsz = s_stat.st_size;
+
+ blob->m_mmap = mmap(NULL, blob->m_mapsz, PROT_READ, MAP_PRIVATE, blob->m_fd, 0);
+ if (blob->m_mmap == MAP_FAILED)
+ {
+ vlog_error("%s: Unable to mmap file", fs_path);
+ goto clean_mmap;
+ }
+
+ offset = sizeof(blob->m_headers);
+
+ SDL_memcpy(&blob->m_headers, blob->m_mmap, sizeof(blob->m_headers));
+ for (size_t i = 0; i < SDL_arraysize(blob->m_headers); i++)
+ {
+ resourceheader *header = &blob->m_headers[i];
+ char **memblock = &blob->m_memblocks[i];
+
+ header->name[sizeof(header->name) - 1] = '\0';
+ if (header->size < 1) {
+ vlog_error("%s: Header %li's size value is zero or negative", fs_path, i);
+ goto fail_mmaped_header;
+ }
+
+ *memblock = (char*)((uintptr_t)blob->m_mmap + offset);
+ offset += header->size;
+ valid += 1;
+ continue;
+fail_mmaped_header:
+ header->valid = false;
+ }
+
+ if (valid == 0)
+ {
+ goto clean_mmap;
+ }
+
+ return true;
+clean_mmap:
+ if (blob->m_fd > 0) {
+ close(blob->m_fd);
+ blob->m_fd = -1;
+ }
+ if (blob->m_mmap != MAP_FAILED) {
+ munmap(blob->m_mmap, blob->m_mapsz);
+ blob->m_mmap = MAP_FAILED;
+ }
+
+ return false;
+}
+#else //USE_MMAP
+bool FILESYSTEM_mapBinaryBlob(binaryBlob *blob, const char *filename)
+{
+ /* Implementation only available on POSIX. */
+ return false;
+}
+#endif
+
bool FILESYSTEM_saveTiXml2Document(const char *name, tinyxml2::XMLDocument& doc, bool sync /*= true*/)
{
if (!isInit)
diff --git a/desktop_version/src/FileSystemUtils.h b/desktop_version/src/FileSystemUtils.h
index e5c65031..4281fd64 100644
--- a/desktop_version/src/FileSystemUtils.h
+++ b/desktop_version/src/FileSystemUtils.h
@@ -42,7 +42,7 @@ void FILESYSTEM_loadAssetToMemory(
);
bool FILESYSTEM_loadBinaryBlob(binaryBlob* blob, const char* filename);
-
+bool FILESYSTEM_mapBinaryBlob(binaryBlob *blob, const char *filename);
bool FILESYSTEM_saveTiXml2Document(const char *name, tinyxml2::XMLDocument& doc, bool sync = true);
bool FILESYSTEM_loadTiXml2Document(const char *name, tinyxml2::XMLDocument& doc);
bool FILESYSTEM_loadAssetTiXml2Document(const char *name, tinyxml2::XMLDocument& doc);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment