memmappedfile-fix (#115)
Co-authored-by: Metehan Tuncbilek <mtuncbilek95@gmail.com> Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com> Co-authored-by: mtuncbilek <metehan.tuncbilek@madvoxel.com> Co-committed-by: mtuncbilek <metehan.tuncbilek@madvoxel.com>
This commit is contained in:
7
3rdParty/tinyusdz/CMakeLists.txt
vendored
7
3rdParty/tinyusdz/CMakeLists.txt
vendored
@@ -18,6 +18,13 @@ FetchContent_Declare(
|
|||||||
-DTINYUSDZ_BUILD_TESTS:BOOL=OFF
|
-DTINYUSDZ_BUILD_TESTS:BOOL=OFF
|
||||||
-DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF
|
-DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(TINYUSDZ_NO_WERROR ON)
|
||||||
|
set(TINYUSDZ_BUILD_TESTS OFF)
|
||||||
|
set(TINYUSDZ_BUILD_BENCHMARKS OFF)
|
||||||
|
set(TINYUSDZ_BUILD_EXAMPLES OFF)
|
||||||
|
set(TINYUSDZ_WITH_BUILTIN_IMAGE_LOADER OFF)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(tinyusdz)
|
FetchContent_MakeAvailable(tinyusdz)
|
||||||
|
|
||||||
function (LinkTinyUSDZ TARGET)
|
function (LinkTinyUSDZ TARGET)
|
||||||
|
|||||||
45
openVulkanoCpp/Host/Windows/ErrorUtils.cpp
Normal file
45
openVulkanoCpp/Host/Windows/ErrorUtils.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ErrorUtils.hpp"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include "Windows.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
std::string ErrorUtils::GetLastErrorMessage()
|
||||||
|
{
|
||||||
|
// Get the error message ID, if any.
|
||||||
|
DWORD errorID = GetLastError();
|
||||||
|
if (errorID == 0)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
LPSTR messageBuffer = nullptr;
|
||||||
|
// Format the error message
|
||||||
|
uint64_t size =
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, errorID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
|
||||||
|
|
||||||
|
// Buffer it up
|
||||||
|
std::string message(messageBuffer, size);
|
||||||
|
|
||||||
|
// Free the buffer and return the message
|
||||||
|
LocalFree(messageBuffer);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::string ErrorUtils::GetLastErrorMessage()
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
18
openVulkanoCpp/Host/Windows/ErrorUtils.hpp
Normal file
18
openVulkanoCpp/Host/Windows/ErrorUtils.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
class ErrorUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string GetLastErrorMessage();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,121 +6,15 @@
|
|||||||
|
|
||||||
#include "MemMappedFile.hpp"
|
#include "MemMappedFile.hpp"
|
||||||
#include "Base/Logger.hpp"
|
#include "Base/Logger.hpp"
|
||||||
#ifdef _MSC_VER
|
#include "MemMappedFileInternal.hpp"
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace OpenVulkano
|
namespace OpenVulkano
|
||||||
{
|
{
|
||||||
class MemMappedFile::Internal final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void* address = nullptr;
|
|
||||||
size_t size = 0;
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
HANDLE fileHandle;
|
|
||||||
HANDLE fileMappingHandle;
|
|
||||||
|
|
||||||
Internal(const char* file, FileMode fileMode)
|
|
||||||
{ //TODO handle other file modes than read
|
|
||||||
fileHandle = CreateFile(
|
|
||||||
TEXT(file), // file to open
|
|
||||||
GENERIC_READ, // open for reading
|
|
||||||
0, // do not share
|
|
||||||
NULL, // default security
|
|
||||||
OPEN_EXISTING, // existing file only
|
|
||||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
|
||||||
NULL); // no attribute template
|
|
||||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to open file: {}", file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LARGE_INTEGER fileSize;
|
|
||||||
if (!GetFileSizeEx(fileHandle, &fileSize))
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to get size of file: {}", file);
|
|
||||||
CloseHandle(fileHandle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size = fileSize.QuadPart;
|
|
||||||
|
|
||||||
fileMappingHandle = CreateFileMapping(
|
|
||||||
fileHandle,
|
|
||||||
NULL, // default security
|
|
||||||
PAGE_READONLY, // read-only access
|
|
||||||
0, // maximum object size (high-order)
|
|
||||||
0, // maximum object size (low-order)
|
|
||||||
NULL); // name of the mapping object
|
|
||||||
if (fileMappingHandle == 0)
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to create file mapping handle: {}", file);
|
|
||||||
CloseHandle(fileHandle);
|
|
||||||
size = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
address = MapViewOfFile(
|
|
||||||
fileMappingHandle, // handle to the map object
|
|
||||||
FILE_MAP_READ, // read access
|
|
||||||
0, // max. object size
|
|
||||||
0, // size of the hFile
|
|
||||||
0); // map the entire file
|
|
||||||
|
|
||||||
if (address == nullptr)
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to create file mapping: {}", file);
|
|
||||||
CloseHandle(fileMappingHandle);
|
|
||||||
CloseHandle(fileHandle);
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Internal()
|
|
||||||
{
|
|
||||||
UnmapViewOfFile(address);
|
|
||||||
CloseHandle(fileMappingHandle);
|
|
||||||
CloseHandle(fileHandle);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int fileHandle;
|
|
||||||
struct stat fileStat;
|
|
||||||
|
|
||||||
Internal(const char* file, FileMode fileMode)
|
|
||||||
{
|
|
||||||
fileHandle = open(file, fileMode);
|
|
||||||
if (fstat(fileHandle, &fileStat) == -1)
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_PRIVATE, fileHandle, 0);
|
|
||||||
if (address == MAP_FAILED)
|
|
||||||
{
|
|
||||||
Logger::FILESYS->critical("Failed to memory map file: {}", file);
|
|
||||||
address = nullptr;
|
|
||||||
}
|
|
||||||
size = fileStat.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Internal()
|
|
||||||
{
|
|
||||||
munmap(address, fileStat.st_size);
|
|
||||||
close(fileHandle);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
MemMappedFile::MemMappedFile(const std::filesystem::path& path, FileMode fileMode)
|
MemMappedFile::MemMappedFile(const std::filesystem::path& path, FileMode fileMode)
|
||||||
|
: m_data(nullptr), m_size(0)
|
||||||
{
|
{
|
||||||
m_internal = std::make_shared<Internal>(path.string().c_str(), fileMode);
|
std::string file = path.string();
|
||||||
|
m_internal = std::make_shared<MemMappedFileInternal>(file.c_str(), fileMode);
|
||||||
m_data = m_internal->address;
|
m_data = m_internal->address;
|
||||||
m_size = (m_data) ? m_internal->size : 0;
|
m_size = (m_data) ? m_internal->size : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,16 +10,22 @@
|
|||||||
|
|
||||||
namespace OpenVulkano
|
namespace OpenVulkano
|
||||||
{
|
{
|
||||||
|
class MemMappedFileInternal;
|
||||||
class MemMappedFile
|
class MemMappedFile
|
||||||
{
|
{
|
||||||
class Internal;
|
friend class MemMappedFileWriteHelper;
|
||||||
|
|
||||||
std::shared_ptr<Internal> m_internal;
|
std::shared_ptr<MemMappedFileInternal> m_internal;
|
||||||
void* m_data;
|
void* m_data;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum FileMode : int { READ_ONLY = 0, WRITE_ONLY, READ_WRITE };
|
enum FileMode : int
|
||||||
|
{
|
||||||
|
READ_ONLY = 0,
|
||||||
|
WRITE_ONLY,
|
||||||
|
READ_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
MemMappedFile(const std::filesystem::path& path, FileMode fileMode = READ_ONLY);
|
MemMappedFile(const std::filesystem::path& path, FileMode fileMode = READ_ONLY);
|
||||||
|
|
||||||
|
|||||||
125
openVulkanoCpp/IO/MemMappedFileInternal.cpp
Normal file
125
openVulkanoCpp/IO/MemMappedFileInternal.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MemMappedFileInternal.hpp"
|
||||||
|
|
||||||
|
#include "Base/Logger.hpp"
|
||||||
|
#include "Host/Windows/ErrorUtils.hpp"
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
|
||||||
|
: size(0), fileHandle(nullptr), fileMappingHandle(nullptr)
|
||||||
|
{
|
||||||
|
DWORD openMode { 0 }, mapMode { 0 }, viewMode { 0 };
|
||||||
|
|
||||||
|
switch (fileMode)
|
||||||
|
{
|
||||||
|
case MemMappedFile::FileMode::READ_ONLY:
|
||||||
|
openMode = GENERIC_READ;
|
||||||
|
mapMode = PAGE_READONLY;
|
||||||
|
viewMode = FILE_MAP_READ;
|
||||||
|
break;
|
||||||
|
case MemMappedFile::FileMode::WRITE_ONLY:
|
||||||
|
openMode = GENERIC_WRITE;
|
||||||
|
mapMode = PAGE_READWRITE;
|
||||||
|
viewMode = FILE_MAP_WRITE;
|
||||||
|
break;
|
||||||
|
case MemMappedFile::FileMode::READ_WRITE:
|
||||||
|
openMode = GENERIC_ALL;
|
||||||
|
mapMode = PAGE_READWRITE;
|
||||||
|
viewMode = FILE_MAP_ALL_ACCESS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileHandle = CreateFileA(file, // file to open
|
||||||
|
openMode, // open for switch case
|
||||||
|
NULL, // share mode
|
||||||
|
NULL, // default security
|
||||||
|
OPEN_ALWAYS, // always
|
||||||
|
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||||
|
NULL); // no attribute template
|
||||||
|
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to open file: {}.", ErrorUtils::GetLastErrorMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER fileSize;
|
||||||
|
if (!GetFileSizeEx(fileHandle, &fileSize))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to get size of file: {}", ErrorUtils::GetLastErrorMessage());
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size = fileSize.QuadPart;
|
||||||
|
|
||||||
|
fileMappingHandle = CreateFileMappingA(fileHandle,
|
||||||
|
NULL, // default security
|
||||||
|
mapMode, // mod for switch case
|
||||||
|
0, // maximum object size (high-order)
|
||||||
|
0, // maximum object size (low-order)
|
||||||
|
NULL); // name of the mapping object
|
||||||
|
if (fileMappingHandle == INVALID_HANDLE_VALUE || fileMappingHandle == NULL)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to create file mapping handle: {}", ErrorUtils::GetLastErrorMessage());
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = MapViewOfFile(fileMappingHandle, // handle to the map object
|
||||||
|
viewMode, // access for switch case
|
||||||
|
0, // max. object size
|
||||||
|
0, // size of the hFile
|
||||||
|
0); // map the entire file
|
||||||
|
|
||||||
|
if (address == nullptr)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to create file mapping: {}", ErrorUtils::GetLastErrorMessage());
|
||||||
|
CloseHandle(fileMappingHandle);
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileInternal::~MemMappedFileInternal()
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(address);
|
||||||
|
CloseHandle(fileMappingHandle);
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
|
||||||
|
{
|
||||||
|
fileHandle = open(file, fileMode);
|
||||||
|
if (fstat(fileHandle, &fileStat) == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_SHARED, fileHandle, 0);
|
||||||
|
if (address == MAP_FAILED)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to memory map file: {}", file);
|
||||||
|
address = nullptr;
|
||||||
|
}
|
||||||
|
size = fileStat.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileInternal::~MemMappedFileInternal()
|
||||||
|
{
|
||||||
|
munmap(address, fileStat.st_size);
|
||||||
|
close(fileHandle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
50
openVulkanoCpp/IO/MemMappedFileInternal.hpp
Normal file
50
openVulkanoCpp/IO/MemMappedFileInternal.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MemMappedFile.hpp"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
class MemMappedFileInternal
|
||||||
|
{
|
||||||
|
friend class MemMappedFileWriteHelper;
|
||||||
|
friend class MemMappedFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode);
|
||||||
|
~MemMappedFileInternal();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
bool InvalidHandle() const { return fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL; }
|
||||||
|
#else
|
||||||
|
[[nodiscard]] bool InvalidHandle() const { return fileHandle == -1; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* address = nullptr;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
HANDLE fileHandle;
|
||||||
|
HANDLE fileMappingHandle;
|
||||||
|
#else
|
||||||
|
int fileHandle;
|
||||||
|
struct stat fileStat;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
367
openVulkanoCpp/IO/MemMappedFileWriteHelper.cpp
Normal file
367
openVulkanoCpp/IO/MemMappedFileWriteHelper.cpp
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MemMappedFileWriteHelper.hpp"
|
||||||
|
|
||||||
|
#include "MemMappedFile.hpp"
|
||||||
|
#include "MemMappedFileInternal.hpp"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Host/Windows/ErrorUtils.hpp>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Base/Logger.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
|
||||||
|
: m_path(path), m_file(nullptr)
|
||||||
|
{
|
||||||
|
// Check if file exists, so we can open it in the correct mode
|
||||||
|
DWORD openMode = CREATE_ALWAYS;
|
||||||
|
if (std::filesystem::exists(path))
|
||||||
|
{
|
||||||
|
openMode = OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the file
|
||||||
|
HANDLE fileHandle =
|
||||||
|
CreateFileA(path.string().c_str(), GENERIC_ALL, FILE_SHARE_WRITE, NULL, openMode, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control the file size
|
||||||
|
LARGE_INTEGER currentSize {};
|
||||||
|
if (fileHandle)
|
||||||
|
{
|
||||||
|
if (!GetFileSizeEx(fileHandle, ¤tSize))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSize.QuadPart <= 0 && maxFileSize == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Either the file size has to be greater than 0 or Initial Size!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the file size
|
||||||
|
if (maxFileSize > 0)
|
||||||
|
{
|
||||||
|
if (fileHandle)
|
||||||
|
{
|
||||||
|
// Set the file size
|
||||||
|
if (!SetFilePointer(fileHandle, DWORD(maxFileSize), NULL, FILE_BEGIN))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetEndOfFile(fileHandle))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileHandle)
|
||||||
|
{
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_file = new MemMappedFile(path.string().c_str(), MemMappedFile::FileMode::READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
|
||||||
|
|
||||||
|
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
|
||||||
|
{
|
||||||
|
if (newSize == 0)
|
||||||
|
{
|
||||||
|
// Handle the case where the new size is zero
|
||||||
|
Logger::FILESYS->critical("New size is zero.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current file handle
|
||||||
|
if (m_file->m_internal->fileHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Invalid file handle.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap the old view of the file and close the file mapping handle
|
||||||
|
if (!(m_file->m_internal->fileMappingHandle == NULL)
|
||||||
|
&& !(m_file->m_internal->fileMappingHandle == INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(m_file->m_internal->address);
|
||||||
|
CloseHandle(m_file->m_internal->fileMappingHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the file
|
||||||
|
if (!SetFilePointer(m_file->m_internal->fileHandle, static_cast<DWORD>(newSize), NULL, FILE_BEGIN))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to set file pointer. Reason: {}", GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetEndOfFile(m_file->m_internal->fileHandle))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to set end of file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new file mapping handle
|
||||||
|
m_file->m_internal->fileMappingHandle =
|
||||||
|
CreateFileMappingW(m_file->m_internal->fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||||
|
if (m_file->m_internal->fileMappingHandle == NULL)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to create file mapping.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the file to a new view
|
||||||
|
m_file->m_internal->address =
|
||||||
|
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
|
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to map view of file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
|
||||||
|
{
|
||||||
|
HANDLE fileHandle {};
|
||||||
|
if (m_file->m_internal->InvalidHandle())
|
||||||
|
{
|
||||||
|
auto file = m_path.string();
|
||||||
|
fileHandle = CreateFileA(file.c_str(), // file to open
|
||||||
|
GENERIC_WRITE, // open for reading
|
||||||
|
0, // do not share
|
||||||
|
NULL, // default security
|
||||||
|
CREATE_ALWAYS, // existing file only
|
||||||
|
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||||
|
NULL); // no attribute template
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileHandle = m_file->m_internal->fileHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file)
|
||||||
|
{
|
||||||
|
if (!UnmapViewOfFile(m_file->m_internal->address))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to unmap view of file on trim.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CloseHandle(m_file->m_internal->fileMappingHandle))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to close file mapping handle.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER liSize;
|
||||||
|
liSize.QuadPart = finalFileSize;
|
||||||
|
if (!SetFilePointerEx(fileHandle, liSize, NULL, FILE_BEGIN) || !SetEndOfFile(fileHandle))
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to trim file: {}", ErrorUtils::GetLastErrorMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new file mapping handle
|
||||||
|
if (m_file)
|
||||||
|
{
|
||||||
|
m_file->m_internal->fileMappingHandle = CreateFileMappingW(fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||||
|
if (m_file->m_internal->fileMappingHandle == NULL)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to create file mapping.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the file to a new view
|
||||||
|
m_file->m_internal->address =
|
||||||
|
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
|
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to map view of file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file)
|
||||||
|
{
|
||||||
|
m_file->m_size = finalFileSize;
|
||||||
|
m_file->m_internal->size = finalFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
|
||||||
|
{
|
||||||
|
const auto file = path.string();
|
||||||
|
const int fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||||
|
if (fileHandle == -1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to open file: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat fileStat
|
||||||
|
{
|
||||||
|
};
|
||||||
|
if (fstat(fileHandle, &fileStat) == -1)
|
||||||
|
{
|
||||||
|
close(fileHandle);
|
||||||
|
throw std::runtime_error("Failed to get file size: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const size_t fileSize = fileStat.st_size; fileSize < maxFileSize)
|
||||||
|
{
|
||||||
|
if (ftruncate(fileHandle, maxFileSize) == -1)
|
||||||
|
{
|
||||||
|
close(fileHandle);
|
||||||
|
throw std::runtime_error("Failed to resize file: " + file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fileHandle);
|
||||||
|
m_file = new MemMappedFile(file.c_str(), MemMappedFile::FileMode::READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
|
||||||
|
|
||||||
|
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
|
||||||
|
{
|
||||||
|
if (newSize == 0)
|
||||||
|
{
|
||||||
|
// Handle the case where the new size is zero
|
||||||
|
Logger::FILESYS->error("New size is zero. New size must be greater than zero.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current file handle
|
||||||
|
if (m_file->m_internal->fileHandle == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Invalid file handle.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the file
|
||||||
|
if (ftruncate(m_file->m_internal->fileHandle, newSize) == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to resize file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap the old view and map a new view of the resized file
|
||||||
|
if (m_file->m_internal->address != nullptr)
|
||||||
|
{
|
||||||
|
if (munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to unmap view of file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the file to a new view
|
||||||
|
m_file->m_internal->address =
|
||||||
|
mmap(nullptr, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_file->m_internal->fileHandle, 0);
|
||||||
|
if (m_file->m_internal->address == MAP_FAILED)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to map file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the size of the file
|
||||||
|
m_file->m_internal->size = newSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
|
||||||
|
{
|
||||||
|
// If getting handle returns invalid file recreate the file
|
||||||
|
if (m_file->m_internal->InvalidHandle())
|
||||||
|
{
|
||||||
|
const auto file = m_path.string();
|
||||||
|
m_file->m_internal->fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap the old view of the file
|
||||||
|
if(munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to unmap address.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim the file
|
||||||
|
if (ftruncate(m_file->m_internal->fileHandle, finalFileSize) == -1)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to trim file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap the file with the new size
|
||||||
|
m_file->m_internal->address = mmap(nullptr, finalFileSize, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||||
|
m_file->m_internal->fileHandle, 0);
|
||||||
|
if (m_file->m_internal->address == MAP_FAILED)
|
||||||
|
{
|
||||||
|
Logger::FILESYS->critical("Failed to map file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the size in MemMappedFile structure
|
||||||
|
m_file->m_size = finalFileSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MemMappedFileWriteHelper::Close()
|
||||||
|
{
|
||||||
|
if (m_file->IsOpen())
|
||||||
|
{
|
||||||
|
delete m_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileWriter::MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize)
|
||||||
|
: m_helper(MemMappedFileWriteHelper(path, maxFileSize))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemMappedFileWriter::~MemMappedFileWriter() { m_helper.Close(); }
|
||||||
|
|
||||||
|
void MemMappedFileWriter::Write(const char* data, const size_t size)
|
||||||
|
{
|
||||||
|
// If the new size is greater than the current size, resize the file
|
||||||
|
if (m_writtenSize + size > m_helper.Size())
|
||||||
|
{
|
||||||
|
m_helper.Resize(m_writtenSize + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to the end of the file
|
||||||
|
memcpy(static_cast<char*>(m_helper.Data()) + m_writtenSize, data, size);
|
||||||
|
m_writtenSize += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
openVulkanoCpp/IO/MemMappedFileWriteHelper.hpp
Normal file
48
openVulkanoCpp/IO/MemMappedFileWriteHelper.hpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IO/MemMappedFile.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace OpenVulkano
|
||||||
|
{
|
||||||
|
class MemMappedFileWriteHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize);
|
||||||
|
~MemMappedFileWriteHelper();
|
||||||
|
|
||||||
|
[[nodiscard]] void* Data() const { return m_file->Data(); }
|
||||||
|
[[nodiscard]] size_t Size() const { return m_file->Size(); }
|
||||||
|
|
||||||
|
bool Resize(size_t newSize);
|
||||||
|
void Close();
|
||||||
|
bool Trim(size_t finalFileSize);
|
||||||
|
|
||||||
|
static constexpr size_t USE_CURRENT_FILE_SIZE = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemMappedFile* m_file;
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemMappedFileWriter final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize);
|
||||||
|
~MemMappedFileWriter();
|
||||||
|
|
||||||
|
void Write(const char* data, size_t size);
|
||||||
|
void SetOffset(size_t offset) { m_writtenSize = offset; }
|
||||||
|
[[nodiscard]] size_t GetOffset() const { return m_writtenSize; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemMappedFileWriteHelper m_helper;
|
||||||
|
size_t m_writtenSize = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base/Wrapper.hpp"
|
||||||
#include "Math/Math.hpp"
|
#include "Math/Math.hpp"
|
||||||
#include "Image/Image.hpp"
|
#include "Image/Image.hpp"
|
||||||
#include "Scene/Texture.hpp"
|
#include "Scene/Texture.hpp"
|
||||||
@@ -56,7 +57,7 @@ namespace OpenVulkano::Scene
|
|||||||
{
|
{
|
||||||
std::map<uint32_t, GlyphInfo> glyphs;
|
std::map<uint32_t, GlyphInfo> glyphs;
|
||||||
AtlasMetadata meta;
|
AtlasMetadata meta;
|
||||||
std::unique_ptr<Image::Image> img;
|
Unique<Image::Image> img;
|
||||||
Texture texture;
|
Texture texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
126
tests/MemFileTests.cpp
Normal file
126
tests/MemFileTests.cpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include <catch2/catch_all.hpp>
|
||||||
|
|
||||||
|
#include "IO/MemMappedFile.hpp"
|
||||||
|
#include "IO/MemMappedFileWriteHelper.hpp"
|
||||||
|
#include "IO/AppFolders.hpp"
|
||||||
|
#include "Base/Logger.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
TEST_CASE("MemMappedFileWrite")
|
||||||
|
{
|
||||||
|
OpenVulkano::Logger::SetupLogger("", "tests.log");
|
||||||
|
|
||||||
|
auto path = OpenVulkano::AppFolders::GetAppTempDir();
|
||||||
|
path += "/MemFileTest.txt";
|
||||||
|
|
||||||
|
std::string data = "Hello World X\n"
|
||||||
|
"Hello World Y\n"
|
||||||
|
"Hello World Z\n"
|
||||||
|
"Hello World W\n"
|
||||||
|
"Hello World A\n"
|
||||||
|
"Hello World B\n"
|
||||||
|
"Hello World C\n"
|
||||||
|
"Hello World D\n"
|
||||||
|
"Hello World E\n"
|
||||||
|
"Hello World F\n"
|
||||||
|
"Hello World G\n"
|
||||||
|
"Hello World H\n"
|
||||||
|
"Hello World I\n"
|
||||||
|
"Hello World J\n"
|
||||||
|
"Hello World K\n"
|
||||||
|
"Hello World L\n"
|
||||||
|
"Hello World M\n"
|
||||||
|
"Hello World N\n";
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("Write to MemMappedFile")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFileWriter writer(path, 1024);
|
||||||
|
writer.Write(data.data(), data.size());
|
||||||
|
|
||||||
|
REQUIRE(writer.GetOffset() == data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Control Size")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFile memFile(path, OpenVulkano::MemMappedFile::READ_ONLY);
|
||||||
|
REQUIRE(memFile.Size() == 1024); // The size that comes from the first Test.
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Compare String Data for per char")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFileWriteHelper memFileHelper(path, OpenVulkano::MemMappedFile::READ_ONLY);
|
||||||
|
REQUIRE(memFileHelper.Trim(data.size()));
|
||||||
|
|
||||||
|
std::string testData((char*) memFileHelper.Data());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data.size(); i++)
|
||||||
|
{
|
||||||
|
if (data[i] != testData[i])
|
||||||
|
{
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memFileHelper.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Trim File")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFileWriteHelper helper(path,
|
||||||
|
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||||
|
REQUIRE(helper.Trim(100));
|
||||||
|
REQUIRE(helper.Size() == 100);
|
||||||
|
|
||||||
|
helper.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Write Data 2")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFileWriter writer(path, OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||||
|
writer.Write(data.data(), data.size());
|
||||||
|
writer.Write(data.data(), data.size());
|
||||||
|
writer.Write(data.data(), data.size());
|
||||||
|
|
||||||
|
REQUIRE(writer.GetOffset() == data.size() * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Compare Data")
|
||||||
|
{
|
||||||
|
OpenVulkano::MemMappedFileWriteHelper helper(path,
|
||||||
|
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||||
|
REQUIRE(helper.Data() != nullptr);
|
||||||
|
std::string testData((char*) helper.Data());
|
||||||
|
printf("size: %llu", helper.Size());
|
||||||
|
helper.Close();
|
||||||
|
|
||||||
|
std::ifstream file(path, std::ios::binary);
|
||||||
|
std::string streamData;
|
||||||
|
std::getline(file, streamData, '\0');
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < testData.size(); i++)
|
||||||
|
{
|
||||||
|
if (streamData[i] != testData[i])
|
||||||
|
{
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(streamData.size() == testData.size());
|
||||||
|
|
||||||
|
printf("helper size: %llu\n", helper.Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Actual Size")
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
std::uintmax_t size = fs::file_size(path, ec);
|
||||||
|
|
||||||
|
REQUIRE(size == 756);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user