Skip to content

Commit

Permalink
Merge branch 'mmap-file-io'
Browse files Browse the repository at this point in the history
  • Loading branch information
Dextinfire committed Nov 27, 2024
2 parents 53d768f + b315bfd commit af63ec4
Show file tree
Hide file tree
Showing 9 changed files with 1,966 additions and 18 deletions.
14 changes: 13 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,10 @@ set(Impacto_Header

vendor/squish/squish.h


vendor/vma/vk_mem_alloc.h
vendor/minilua/minilua.h
)
)

if (WIN32)
list(APPEND Impacto_Src
Expand All @@ -634,6 +635,7 @@ endif ()
if (NX OR EMSCRIPTEN)
set(IMPACTO_DISABLE_VULKAN ON)
set(IMPACTO_DISABLE_DX9 ON)
set(IMPACTO_DISABLE_MMAP ON)
endif ()

if(ANDROID)
Expand Down Expand Up @@ -712,6 +714,16 @@ FetchContent_MakeAvailable(fmt)
FetchContent_MakeAvailable(pugixml)
FetchContent_MakeAvailable(utf8cpp)

if (NOT DEFINED IMPACTO_DISABLE_MMAP)
list(APPEND Impacto_Src
src/io/memorymappedfilestream.cpp
)
list(APPEND Impacto_Header
src/io/memorymappedfilestream.h
vendor/mio/mio.hpp
)
endif ()

if (NOT DEFINED IMPACTO_DISABLE_IMGUI)
FetchContent_Declare(
ImGui
Expand Down
9 changes: 9 additions & 0 deletions THIRDPARTY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* `vendor/mspack`: [libmspack](https://www.cabextract.org.uk/libmspack/), only includes LZX decompressor to reduce code size
* `vendor/pugixml`: [pugixml](https://github.com/zeux/pugixml)
* `vendor/span`: [span](https://github.com/tcbrindle/span)
* `vendor/mio`: [mio](https://github.com/vimpunk/mio)

All third-party code mentioned above is mandatory, included in the build process and compiled into the output executable for impacto on every supported platform and build configuration.

Expand Down Expand Up @@ -796,6 +797,14 @@ https://github.com/tcbrindle/span

Distributed under the Boost Software License - Version 1.0 - August 17th, 2003. See below for license text.

## mio

https://github.com/vimpunk/mio/blob/master/single_include/mio/mio.hpp

Copyright (c) 2018 https://github.com/mandreyel/

See below for license text (MIT).

## stb_image

https://github.com/nothings/stb/blob/5d90a8375a1393abc0dc5f8cc9f1ac9fd9ae6530/stb_image.h
Expand Down
18 changes: 4 additions & 14 deletions doc/ubuntu1804_build.md → doc/ubuntu_build.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Build instructions based on Ubuntu 18.04 LTS
# Build instructions based on Ubuntu 20.04 LTS

You can use the following shell script for getting dependencies and setting up first time build on Ubuntu 18.04 LTS.
You can use the following shell script for getting dependencies and setting up first time build on Ubuntu 20.04 LTS.

```shell
# Build instructions based on Ubuntu 18.04 LTS
# Build instructions based on Ubuntu 20.04 LTS

# Install required programs and dependencies
# Also install libglm-dev if the glm version provided by your distro is 0.9.9.3 or higher
sudo apt-get -y install git cmake libsdl2-dev libopenal-dev libogg-dev libvorbis-dev zlib1g-dev
sudo apt-get -y install git cmake libsdl2-dev libopenal-dev libogg-dev libvorbis-dev zlib1g-dev libavcodec-dev libavformat-dev libavfilter-dev libvulkan-dev libwebp-dev nasm libglm-dev libglm-dev

# Clone impacto
git clone https://github.com/CommitteeOfZero/impacto.git
Expand All @@ -23,15 +22,6 @@ cp bin/libatrac9.a ../libs/
cp src/libatrac9.h ../include/libatrac9/
popd

# Build glm
# This step can be ommited if you have installed glm as a system dependency.
pushd vendor
git clone -b "0.9.9.3" https://github.com/g-truc/glm.git --depth 1
cd glm
cmake .
make
popd

# Executable expects the shaders dir to be nearby
cp -r src/shaders .

Expand Down
3 changes: 2 additions & 1 deletion src/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
#cmakedefine IMPACTO_DISABLE_FFMPEG
#cmakedefine IMPACTO_DISABLE_OPENAL
#cmakedefine IMPACTO_DISABLE_MSPACK
#cmakedefine IMPACTO_DISABLE_IMGUI
#cmakedefine IMPACTO_DISABLE_IMGUI
#cmakedefine IMPACTO_DISABLE_MMAP
104 changes: 104 additions & 0 deletions src/io/memorymappedfilestream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "memorymappedfilestream.h"
#include "../log.h"

#include <cstring>
#include <algorithm>
#include <system_error>

namespace Impacto {
namespace Io {
template <AccessMode M>
IoError MemoryMappedFileStream<M>::Create(std::string const& fileName,
Stream** out) {
MemoryMappedFileStream* result =
new MemoryMappedFileStream(GetSystemDependentPath(fileName));
result->Meta.Size = GetFileSize(result->SourceFileName);
if (result->Meta.Size == IoError_Fail) {
delete result;
return IoError_Fail;
}

std::error_code ec;
result->mmapFile.map(result->SourceFileName, 0, result->Meta.Size, ec);
if (ec) {
ImpLog(LL_Error, LC_IO, "Failed to open file \"%s\", error:\"%s\"\n",
result->SourceFileName.c_str(), ec.message().c_str());
delete result;
return ec == std::errc::no_such_file_or_directory ? IoError_Eof
: IoError_Fail;
}
*out = (Stream*)result;
return IoError_OK;
}

template <AccessMode M>
int64_t MemoryMappedFileStream<M>::Read(void* buffer, int64_t sz) {
if (sz < 0) return IoError_Fail;
if (Position >= Meta.Size) return IoError_Eof;

int bytesToRead = std::min(sz, Meta.Size - Position);
assert(mmapFile.data());
// Lock only if we are in read/write mode
if constexpr (M == AccessMode::write) {
std::shared_lock lock(*mutexLock); // Lock for shared read access
memcpy(buffer, mmapFile.data() + Position, bytesToRead);
} else {
memcpy(buffer, mmapFile.data() + Position, bytesToRead);
}

Position += bytesToRead;
return bytesToRead;
}

template <AccessMode M>
int64_t MemoryMappedFileStream<M>::Seek(int64_t offset, int origin) {
int64_t absPos;
switch (origin) {
case RW_SEEK_SET:
absPos = offset;
break;
case RW_SEEK_CUR:
absPos = Position + offset;
break;
case RW_SEEK_END:
absPos = Meta.Size - offset;
break;
}

if (absPos < 0 || absPos > Meta.Size) return IoError_Fail;
Position = absPos;
return Position;
}

template <AccessMode M>
IoError MemoryMappedFileStream<M>::Duplicate(Stream** outStream) {
MemoryMappedFileStream* result = new MemoryMappedFileStream(*this);
if (result->Seek(Position, RW_SEEK_SET) < 0) {
ImpLog(LL_Error, LC_IO, "Seek failed for file \"%s\"\n",
SourceFileName.c_str());
delete result;
return IoError_Fail;
}
*outStream = (Stream*)result;
return IoError_OK;
}

template <AccessMode M>
int64_t MemoryMappedFileStream<M>::Write(void* buffer, int64_t sz, int cnt) {
if constexpr (M == AccessMode::read) {
assert(false);
return 0;
} else {
std::lock_guard<std::shared_mutex> lock(*mutexLock);
sz = std::min(Meta.Size - Position, sz);
memcpy(mmapFile.data() + Position, buffer, sz);
Position += sz;
return sz;
}
}

template class MemoryMappedFileStream<AccessMode::write>;
template class MemoryMappedFileStream<AccessMode::read>;

} // namespace Io
} // namespace Impacto
46 changes: 46 additions & 0 deletions src/io/memorymappedfilestream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include "stream.h"
#include <fstream>
#include <cstddef>
#include <shared_mutex>
#include "../../vendor/mio/mio.hpp"

namespace Impacto {
namespace Io {

using AccessMode = mio::access_mode;

template <AccessMode Access>
class MemoryMappedFileStream : public Stream {
public:
AccessMode Mode = Access;
static IoError Create(std::string const& fileName, Stream** out);
int64_t Read(void* buffer, int64_t sz) override;
int64_t Seek(int64_t offset, int origin) override;
IoError Duplicate(Stream** outStream) override;
int64_t Write(void* buffer, int64_t sz, int cnt = 1) override;

protected:
MemoryMappedFileStream(std::string filePath)
: SourceFileName(std::move(filePath)) {
Meta.FileName = SourceFileName;
if constexpr (Access == AccessMode::write) {
mutexLock = std::make_shared<std::shared_mutex>();
}
}

MemoryMappedFileStream(MemoryMappedFileStream const& other)
: SourceFileName(other.SourceFileName), mmapFile(other.mmapFile) {
Meta.FileName = SourceFileName;
Meta.Size = other.Meta.Size;
if constexpr (Access == AccessMode::write) {
mutexLock = other.mutexLock;
}
}
std::string SourceFileName;
mio::basic_shared_mmap<Access, std::byte> mmapFile;
std::shared_ptr<std::shared_mutex> mutexLock;
};
} // namespace Io
} // namespace Impacto
1 change: 0 additions & 1 deletion src/io/physicalfilestream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ int64_t PhysicalFileStream::Seek(int64_t offset, int origin) {

IoError PhysicalFileStream::Duplicate(Stream** outStream) {
PhysicalFileStream* result = new PhysicalFileStream(*this);
std::error_code ec;
if (result->ErrorCode != IoError_OK) {
ImpLog(LL_Error, LC_IO, "Failed to open file \"%s\"\n",
SourceFileName.c_str());
Expand Down
11 changes: 10 additions & 1 deletion src/io/vfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
#include "../impacto.h"
#include <vector>
#include "vfsarchive.h"
#include "physicalfilestream.h"
#include "memorystream.h"
#include "../log.h"
#include "../profile/vfs.h"
#ifndef IMPACTO_DISABLE_MMAP
#include "memorymappedfilestream.h"
#else
#include "physicalfilestream.h"
#endif

#include "afsarchive.h"
#include "cpkarchive.h"
Expand Down Expand Up @@ -76,7 +80,12 @@ IoError VfsMount(std::string const& mountpoint,
}

Stream* archiveFile;
#ifndef IMPACTO_DISABLE_MMAP
err = MemoryMappedFileStream<AccessMode::read>::Create(archiveFileName,
&archiveFile);
#else
err = PhysicalFileStream::Create(archiveFileName, &archiveFile);
#endif
if (err != IoError_OK) {
ImpLog(LL_Debug, LC_IO, "Could not open physical file \"%s\"\n",
archiveFileName.c_str());
Expand Down
Loading

0 comments on commit af63ec4

Please sign in to comment.