From 5b177db5515fba44f9f38824d3e4e5b6ce17b63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 19 Aug 2024 23:50:21 +0300 Subject: [PATCH 1/3] Remove the decode functions from SawyerChunkReader.h, re-order in cpp --- src/openrct2/rct12/SawyerChunkReader.cpp | 68 ++++++++++++------------ src/openrct2/rct12/SawyerChunkReader.h | 7 --- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/openrct2/rct12/SawyerChunkReader.cpp b/src/openrct2/rct12/SawyerChunkReader.cpp index d654ea5777..9946b23765 100644 --- a/src/openrct2/rct12/SawyerChunkReader.cpp +++ b/src/openrct2/rct12/SawyerChunkReader.cpp @@ -33,6 +33,8 @@ constexpr const char* EXCEPTION_MSG_DESTINATION_TOO_SMALL = "Chunk data larger t constexpr const char* EXCEPTION_MSG_INVALID_CHUNK_ENCODING = "Invalid chunk encoding."; constexpr const char* EXCEPTION_MSG_ZERO_SIZED_CHUNK = "Encountered zero-sized chunk."; +static std::vector DecodeChunk(const void* src, const SawyerCodingChunkHeader& header); + SawyerChunkReader::SawyerChunkReader(OpenRCT2::IStream* stream) : _stream(stream) { @@ -151,37 +153,7 @@ void SawyerChunkReader::ReadChunk(void* dst, size_t length) } } -std::vector SawyerChunkReader::DecodeChunk(const void* src, const SawyerCodingChunkHeader& header) -{ - std::vector buf; - switch (header.encoding) - { - case CHUNK_ENCODING_NONE: - buf.resize(header.length); - std::memcpy(buf.data(), src, header.length); - break; - case CHUNK_ENCODING_RLE: - buf = DecodeChunkRLE(src, header.length); - break; - case CHUNK_ENCODING_RLECOMPRESSED: - buf = DecodeChunkRLERepeat(src, header.length); - break; - case CHUNK_ENCODING_ROTATE: - buf = DecodeChunkRotate(src, header.length); - break; - default: - throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING); - } - return buf; -} - -std::vector SawyerChunkReader::DecodeChunkRLERepeat(const void* src, size_t srcLength) -{ - auto tempBuf = DecodeChunkRLE(src, srcLength); - return DecodeChunkRepeat(tempBuf.data(), tempBuf.size()); -} - -std::vector SawyerChunkReader::DecodeChunkRLE(const void* src, size_t srcLength) +static std::vector DecodeChunkRLE(const void* src, size_t srcLength) { std::vector buf; buf.reserve(srcLength); @@ -233,7 +205,7 @@ std::vector SawyerChunkReader::DecodeChunkRLE(const void* src, size_t s return buf; } -std::vector SawyerChunkReader::DecodeChunkRepeat(const void* src, size_t srcLength) +static std::vector DecodeChunkRepeat(const void* src, size_t srcLength) { std::vector buf; buf.reserve(srcLength); @@ -271,7 +243,13 @@ std::vector SawyerChunkReader::DecodeChunkRepeat(const void* src, size_ return buf; } -std::vector SawyerChunkReader::DecodeChunkRotate(const void* src, size_t srcLength) +static std::vector DecodeChunkRLERepeat(const void* src, size_t srcLength) +{ + auto tempBuf = DecodeChunkRLE(src, srcLength); + return DecodeChunkRepeat(tempBuf.data(), tempBuf.size()); +} + +static std::vector DecodeChunkRotate(const void* src, size_t srcLength) { std::vector buf; buf.reserve(srcLength); @@ -287,3 +265,27 @@ std::vector SawyerChunkReader::DecodeChunkRotate(const void* src, size_ return buf; } + +static std::vector DecodeChunk(const void* src, const SawyerCodingChunkHeader& header) +{ + std::vector buf; + switch (header.encoding) + { + case CHUNK_ENCODING_NONE: + buf.resize(header.length); + std::memcpy(buf.data(), src, header.length); + break; + case CHUNK_ENCODING_RLE: + buf = DecodeChunkRLE(src, header.length); + break; + case CHUNK_ENCODING_RLECOMPRESSED: + buf = DecodeChunkRLERepeat(src, header.length); + break; + case CHUNK_ENCODING_ROTATE: + buf = DecodeChunkRotate(src, header.length); + break; + default: + throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING); + } + return buf; +} diff --git a/src/openrct2/rct12/SawyerChunkReader.h b/src/openrct2/rct12/SawyerChunkReader.h index cb878e5b3c..d17470ae0e 100644 --- a/src/openrct2/rct12/SawyerChunkReader.h +++ b/src/openrct2/rct12/SawyerChunkReader.h @@ -85,11 +85,4 @@ public: ReadChunk(&result, sizeof(result)); return result; } - -private: - static std::vector DecodeChunk(const void* src, const SawyerCodingChunkHeader& header); - static std::vector DecodeChunkRLERepeat(const void* src, size_t srcLength); - static std::vector DecodeChunkRLE(const void* src, size_t srcLength); - static std::vector DecodeChunkRepeat(const void* src, size_t srcLength); - static std::vector DecodeChunkRotate(const void* src, size_t srcLength); }; From 2c0bfd01ac63c769069dc18a1609284bfe03fce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:26:03 +0300 Subject: [PATCH 2/3] Refactor SawyerChunkReader to use MemoryStream, better performance --- src/openrct2/rct12/SawyerChunk.cpp | 5 +- src/openrct2/rct12/SawyerChunk.h | 13 ++--- src/openrct2/rct12/SawyerChunkReader.cpp | 63 ++++++++++++++---------- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/openrct2/rct12/SawyerChunk.cpp b/src/openrct2/rct12/SawyerChunk.cpp index 4c73858f83..667821ec6e 100644 --- a/src/openrct2/rct12/SawyerChunk.cpp +++ b/src/openrct2/rct12/SawyerChunk.cpp @@ -9,10 +9,11 @@ #include "SawyerChunk.h" -#include "../core/Memory.hpp" #include "SawyerChunkReader.h" -SawyerChunk::SawyerChunk(SAWYER_ENCODING encoding, std::vector&& data) +using namespace OpenRCT2; + +SawyerChunk::SawyerChunk(SAWYER_ENCODING encoding, MemoryStream&& data) : _data(std::move(data)) , _encoding(encoding) { diff --git a/src/openrct2/rct12/SawyerChunk.h b/src/openrct2/rct12/SawyerChunk.h index 93ea2c3068..fb7fa47966 100644 --- a/src/openrct2/rct12/SawyerChunk.h +++ b/src/openrct2/rct12/SawyerChunk.h @@ -9,8 +9,9 @@ #pragma once -#include -#include +#include "../core/MemoryStream.h" + +#include /** * The type of encoding / compression for a sawyer encoded chunk. @@ -29,22 +30,22 @@ enum class SAWYER_ENCODING : uint8_t class SawyerChunk final { private: - std::vector _data; + OpenRCT2::MemoryStream _data; SAWYER_ENCODING _encoding = SAWYER_ENCODING::NONE; public: const void* GetData() const { - return _data.data(); + return _data.GetData(); } size_t GetLength() const { - return _data.size(); + return _data.GetLength(); } SAWYER_ENCODING GetEncoding() const { return _encoding; } - SawyerChunk(SAWYER_ENCODING encoding, std::vector&& data); + SawyerChunk(SAWYER_ENCODING encoding, OpenRCT2::MemoryStream&& data); }; diff --git a/src/openrct2/rct12/SawyerChunkReader.cpp b/src/openrct2/rct12/SawyerChunkReader.cpp index 9946b23765..72b47bb969 100644 --- a/src/openrct2/rct12/SawyerChunkReader.cpp +++ b/src/openrct2/rct12/SawyerChunkReader.cpp @@ -10,6 +10,7 @@ #include "SawyerChunkReader.h" #include "../core/IStream.hpp" +#include "../core/MemoryStream.h" #include "../core/Numerics.hpp" using namespace OpenRCT2; @@ -33,7 +34,7 @@ constexpr const char* EXCEPTION_MSG_DESTINATION_TOO_SMALL = "Chunk data larger t constexpr const char* EXCEPTION_MSG_INVALID_CHUNK_ENCODING = "Invalid chunk encoding."; constexpr const char* EXCEPTION_MSG_ZERO_SIZED_CHUNK = "Encountered zero-sized chunk."; -static std::vector DecodeChunk(const void* src, const SawyerCodingChunkHeader& header); +static MemoryStream DecodeChunk(const void* src, const SawyerCodingChunkHeader& header); SawyerChunkReader::SawyerChunkReader(OpenRCT2::IStream* stream) : _stream(stream) @@ -79,10 +80,11 @@ std::shared_ptr SawyerChunkReader::ReadChunk() } auto buffer = DecodeChunk(compressedData.get(), header); - if (buffer.empty()) + if (buffer.GetLength() == 0) { throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK); } + return std::make_shared(static_cast(header.encoding), std::move(buffer)); } default: @@ -118,7 +120,7 @@ std::shared_ptr SawyerChunkReader::ReadChunkTrack() SawyerCodingChunkHeader header{ CHUNK_ENCODING_RLE, compressedDataLength }; auto buffer = DecodeChunk(compressedData.get(), header); - if (buffer.empty()) + if (buffer.GetLength() == 0) { throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK); } @@ -153,10 +155,9 @@ void SawyerChunkReader::ReadChunk(void* dst, size_t length) } } -static std::vector DecodeChunkRLE(const void* src, size_t srcLength) +static MemoryStream DecodeChunkRLE(const void* src, size_t srcLength) { - std::vector buf; - buf.reserve(srcLength); + MemoryStream buf; auto src8 = static_cast(src); for (size_t i = 0; i < srcLength; i++) @@ -171,12 +172,15 @@ static std::vector DecodeChunkRLE(const void* src, size_t srcLength) { throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); } - if (buf.size() + count > MAX_UNCOMPRESSED_CHUNK_SIZE) + if (buf.GetLength() + count > MAX_UNCOMPRESSED_CHUNK_SIZE) { throw SawyerChunkException(EXCEPTION_MSG_DESTINATION_TOO_SMALL); } - buf.insert(buf.end(), count, src8[i]); + for (size_t n = 0; n < count; n++) + { + buf.Write1(src8 + i); + } } else { @@ -186,7 +190,7 @@ static std::vector DecodeChunkRLE(const void* src, size_t srcLength) { throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); } - if (buf.size() + len > MAX_UNCOMPRESSED_CHUNK_SIZE) + if (buf.GetLength() + len > MAX_UNCOMPRESSED_CHUNK_SIZE) { throw SawyerChunkException(EXCEPTION_MSG_DESTINATION_TOO_SMALL); } @@ -196,8 +200,8 @@ static std::vector DecodeChunkRLE(const void* src, size_t srcLength) } const auto* pos = src8 + i + 1; - buf.insert(buf.end(), pos, pos + len); + buf.Write(pos, len); i += len; } } @@ -205,10 +209,9 @@ static std::vector DecodeChunkRLE(const void* src, size_t srcLength) return buf; } -static std::vector DecodeChunkRepeat(const void* src, size_t srcLength) +static MemoryStream DecodeChunkRepeat(const void* src, size_t srcLength) { - std::vector buf; - buf.reserve(srcLength); + MemoryStream buf; auto src8 = static_cast(src); for (size_t i = 0; i < srcLength; i++) @@ -219,15 +222,17 @@ static std::vector DecodeChunkRepeat(const void* src, size_t srcLength) { throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); } - buf.push_back(src8[++i]); + i++; + buf.Write1(src8 + i); } else { size_t count = (src8[i] & 7) + 1; int32_t offset = static_cast(src8[i] >> 3) - 32; - const uint8_t* copySrc = buf.data() + (buf.size() + offset); + const uint8_t* copySrc = static_cast(buf.GetData()) + (buf.GetLength() + offset); - if (copySrc < buf.data() || copySrc + count > buf.data() + buf.size()) + if (copySrc < static_cast(buf.GetData()) + || copySrc + count > static_cast(buf.GetData()) + buf.GetLength()) { throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); } @@ -236,44 +241,44 @@ static std::vector DecodeChunkRepeat(const void* src, size_t srcLength) uint8_t temp[16]; std::memcpy(temp, copySrc, count); - buf.insert(buf.end(), std::begin(temp), std::begin(temp) + count); + buf.Write(temp, count); } } return buf; } -static std::vector DecodeChunkRLERepeat(const void* src, size_t srcLength) +static MemoryStream DecodeChunkRLERepeat(const void* src, size_t srcLength) { auto tempBuf = DecodeChunkRLE(src, srcLength); - return DecodeChunkRepeat(tempBuf.data(), tempBuf.size()); + return DecodeChunkRepeat(tempBuf.GetData(), tempBuf.GetLength()); } -static std::vector DecodeChunkRotate(const void* src, size_t srcLength) +static MemoryStream DecodeChunkRotate(const void* src, size_t srcLength) { - std::vector buf; - buf.reserve(srcLength); + MemoryStream buf; auto src8 = static_cast(src); uint8_t code = 1; for (size_t i = 0; i < srcLength; i++) { - buf.push_back(Numerics::ror8(src8[i], code)); + uint8_t temp = Numerics::ror8(src8[i], code); + buf.Write1(&temp); code = (code + 2) % 8; } return buf; } -static std::vector DecodeChunk(const void* src, const SawyerCodingChunkHeader& header) +static MemoryStream DecodeChunk(const void* src, const SawyerCodingChunkHeader& header) { - std::vector buf; + MemoryStream buf; + switch (header.encoding) { case CHUNK_ENCODING_NONE: - buf.resize(header.length); - std::memcpy(buf.data(), src, header.length); + buf.Write(src, header.length); break; case CHUNK_ENCODING_RLE: buf = DecodeChunkRLE(src, header.length); @@ -287,5 +292,9 @@ static std::vector DecodeChunk(const void* src, const SawyerCodingChunk default: throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING); } + + // Return the stream with the position at the beginning. + buf.SetPosition(0); + return buf; } From 7c1d3c42b3e6aa304a653c41bfe3039f32eed36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:27:00 +0300 Subject: [PATCH 3/3] Remove windows.h include and win32 specific defines, not needed --- src/openrct2/rct12/SawyerChunkReader.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/openrct2/rct12/SawyerChunkReader.cpp b/src/openrct2/rct12/SawyerChunkReader.cpp index 72b47bb969..1e93b99298 100644 --- a/src/openrct2/rct12/SawyerChunkReader.cpp +++ b/src/openrct2/rct12/SawyerChunkReader.cpp @@ -15,16 +15,6 @@ using namespace OpenRCT2; -// malloc is very slow for large allocations in MSVC debug builds as it allocates -// memory on a special debug heap and then initialises all the memory to 0xCC. -#if defined(_WIN32) && defined(DEBUG) -# define __USE_HEAP_ALLOC__ -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -#endif - // Allow chunks to be uncompressed to a maximum of 16 MiB constexpr size_t MAX_UNCOMPRESSED_CHUNK_SIZE = 16 * 1024 * 1024;