From c503ce663de02508b56b1415935dad72ce1cf893 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 3 Jan 2023 21:20:53 +0100 Subject: [PATCH] Improve LZ4 decompression --- include/PSX/Auxiliary/lz4_decompressor.hpp | 9 +- .../src/Auxiliary/lz4_decompressor.cpp | 260 +++++++----------- src/Library/src/BootLoader/gpu_boot.cpp | 2 +- 3 files changed, 104 insertions(+), 167 deletions(-) diff --git a/include/PSX/Auxiliary/lz4_decompressor.hpp b/include/PSX/Auxiliary/lz4_decompressor.hpp index 179b00ff..e8343cc9 100644 --- a/include/PSX/Auxiliary/lz4_decompressor.hpp +++ b/include/PSX/Auxiliary/lz4_decompressor.hpp @@ -49,13 +49,6 @@ namespace JabyEngine { static bool obtain_any_length(ArrayRange& data, uint32_t &dst_length); - pair read_token(ArrayRange& data); - pair obtain_literal_length(ArrayRange& data); - pair copy_literals(ArrayRange& data); - pair obtain_match_offset(ArrayRange& data); - pair obtain_match_length(ArrayRange& data); - pair copy_match(ArrayRange& data); - public: LZ4Decompressor() = default; LZ4Decompressor(uint8_t* dst_adr) : LZ4Decompressor() { @@ -65,7 +58,7 @@ namespace JabyEngine { void setup(uint8_t* dst_adr); void reset(); - Result process(ArrayRange data); + Result process(ArrayRange data, bool is_last); }; } diff --git a/src/Library/src/Auxiliary/lz4_decompressor.cpp b/src/Library/src/Auxiliary/lz4_decompressor.cpp index 3d028ffa..77360d0e 100644 --- a/src/Library/src/Auxiliary/lz4_decompressor.cpp +++ b/src/Library/src/Auxiliary/lz4_decompressor.cpp @@ -1,7 +1,5 @@ #include -#include - namespace JabyEngine { static void memcpy(uint8_t* &dst, ArrayRange &src, size_t size) { for(size_t n = 0; n < size; n++) { @@ -23,130 +21,6 @@ namespace JabyEngine { return false; } - pair LZ4Decompressor :: read_token(ArrayRange& data) { - if(data) { - const auto token = data.pop(); - - /*if(token == 0) { - return {false, Result::new_done(0)}; - }*/ - - this->state.literal_length = (token & 0xF0) >> 4; - this->state.match_length = (token & 0x0F); - - printf("LiteralLength: %llu MatchLength: %llu\n", this->state.literal_length, this->state.match_length); - - if(this->state.literal_length == 15) { - this->state.step = State::Step::ObtainLiteralLength; - } - - else if(this->state.literal_length == 0) { - this->state.step = State::Step::ObtainMatchOffset; - } - - else { - this->state.step = State::Step::CopyLiterals; - } - return {true, Result::new_in_progress(0)}; - } - - return {false, Result::new_in_progress(0)}; - } - - pair LZ4Decompressor :: obtain_literal_length(ArrayRange& data) { - if(LZ4Decompressor::obtain_any_length(data, this->state.literal_length)) { - printf("New LiteralLength: %llu\n", this->state.literal_length); - this->state.step = State::Step::CopyLiterals; - return {true, Result::new_in_progress(0)}; - } - - return {false, Result::new_in_progress(0)}; - } - - pair LZ4Decompressor :: copy_literals(ArrayRange& data) { - if(data) { - const auto bytes_copy = (this->state.literal_length > data.size) ? data.size : this->state.literal_length; - - printf("Copy %llu bytes of literal\n", bytes_copy); - memcpy(this->dst_adr, data, bytes_copy); - - this->state.literal_length -= bytes_copy; - if(this->state.literal_length == 0) { - this->state.step = State::Step::ObtainMatchOffset; - return {true, Result::new_in_progress(bytes_copy)}; - } - } - - return {false, Result::new_in_progress(0)}; - } - - pair LZ4Decompressor :: obtain_match_offset(ArrayRange& data) { - static const auto state_complete = [](State& state) -> pair { - if(state.match_length == 15) { - state.step = State::Step::ObtainMatchLength; - } - - else { - state.step = State::Step::CopyMatch; - } - - printf("New MatchOffset: %llu\n", state.match_offset); - return {true, Result::new_in_progress(0)}; - }; - - if(data) { - if(this->state.match_offset == 0xFFFF) { - // We are unused and invalid - if(data.size >= sizeof(uint16_t)) { - // We can read all - this->state.match_offset = *reinterpret_cast(data.start); - data.skip(sizeof(uint16_t)); - - return state_complete(this->state); - } - - else { - this->state.match_offset = static_cast(data.pop()); - } - } - - else { - this->state.match_offset |= (static_cast(data.pop()) << 8); - return state_complete(this->state); - } - } - - return {false, Result::new_in_progress(0)}; - } - - pair LZ4Decompressor :: obtain_match_length(ArrayRange& data) { - if(LZ4Decompressor::obtain_any_length(data, this->state.match_length)) { - this->state.step = State::Step::CopyMatch; - - printf("New match length: %llu\n", this->state.match_length); - return {true, Result::new_in_progress(0)}; - } - - return {false, Result::new_in_progress(0)}; - } - - pair LZ4Decompressor :: copy_match(ArrayRange& data) { - static constexpr size_t min_match_length = 4; - - this->state.match_length += min_match_length; - - const uint8_t* src = this->dst_adr - this->state.match_offset; - ArrayRange src_data(src, this->state.match_length); - - memcpy(this->dst_adr, src_data, this->state.match_length); - - this->state.match_offset = 0xFFFF; - this->state.step = State::Step::ReadToken; - - const bool keep_going = data; - return {keep_going, data ? Result::new_in_progress(this->state.match_length) : Result::new_done(this->state.match_length)}; - } - void LZ4Decompressor :: setup(uint8_t* dst_adr) { this->dst_adr = dst_adr; LZ4Decompressor::reset(); @@ -156,47 +30,117 @@ namespace JabyEngine { this->state = State(); } - LZ4Decompressor::Result LZ4Decompressor :: process(ArrayRange data) { - const auto do_call = [this](ArrayRange& data, size_t bytes_ready) -> pair { + LZ4Decompressor::Result LZ4Decompressor :: process(ArrayRange data, bool is_last) { + size_t bytes_ready = 0; + + while(data) { switch(this->state.step) { - case State::Step::ReadToken: - printf("Read Token! %llu bytes left (%llu bytes ready)\n", data.size, bytes_ready); - return LZ4Decompressor::read_token(data); + case State::Step::ReadToken: { + const auto token = data.pop(); - case State::Step::ObtainLiteralLength: - printf("Obtain literal length! %llu bytes left (%llu bytes ready)\n", data.size, bytes_ready); - return LZ4Decompressor::obtain_literal_length(data); + this->state.literal_length = (token & 0xF0) >> 4; + this->state.match_length = (token & 0x0F); - case State::Step::CopyLiterals: - printf("Copy Literals! %llu bytes left (%llu bytes ready)\n", data.size, bytes_ready); - return LZ4Decompressor::copy_literals(data); + if(this->state.literal_length == 15) { + this->state.step = State::Step::ObtainLiteralLength; + } - case State::Step::ObtainMatchOffset: - printf("Obtain match offset! %llu bytes left (%llu bytes ready)\n", data.size, bytes_ready); - return LZ4Decompressor::obtain_match_offset(data); + else if(this->state.literal_length == 0) { + this->state.step = State::Step::ObtainMatchOffset; + } - case State::Step::ObtainMatchLength: - printf("Obtain match length! %llu bytes left (%llu bytes ready)\n", data.size, bytes_ready); - return LZ4Decompressor::obtain_match_length(data); + else { + this->state.step = State::Step::CopyLiterals; + } + } break; - case State::Step::CopyMatch: - printf("Copy match! %llu bytes left\n", data.size); - return LZ4Decompressor::copy_match(data); + case State::Step::ObtainLiteralLength: { + if(LZ4Decompressor::obtain_any_length(data, this->state.literal_length)) { + this->state.step = State::Step::CopyLiterals; + } + } break; + + case State::Step::CopyLiterals: { + const auto bytes_copy = (this->state.literal_length > data.size) ? data.size : this->state.literal_length; + + memcpy(this->dst_adr, data, bytes_copy); + + this->state.literal_length -= bytes_copy; + if(this->state.literal_length == 0) { + this->state.step = State::Step::ObtainMatchOffset; + bytes_ready += bytes_copy; + } + } break; + + case State::Step::ObtainMatchOffset: { + static const auto state_complete = [](State& state) -> bool { + if(state.match_offset == 0) { + return false; + } + + else { + if(state.match_length == 15) { + state.step = State::Step::ObtainMatchLength; + } + + else { + state.step = State::Step::CopyMatch; + } + return true; + } + }; + + if(this->state.match_offset == 0xFFFF) { + // We are unused and invalid + if(data.size >= sizeof(uint16_t)) { + // We can read all + this->state.match_offset = *reinterpret_cast(data.start); + data.skip(sizeof(uint16_t)); + + if(!state_complete(this->state)) { + return Result::new_done(bytes_ready); + } + } + + else { + this->state.match_offset = static_cast(data.pop()); + } + } + + else { + this->state.match_offset |= (static_cast(data.pop()) << 8); + if(!state_complete(this->state)) { + return Result::new_done(bytes_ready); + } + } + } break; + + case State::Step::ObtainMatchLength: { + if(LZ4Decompressor::obtain_any_length(data, this->state.match_length)) { + this->state.step = State::Step::CopyMatch; + } + } break; + + case State::Step::CopyMatch: { + static constexpr size_t min_match_length = 4; + + this->state.match_length += min_match_length; + + const uint8_t* src = this->dst_adr - this->state.match_offset; + ArrayRange src_data(src, this->state.match_length); + + memcpy(this->dst_adr, src_data, this->state.match_length); + + this->state.match_offset = 0xFFFF; + this->state.step = State::Step::ReadToken; + + bytes_ready += this->state.match_length; + } break; default: - return {false, Result::new_error()}; - } - }; - - size_t bytes_ready = 0; - while(true) { - auto [keep_going, result] = do_call(data, bytes_ready); - - bytes_ready += result.bytes_ready; - if(!keep_going) { - result.bytes_ready = bytes_ready; - return result; + return Result::new_error(); } } + return is_last ? Result::new_done(bytes_ready) : Result::new_in_progress(bytes_ready); } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/gpu_boot.cpp b/src/Library/src/BootLoader/gpu_boot.cpp index 77cb7e84..90644665 100644 --- a/src/Library/src/BootLoader/gpu_boot.cpp +++ b/src/Library/src/BootLoader/gpu_boot.cpp @@ -17,7 +17,7 @@ namespace JabyEngine { static size_t decompress_logo() { LZ4Decompressor lz4_decomp(reinterpret_cast(&__boot_loader_end)); - const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen))); + const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen)), true); switch(progress) { case Progress::InProgress: printf("Decompressing still in progress... %llu\n", bytes_ready);