From 77ac2bd47dee84f41810e3f1986dceb66f73ca76 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 4 Jun 2024 19:06:00 +0200 Subject: [PATCH] Add a custom buffered filebuf that uses a file descriptor Implemented for the WiiU because IO through std::filebuf appears to be unbuffered. But can maybe help on other platforms. Can be toggled by setting USE_CUSTOM_FILE_READBUF to the prefered buffer size. --- src/filesystem_native.cpp | 20 ++++++++- src/filesystem_stream.cpp | 86 +++++++++++++++++++++++++++++++++++++++ src/filesystem_stream.h | 24 +++++++++++ src/system.h | 1 + 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/filesystem_native.cpp b/src/filesystem_native.cpp index b3969f3b2c4..1ae415fcdfd 100644 --- a/src/filesystem_native.cpp +++ b/src/filesystem_native.cpp @@ -20,14 +20,21 @@ #include #include #include +#include #include #include #include +#include "filesystem_stream.h" #include "system.h" #include "output.h" #include "platform.h" +#ifdef USE_CUSTOM_FILE_READBUF +# include +# include +#endif + NativeFilesystem::NativeFilesystem(std::string base_path, FilesystemView parent_fs) : Filesystem(std::move(base_path), parent_fs) { } @@ -48,7 +55,17 @@ int64_t NativeFilesystem::GetFilesize(StringView path) const { } std::streambuf* NativeFilesystem::CreateInputStreambuffer(StringView path, std::ios_base::openmode mode) const { - auto* buf = new std::filebuf(); +#ifdef USE_CUSTOM_FILE_READBUF + (void)mode; + int fd = open(ToString(path).c_str(), O_RDONLY); + if (fd < 0) { + return nullptr; + } + + return new Filesystem_Stream::FdStreamBuf(fd); +#else + auto buf = new std::filebuf(); + buf->open( #ifdef _MSC_VER Utils::ToWideString(path), @@ -63,6 +80,7 @@ std::streambuf* NativeFilesystem::CreateInputStreambuffer(StringView path, std:: } return buf; +#endif } std::streambuf* NativeFilesystem::CreateOutputStreambuffer(StringView path, std::ios_base::openmode mode) const { diff --git a/src/filesystem_stream.cpp b/src/filesystem_stream.cpp index cadf97d4a4d..5d20a592497 100644 --- a/src/filesystem_stream.cpp +++ b/src/filesystem_stream.cpp @@ -19,6 +19,10 @@ #include +#ifdef USE_CUSTOM_FILE_READBUF +# include +#endif + Filesystem_Stream::InputStream::InputStream(std::streambuf* sb, std::string name) : std::istream(sb), name(std::move(name)) {} @@ -122,3 +126,85 @@ Filesystem_Stream::InputMemoryStreamBuf::InputMemoryStreamBuf(std::vector 0) { + auto dist = std::distance(gptr(), gptr() + offset); + if (gptr() + offset > egptr()) { + // Not cached: Outside of the buffer: Reposition the stream + file_offset = lseek(fd, dist - bytes_remaining(), SEEK_CUR); + clear_buffer(); + } else { + setg(buffer.begin(), gptr() + dist, egptr()); + } + } + return file_offset - bytes_remaining(); + } else { + // Not cached: Seek to end + clear_buffer(); + file_offset = lseek(fd, offset, SEEK_END); + + if (file_offset < 0) { + file_offset = 0; + return -1; + } + + return file_offset; + } + + assert(false); +} + +std::streambuf::pos_type Filesystem_Stream::FdStreamBuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode mode) { + return seekoff(pos, std::ios_base::beg, mode); +} + +void Filesystem_Stream::FdStreamBuf::clear_buffer() { + setg(buffer.begin(), buffer.end(), buffer.end()); +} + +ssize_t Filesystem_Stream::FdStreamBuf::bytes_remaining() const { + return egptr() - gptr(); +} + +#endif diff --git a/src/filesystem_stream.h b/src/filesystem_stream.h index 4a0d76bc7dc..2114f938172 100644 --- a/src/filesystem_stream.h +++ b/src/filesystem_stream.h @@ -24,6 +24,7 @@ #include #include "filesystem.h" #include "utils.h" +#include "system.h" namespace Filesystem_Stream { class InputStream final : public std::istream { @@ -96,6 +97,29 @@ namespace Filesystem_Stream { std::vector buffer; }; +#ifdef USE_CUSTOM_FILE_READBUF + class FdStreamBuf : public std::streambuf { + public: + FdStreamBuf(int fd); + FdStreamBuf(FdStreamBuf const& other) = delete; + FdStreamBuf const& operator=(FdStreamBuf const& other) = delete; + ~FdStreamBuf(); + + protected: + int_type underflow(); + std::streambuf::pos_type seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir, std::ios_base::openmode mode); + std::streambuf::pos_type seekpos(std::streambuf::pos_type pos, std::ios_base::openmode); + + private: + void clear_buffer(); + ssize_t bytes_remaining() const; + + int fd; + off_t file_offset = 0; + std::array buffer; + }; +#endif + static constexpr std::ios_base::seekdir CSeekdirToCppSeekdir(int origin); static constexpr int CppSeekdirToCSeekdir(std::ios_base::seekdir origin); diff --git a/src/system.h b/src/system.h index 74b8d0b12c0..74c2ba5c9ed 100644 --- a/src/system.h +++ b/src/system.h @@ -71,6 +71,7 @@ # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS # define SUPPORT_TOUCH +# define USE_CUSTOM_FILE_READBUF 16 * 1024 #elif defined(_WIN32) # define SUPPORT_ZOOM # define SUPPORT_MOUSE