From b157b66d1a19e0230d3b0d94e92c7cb17d41e077 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Sat, 5 Aug 2023 17:15:55 -0700 Subject: [PATCH] Moved mimir namespace to its own submodule --- .gitmodules | 3 + CMakeLists.txt | 8 + kraken/CMakeLists.txt | 1 - kraken/KRContext.cpp | 25 +- kraken/KRContext.h | 2 - kraken/KRResource+blend.cpp | 4 +- kraken/KRResource+obj.cpp | 4 +- kraken/KRResource.cpp | 38 --- kraken/KRResource.h | 4 - kraken/KRShader.cpp | 6 +- kraken/KRShaderManager.cpp | 6 +- kraken/block.cpp | 610 ------------------------------------ kraken/block.h | 131 -------- mimir | 1 + 14 files changed, 31 insertions(+), 812 deletions(-) delete mode 100755 kraken/block.cpp delete mode 100755 kraken/block.h create mode 160000 mimir diff --git a/.gitmodules b/.gitmodules index efbf647..a08bf54 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "3rdparty/compressonator"] path = 3rdparty/compressonator url = https://github.com/GPUOpen-Tools/compressonator.git +[submodule "mimir"] + path = mimir + url = https://src.kearwood.com/kraken_engine/mimir diff --git a/CMakeLists.txt b/CMakeLists.txt index 096236b..902174c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,9 @@ add_public_header(hydra/include/vector3.h) add_public_header(hydra/include/vector4.h) add_public_header(hydra/include/vector2i.h) +add_public_header(mimir/include/mimir.h) +add_public_header(mimir/include/block.h) + # ---- Android ---- if(ANDROID) add_subdirectory(kraken_android) @@ -102,6 +105,11 @@ add_subdirectory(hydra) include_directories(hydra/include) list (APPEND EXTRA_LIBS hydra) +# ---- Mimir ---- +add_subdirectory(mimir) +include_directories(mimir/include) +list (APPEND EXTRA_LIBS mimir) + # ---- Compressonator CMP_Core ---- add_subdirectory(3rdparty/compressonator/cmp_core) include_directories("${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/compressonator/cmp_core/source") diff --git a/kraken/CMakeLists.txt b/kraken/CMakeLists.txt index 389e18e..0a45e0f 100644 --- a/kraken/CMakeLists.txt +++ b/kraken/CMakeLists.txt @@ -3,7 +3,6 @@ add_subdirectory(public) set(KRAKEN_PUBLIC_HEADERS "${KRAKEN_PUBLIC_HEADERS}" PARENT_SCOPE) # Private Implementation -add_sources(block.cpp) add_sources(kraken.cpp) add_sources(KRAmbientZone.cpp) add_sources(KRAnimation.cpp) diff --git a/kraken/KRContext.cpp b/kraken/KRContext.cpp index 74c6197..ff93d3d 100755 --- a/kraken/KRContext.cpp +++ b/kraken/KRContext.cpp @@ -31,6 +31,8 @@ #include "KREngine-common.h" +#include "mimir.h" + #include "KRContext.h" #include "KRCamera.h" #include "KRAudioManager.h" @@ -60,9 +62,6 @@ int KRContext::KRENGINE_MIN_TEXTURE_DIM = 64; // TODO - This should be configured per-scene? Or auto/dynamic? int KRContext::KRENGINE_PRESTREAM_DISTANCE = 1000.0f; -int KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY; -int KRContext::KRENGINE_SYS_PAGE_SIZE; - #if TARGET_OS_IPHONE @@ -128,21 +127,7 @@ KRContext::KRContext(const KrInitializeInfo* initializeInfo) m_pSourceManager = std::make_unique(*this); m_streamingEnabled = true; -#if defined(_WIN32) || defined(_WIN64) - - SYSTEM_INFO winSysInfo; - GetSystemInfo(&winSysInfo); - KRENGINE_SYS_ALLOCATION_GRANULARITY = winSysInfo.dwAllocationGranularity; - KRENGINE_SYS_PAGE_SIZE = winSysInfo.dwPageSize; - -#elif defined(__APPLE__) || defined(ANDROID) - - KRENGINE_SYS_PAGE_SIZE = getpagesize(); - KRENGINE_SYS_ALLOCATION_GRANULARITY = KRENGINE_SYS_PAGE_SIZE; - -#else -#error Unsupported -#endif + mimir::init(); m_presentationThread->start(); m_streamerThread->start(); @@ -329,8 +314,8 @@ std::vector KRContext::getResources() KRResource* KRContext::loadResource(const std::string& file_name, Block* data) { - std::string name = KRResource::GetFileBase(file_name); - std::string extension = KRResource::GetFileExtension(file_name); + std::string name = util::GetFileBase(file_name); + std::string extension = util::GetFileExtension(file_name); KRResource* resource = nullptr; diff --git a/kraken/KRContext.h b/kraken/KRContext.h index 7756c3e..e512a84 100755 --- a/kraken/KRContext.h +++ b/kraken/KRContext.h @@ -67,8 +67,6 @@ public: static int KRENGINE_MAX_TEXTURE_DIM; static int KRENGINE_MIN_TEXTURE_DIM; static int KRENGINE_PRESTREAM_DISTANCE; - static int KRENGINE_SYS_ALLOCATION_GRANULARITY; - static int KRENGINE_SYS_PAGE_SIZE; KRContext(const KrInitializeInfo* initializeInfo); diff --git a/kraken/KRResource+blend.cpp b/kraken/KRResource+blend.cpp index 539706c..2f9d665 100755 --- a/kraken/KRResource+blend.cpp +++ b/kraken/KRResource+blend.cpp @@ -35,12 +35,14 @@ #include "KRScene.h" #include "KRResource+blend.h" +#include "mimir.h" + using namespace mimir; KRScene* KRResource::LoadBlenderScene(KRContext& context, const std::string& path) { - KRScene* pScene = new KRScene(context, KRResource::GetFileBase(path)); + KRScene* pScene = new KRScene(context, mimir::util::GetFileBase(path)); Block data; diff --git a/kraken/KRResource+obj.cpp b/kraken/KRResource+obj.cpp index bdf1bba..17918a3 100755 --- a/kraken/KRResource+obj.cpp +++ b/kraken/KRResource+obj.cpp @@ -34,11 +34,13 @@ #include "KRResource.h" #include "KRMesh.h" +#include "mimir.h" + using namespace mimir; KRMesh* KRResource::LoadObj(KRContext& context, const std::string& path) { - KRMesh* new_mesh = new KRMesh(context, KRResource::GetFileBase(path)); + KRMesh* new_mesh = new KRMesh(context, util::GetFileBase(path)); KRMesh::mesh_info mi; diff --git a/kraken/KRResource.cpp b/kraken/KRResource.cpp index fe3294f..ecac755 100755 --- a/kraken/KRResource.cpp +++ b/kraken/KRResource.cpp @@ -51,44 +51,6 @@ std::string KRResource::getName() return m_name; } -std::string KRResource::GetFileExtension(const std::string& name) -{ - if (name.find_last_of(".") != std::string::npos) { - return name.substr(name.find_last_of(".") + 1); - } else { - return ""; - } -} - -std::string KRResource::GetFileBase(const std::string& name) -{ - std::string f = name; - - // Normalize Windows Paths - std::replace(f.begin(), f.end(), '\\', '/'); - - // Strip off directory - if (f.find_last_of("/") != std::string::npos) { - f = f.substr(f.find_last_of("/") + 1); - } - - // Strip off extension - if (f.find_last_of(".") != std::string::npos) { - f = f.substr(0, f.find_last_of(".")); - } - - return f; -} - -std::string KRResource::GetFilePath(const std::string& name) -{ - if (name.find_last_of("/") != std::string::npos) { - return name.substr(0, name.find_last_of("/")); - } else { - return ""; - } -} - bool KRResource::save(const std::string& path) { Block data; diff --git a/kraken/KRResource.h b/kraken/KRResource.h index 26b9f28..e727647 100755 --- a/kraken/KRResource.h +++ b/kraken/KRResource.h @@ -48,10 +48,6 @@ public: KrResult moveToBundle(KRBundle* bundle); - static std::string GetFileExtension(const std::string& name); - static std::string GetFileBase(const std::string& name); - static std::string GetFilePath(const std::string& name); - virtual ~KRResource(); static KRMesh* LoadObj(KRContext& context, const std::string& path); diff --git a/kraken/KRShader.cpp b/kraken/KRShader.cpp index 032c151..ede47e4 100644 --- a/kraken/KRShader.cpp +++ b/kraken/KRShader.cpp @@ -32,6 +32,8 @@ #include "KRShader.h" #include "spirv_reflect.h" +#include "mimir.h" + using namespace mimir; ShaderStage getShaderStageFromExtension(const char* extension) @@ -108,7 +110,7 @@ KRShader::KRShader(KRContext& context, std::string name, std::string extension) { m_pData = new Block(); m_extension = extension; - m_subExtension = KRResource::GetFileExtension(name); + m_subExtension = util::GetFileExtension(name); m_stage = getShaderStageFromExtension(m_subExtension.c_str()); m_reflectionValid = false; @@ -119,7 +121,7 @@ KRShader::KRShader(KRContext& context, std::string name, std::string extension, { m_pData = data; m_extension = extension; - m_subExtension = KRResource::GetFileExtension(name); + m_subExtension = util::GetFileExtension(name); m_stage = getShaderStageFromExtension(m_subExtension.c_str()); m_reflectionValid = false; } diff --git a/kraken/KRShaderManager.cpp b/kraken/KRShaderManager.cpp index a33ec00..844761e 100644 --- a/kraken/KRShaderManager.cpp +++ b/kraken/KRShaderManager.cpp @@ -36,6 +36,8 @@ #include "KRUnknownManager.h" #include "KRUnknown.h" +#include "mimir.h" + using namespace mimir; KRShaderManager::KRShaderManager(KRContext& context) : KRResourceManager(context) @@ -389,8 +391,8 @@ glslang::TShader::Includer::IncludeResult* KRShaderManager::Includer::includeLoc const char* includerName, size_t inclusionDepth) { - std::string name = KRResource::GetFileBase(headerName); - std::string extension = KRResource::GetFileExtension(headerName); + std::string name = util::GetFileBase(headerName); + std::string extension = util::GetFileExtension(headerName); KRSource* source = m_context->getSourceManager()->get(name, extension); if (!source) { return nullptr; diff --git a/kraken/block.cpp b/kraken/block.cpp deleted file mode 100755 index cc7833f..0000000 --- a/kraken/block.cpp +++ /dev/null @@ -1,610 +0,0 @@ -// -// block.cpp -// Kraken Engine -// -// Copyright 2023 Kearwood Gilbert. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// The views and conclusions contained in the software and documentation are those of the -// authors and should not be interpreted as representing official policies, either expressed -// or implied, of Kearwood Gilbert. -// - -#include "block.h" -#include "KREngine-common.h" -#include "KRResource.h" -#include "KRContext.h" - -#include -#if defined(__APPLE__) || defined(ANDROID) -#include -#include -#endif - -#define KRENGINE_MIN_MMAP 32768 -#define KRAKEN_MEM_ROUND_DOWN_PAGE(x) ((x) & ~(KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY - 1)) -#define KRAKEN_MEM_ROUND_UP_PAGE(x) ((((x) - 1) & ~(KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY - 1)) + KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY) - -int m_mapCount = 0; -size_t m_mapSize = 0; -size_t m_mapOverhead = 0; - -namespace mimir { - -Block::Block() -{ - m_data = NULL; - m_data_size = 0; - m_data_offset = 0; -#if defined(_WIN32) || defined(_WIN64) - m_hPackFile = INVALID_HANDLE_VALUE; - m_hFileMapping = NULL; -#elif defined(__APPLE__) - m_fdPackFile = 0; -#endif - m_fileName = ""; - m_mmapData = NULL; - m_fileOwnerDataBlock = NULL; - m_bMalloced = false; - m_lockCount = 0; - m_bReadOnly = false; -} - -Block::Block(void* data, size_t size) -{ - m_data = NULL; - m_data_size = 0; - m_data_offset = 0; -#if defined(_WIN32) || defined(_WIN64) - m_hPackFile = INVALID_HANDLE_VALUE; - m_hFileMapping = NULL; -#elif defined(__APPLE__) - m_fdPackFile = 0; -#endif - m_fileName = ""; - m_mmapData = NULL; - m_fileOwnerDataBlock = NULL; - m_bMalloced = false; - m_lockCount = 0; - m_bReadOnly = false; - load(data, size); -} - -Block::~Block() -{ - unload(); -} - -// Unload a file, releasing any mmap'ed file handles or malloc'ed ram that was in use -void Block::unload() -{ - assert(m_lockCount == 0); - -#if defined(_WIN32) || defined(_WIN64) - if (m_hPackFile != INVALID_HANDLE_VALUE) { - // Memory mapped file - if (m_fileOwnerDataBlock == this) { - CloseHandle(m_hPackFile); - } - m_hPackFile = INVALID_HANDLE_VALUE; - } -#elif defined(__APPLE__) - if (m_fdPackFile) { - // Memory mapped file - if (m_fileOwnerDataBlock == this) { - close(m_fdPackFile); - } - m_fdPackFile = 0; - } -#endif - - if (m_data != NULL && m_bMalloced) { - // Malloc'ed data - free(m_data); - } - - m_bMalloced = false; - m_data = NULL; - m_data_size = 0; - m_data_offset = 0; - m_fileName = ""; - m_mmapData = NULL; - m_fileOwnerDataBlock = NULL; - m_bReadOnly = false; -} - -// Encapsulate a pointer. Note - The pointer will not be free'ed -bool Block::load(void* data, size_t size) -{ - unload(); - m_data = data; - m_data_size = size; - m_data_offset = 0; - m_bReadOnly = false; - return true; -} - -// Load a file into memory using mmap. The data pointer will be protected as read-only until append() or expand() is called -bool Block::load(const std::string& path) -{ - bool success = false; - unload(); - - m_bReadOnly = true; - -#if defined(_WIN32) || defined(_WIN64) - m_hPackFile = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (m_hPackFile != INVALID_HANDLE_VALUE) { - m_fileOwnerDataBlock = this; - m_fileName = KRResource::GetFileBase(path); - FILE_STANDARD_INFO fileInfo; - if (GetFileInformationByHandleEx(m_hPackFile, FileStandardInfo, &fileInfo, sizeof(fileInfo))) { - m_data_size = fileInfo.EndOfFile.QuadPart; - m_data_offset = 0; - success = true; - } - } -#elif defined(__APPLE__) - m_fdPackFile = open(path.c_str(), O_RDONLY); - if (m_fdPackFile >= 0) { - m_fileOwnerDataBlock = this; - m_fileName = KRResource::GetFileBase(path); - struct stat statbuf; - if (fstat(m_fdPackFile, &statbuf) >= 0) { - m_data_size = statbuf.st_size; - m_data_offset = 0; - success = true; - } - } -#endif - if (!success) { - // If anything failed, don't leave the object in an invalid state - unload(); - } - return success; -} - -// Create a Block encapsulating a sub-region of this block. The caller is responsible to free the object. -Block* Block::getSubBlock(int start, int length) -{ - Block* new_block = new Block(); - - new_block->m_data_size = length; -#if defined(_WIN32) || defined(_WIN64) - if (m_hPackFile != INVALID_HANDLE_VALUE) { - new_block->m_hPackFile = m_hPackFile; -#elif defined(__APPLE__) || defined(ANDROID) - if (m_fdPackFile) { - new_block->m_fdPackFile = m_fdPackFile; -#else -#error Unsupported -#endif - new_block->m_fileOwnerDataBlock = m_fileOwnerDataBlock; - new_block->m_data_offset = start + m_data_offset; - } else if (m_bMalloced) { - new_block->m_data = (unsigned char*)m_data + start + m_data_offset; - } - new_block->m_bReadOnly = true; - - return new_block; -} - -// Return a pointer to the start of the data block -void* Block::getStart() -{ - assertLocked(); - return m_data; -} - -// Return a pointer to the byte after the end of the data block -void* Block::getEnd() -{ - assertLocked(); - return (unsigned char*)m_data + m_data_size; -} - -// Return the size of the data block. Use append() or expand() to make the data block larger -size_t Block::getSize() const -{ - return m_data_size; -} - -// Expand the data block, and switch it to read-write mode. Note - this may result in a mmap'ed file being copied to malloc'ed ram and then closed -void Block::expand(size_t size) -{ -#if defined(_WIN32) || defined(_WIN64) - if (m_data == NULL && m_hPackFile == INVALID_HANDLE_VALUE) { -#elif defined(__APPLE__) || defined(ANDROID) - if (m_data == NULL && m_fdPackFile == 0) { -#else -#error Unsupported -#endif - // Starting with an empty data block; allocate memory on the heap - m_data = malloc(size); - assert(m_data != NULL); - m_data_size = size; - m_data_offset = 0; - m_bMalloced = true; - } else if (m_bMalloced) { - // Starting with a malloc'ed data block; realloc it expand - m_data = realloc(m_data, m_data_size + size); - m_data_size += size; - } else { - // Starting with a mmap'ed data block, an encapsulated pointer, or a sub-block; copy it to ram before expanding to avoid updating the original file until save() is called - // ... Or starting with a pointer reference, we must make our own copy and must not free the pointer - void* pNewData = malloc(m_data_size + size); - assert(pNewData != NULL); - - // Copy exising data - copy(pNewData); - - // Unload existing data allocation, which is now redundant - size_t new_size = m_data_size + size; // We need to store this before unload() as unload() will reset it - unload(); - m_bMalloced = true; - m_data = pNewData; - m_data_size = new_size; - m_data_offset = 0; - } -} - -// Append data to the end of the block, increasing the size of the block and making it read-write. -void Block::append(void* data, size_t size) -{ - // Expand the data block - expand(size); - - // Fill the new space with the data to append - lock(); - memcpy((unsigned char*)m_data + m_data_size - size, data, size); - unlock(); -} - - -// Copy the entire data block to the destination pointer -void Block::copy(void* dest) -{ - copy(dest, 0, (int)m_data_size); -} - -// Copy a range of data to the destination pointer -void Block::copy(void* dest, int start, int count) -{ -#if defined(_WIN32) || defined(_WIN64) - if (m_lockCount == 0 && m_hPackFile != INVALID_HANDLE_VALUE) { - // Optimization: If we haven't mmap'ed or malloced the data already, ReadFile() it directly from the file into the buffer - LARGE_INTEGER distance; - distance.QuadPart = start + m_data_offset; - bool success = SetFilePointerEx(m_hPackFile, distance, NULL, FILE_BEGIN); - assert(success); - - void* w = dest; - DWORD bytes_remaining = count; - while (bytes_remaining > 0) { - DWORD bytes_read = 0; - success = ReadFile(m_hPackFile, w, bytes_remaining, &bytes_read, NULL); - assert(success); - assert(bytes_read > 0); - w = (unsigned char*)w + bytes_read; - bytes_remaining -= bytes_read; - } - assert(bytes_remaining == 0); -#elif defined(__APPLE__) || defined(ANDROID) - if (m_lockCount == 0 && m_fdPackFile != 0) { - // Optimization: If we haven't mmap'ed or malloced the data already, pread() it directly from the file into the buffer - ssize_t r = pread(m_fdPackFile, dest, count, start + m_data_offset); - assert(r != -1); -#else -#error Unsupported -#endif - } else { - lock(); - memcpy((unsigned char*)dest, (unsigned char*)m_data + start, count); - unlock(); -} -} - -// Append data to the end of the block, increasing the size of the block and making it read-write. -void Block::append(Block & data) -{ - data.lock(); - append(data.getStart(), data.getSize()); - data.unlock(); -} - -// Append string to the end of the block, increasing the size of the block and making it read-write. The resulting datablock includes a terminating character -void Block::append(const std::string & s) -{ - const char* szText = s.c_str(); - size_t text_length = strlen(szText); - size_t prev_size = getSize(); - if (prev_size == 0) { - // First string appended to data block, just memcpy it.. - append((void*)szText, text_length + 1); - } else { - // prev_size includes a null terminating character, don't need to add two. - expand(text_length); - lock(); - // Copy new string, overwriting prior null terminating character and - // including new terminating character - memcpy((unsigned char*)m_data + prev_size - 1, szText, text_length + 1); - unlock(); - } -} - -// Save the data to a file. -bool Block::save(const std::string & path) -{ -#if defined(_WIN32) || defined(_WIN64) - bool success = true; - HANDLE hNewFile = INVALID_HANDLE_VALUE; - HANDLE hFileMapping = NULL; - void* pNewData = NULL; - - hNewFile = CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hNewFile == INVALID_HANDLE_VALUE) { - success = false; - } - - if (success) { - hFileMapping = CreateFileMappingFromApp(hNewFile, NULL, PAGE_READWRITE, m_data_size, NULL); - if (hFileMapping == NULL) { - success = false; - } - } - - if (success) { - pNewData = MapViewOfFileFromApp(hFileMapping, FILE_MAP_WRITE, 0, m_data_size); - if (pNewData == NULL) { - success = false; - } - } - - if (success) { - // Copy data to new file - copy(pNewData); - } - - if (pNewData != NULL) { - UnmapViewOfFile(pNewData); - } - - if (hFileMapping != NULL) { - CloseHandle(hFileMapping); - } - - if (hNewFile != INVALID_HANDLE_VALUE) { - CloseHandle(hNewFile); - } - - return success; - -#elif defined(__APPLE__) || defined(ANDROID) - int fdNewFile = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); - if (fdNewFile == -1) { - return false; - } - - // Seek to end of file and write a byte to enlarge it - lseek(fdNewFile, m_data_size - 1, SEEK_SET); - write(fdNewFile, "", 1); - - // Now map it... - void* pNewData = mmap(0, m_data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdNewFile, 0); - if (pNewData == (caddr_t)-1) { - close(fdNewFile); - return false; - } - if (m_data != NULL) { - // Copy data to new file - copy(pNewData); - - // Unmap the new file - munmap(pNewData, m_data_size); - - // Close the new file - close(fdNewFile); - } - return true; - -#else -#error Unsupported -#endif -} - -// Get contents as a string -std::string Block::getString() -{ - Block b; - b.append(*this); - b.append((void*)"\0", 1); // Ensure data is null terminated, to read as a string safely - b.lock(); - std::string ret = std::string((char*)b.getStart()); - b.unlock(); - return ret; -} - -#if defined(_WIN32) || defined(_WIN64) -void ReportWindowsLastError(LPCTSTR lpszFunction) -{ - LPVOID lpMsgBuf; - LPVOID lpDisplayBuf; - DWORD dw = GetLastError(); - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, NULL); - - // Display the error message and exit the process - - lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, - (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); - fprintf(stderr, - TEXT("%s failed with error %d: %s\n"), - lpszFunction, dw, (LPCTSTR)lpMsgBuf); - - LocalFree(lpMsgBuf); - LocalFree(lpDisplayBuf); -} -#endif - -// Lock the memory, forcing it to be loaded into a contiguous block of address space -void Block::lock() -{ - if (m_lockCount == 0) { - - // Memory mapped file; ensure data is mapped to ram -#if defined(_WIN32) || defined(_WIN64) - if (m_hPackFile != INVALID_HANDLE_VALUE) { -#elif defined(__APPLE__) || defined(ANDROID) - if (m_fdPackFile) { -#else -#error Unsupported -#endif - if (m_data_size < KRENGINE_MIN_MMAP) { - m_data = malloc(m_data_size); - assert(m_data != NULL); - copy(m_data); - } else { - size_t alignment_offset = m_data_offset & (KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY - 1); - assert(m_mmapData == NULL); -#if defined(_WIN32) || defined(_WIN64) - m_hFileMapping = CreateFileMappingFromApp(m_hPackFile, NULL, m_bReadOnly ? PAGE_READONLY : PAGE_READWRITE, m_fileOwnerDataBlock->getSize(), NULL); - if (m_hFileMapping == NULL) { - ReportWindowsLastError("CreateFileMappingFromApp"); - } - assert(m_hFileMapping != NULL); - - m_mmapData = MapViewOfFileFromApp(m_hFileMapping, m_bReadOnly ? FILE_MAP_READ | FILE_MAP_COPY : FILE_MAP_WRITE, m_data_offset - alignment_offset, m_data_size + alignment_offset); - if (m_mmapData == NULL) { - ReportWindowsLastError("MapViewOfFileFromApp"); - } - assert(m_mmapData != NULL); -#elif defined(__APPLE__) || defined(ANDROID) - //fprintf(stderr, "Block::lock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); - // Round m_data_offset down to the next memory page, as required by mmap - - if ((m_mmapData = mmap(0, m_data_size + alignment_offset, m_bReadOnly ? PROT_READ : PROT_WRITE, MAP_SHARED, m_fdPackFile, m_data_offset - alignment_offset)) == (caddr_t)-1) { - int iError = errno; - switch (iError) { - case EACCES: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with EACCES"); - break; - case EBADF: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with EBADF"); - break; - case EMFILE: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with EMFILE"); - break; - case EINVAL: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with EINVAL"); - break; - case ENOMEM: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with ENOMEM"); - break; - case ENXIO: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with ENXIO"); - break; - case EOVERFLOW: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with EOVERFLOW"); - break; - default: - KRContext::Log(KRContext::LOG_LEVEL_ERROR, "mmap failed with errno: %i", iError); - break; - } - assert(false); // mmap() failed. - } -#else -#error Unsupported -#endif - m_mapCount++; - m_mapSize += m_data_size; - m_mapOverhead += alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; - // fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); - m_data = (unsigned char*)m_mmapData + alignment_offset; - } - } - } -m_lockCount++; -} - -// Unlock the memory, releasing the address space for use by other allocations -void Block::unlock() -{ - // We expect that the data block was previously locked - assertLocked(); - - - if (m_lockCount == 1) { - - // Memory mapped file; ensure data is unmapped from ram -#if defined(_WIN32) || defined(_WIN64) - if (m_hPackFile != INVALID_HANDLE_VALUE) { -#elif defined(__APPLE__) || defined(ANDROID) - if (m_fdPackFile) { -#else -#error Undefined -#endif - if (m_data_size < KRENGINE_MIN_MMAP) { - free(m_data); - m_data = NULL; - } else { - //fprintf(stderr, "Block::unlock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); -#if defined(_WIN32) || defined(_WIN64) - if (m_mmapData != NULL) { - UnmapViewOfFile(m_mmapData); - } - if (m_hFileMapping != NULL) { - CloseHandle(m_hFileMapping); - m_hFileMapping = NULL; - } -#elif defined(__APPLE__) || defined(ANDROID) - munmap(m_mmapData, m_data_size); -#else -#error Undefined -#endif - m_data = NULL; - m_mmapData = NULL; - m_mapCount--; - m_mapSize -= m_data_size; - size_t alignment_offset = m_data_offset & (KRContext::KRENGINE_SYS_ALLOCATION_GRANULARITY - 1); - m_mapOverhead -= alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; - // fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); - } - } - } -m_lockCount--; -} - -// Assert if not locked -void Block::assertLocked() -{ - assert(m_lockCount > 0); -} - -} // namespace mimir diff --git a/kraken/block.h b/kraken/block.h deleted file mode 100755 index 3f7a9e0..0000000 --- a/kraken/block.h +++ /dev/null @@ -1,131 +0,0 @@ -// -// block.h -// Kraken Engine -// -// Copyright 2023 Kearwood Gilbert. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// The views and conclusions contained in the software and documentation are those of the -// authors and should not be interpreted as representing official policies, either expressed -// or implied, of Kearwood Gilbert. -// - -#pragma once - -#include -#include "KREngine-common.h" - -#if defined(_WIN32) || defined(_WIN64) -#include -#endif - -namespace mimir { -class Block -{ -public: - Block(); - Block(void* data, size_t size); - ~Block(); - - // Encapsulate a pointer. Note - The pointer will not be free'ed - bool load(void* data, size_t size); - - // Load a file into memory using mmap. The data pointer will be protected as read-only until append() or expand() is called - bool load(const std::string& path); - - // Save the data to a file. - bool save(const std::string& path); - - // Create a Block encapsulating a sub-region of this block. The caller is responsible to free the object. - Block* getSubBlock(int start, int length); - - // Append data to the end of the block, increasing the size of the block and making it read-write. - void append(void* data, size_t size); - - // Append data to the end of the block, increasing the size of the block and making it read-write. - void append(Block& data); - - // Append string to the end of the block, increasing the size of the block and making it read-write. The null terminating character is included - void append(const std::string& s); - - // Expand or shrink the data block, and switch it to read-write mode. Note - this may result in a mmap'ed file being copied to malloc'ed ram and then closed - void expand(size_t size); - - // Unload a file, releasing any mmap'ed file handles or malloc'ed ram that was in use - void unload(); - - // Return a pointer to the start of the data block - void* getStart(); - - // Return a pointer to the one byte after the end of the data block - void* getEnd(); - - // Return the size of the data block. Use append() or expand() to make the data block larger - size_t getSize() const; - - // Get the contents as a string - std::string getString(); - - // Copy the entire data block to the destination pointer - void copy(void* dest); - - // Copy a range of data to the destination pointer - void copy(void* dest, int start, int count); - - // Lock the memory, forcing it to be loaded into a contiguous block of address space - void lock(); - - // Unlock the memory, releasing the address space for use by other allocations - void unlock(); - -private: - void* m_data; - size_t m_data_size; - size_t m_data_offset; - - // For memory mapped objects: -#if defined(_WIN32) || defined(_WIN64) - HANDLE m_hPackFile; - HANDLE m_hFileMapping; -#elif defined(__APPLE__) || defined(ANDROID) - int m_fdPackFile; -#endif - - std::string m_fileName; - Block* m_fileOwnerDataBlock; - void* m_mmapData; - - // For malloc'ed objects: - bool m_bMalloced; - - // Lock refcount - int m_lockCount; - - // Read-only allocation - bool m_bReadOnly; - - // Assert if not locked - void assertLocked(); - -}; -} // namespace mimir - diff --git a/mimir b/mimir new file mode 160000 index 0000000..ac12ba1 --- /dev/null +++ b/mimir @@ -0,0 +1 @@ +Subproject commit ac12ba1d0e9f72ac8fe0df49afd071a3f2692f98