From 6b7e6e01bb025bf5cbeb92e65a492121070fb996 Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Wed, 16 Oct 2019 16:12:28 +0900 Subject: [PATCH] v111.8 Serialize SDD1 decompressor Major speedup to nall/serializer [Alcaro] Removed fast PPU tile cache (major speedup for run-ahead mode) --- bsnes/GNUmakefile | 2 - bsnes/emulator/emulator.hpp | 6 +- bsnes/sfc/coprocessor/sdd1/decompressor.hpp | 7 +++ bsnes/sfc/coprocessor/sdd1/serialization.cpp | 52 +++++++++++++++++ bsnes/sfc/ppu-fast/background.cpp | 29 +++++++++- bsnes/sfc/ppu-fast/io.cpp | 2 + bsnes/sfc/ppu-fast/object.cpp | 15 +++-- bsnes/sfc/ppu-fast/ppu.cpp | 7 --- bsnes/sfc/ppu-fast/ppu.hpp | 3 +- bsnes/sfc/ppu-fast/serialization.cpp | 2 - bsnes/sfc/system/serialization.cpp | 7 +++ bsnes/target-libretro/GNUmakefile | 12 +++- bsnes/target-libretro/libretro.cpp | 24 +------- bsnes/target-libretro/program.cpp | 3 - libco/aarch64.c | 27 +++------ libco/amd64.c | 23 +++----- libco/arm.c | 26 +++------ libco/fiber.c | 4 ++ libco/libco.c | 2 +- libco/libco.h | 3 +- libco/ppc.c | 4 ++ libco/ppc64v2.c | 10 ++-- libco/sjlj.c | 4 ++ libco/ucontext.c | 4 ++ libco/x86.c | 23 +++----- nall/dsp/resampler/cubic.hpp | 4 +- nall/http/response.hpp | 21 ++++++- nall/queue.hpp | 2 +- nall/serializer.hpp | 61 ++++++++++---------- nall/string/transform/dml.hpp | 40 +++++++++++-- 30 files changed, 262 insertions(+), 167 deletions(-) diff --git a/bsnes/GNUmakefile b/bsnes/GNUmakefile index f017341e..9450f39c 100644 --- a/bsnes/GNUmakefile +++ b/bsnes/GNUmakefile @@ -42,8 +42,6 @@ else ifneq ($(filter $(platform),linux bsd),) flags += -fPIC options += -shared endif -else - $(error "unsupported platform") endif objects := libco emulator filter lzma diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 75d7ebe3..a6af8090 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -20,8 +22,6 @@ #include using namespace nall; -#include - #include #include #include @@ -29,7 +29,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "111.8"; + static const string Version = "111.9"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/sfc/coprocessor/sdd1/decompressor.hpp b/bsnes/sfc/coprocessor/sdd1/decompressor.hpp index fad49015..e972c821 100644 --- a/bsnes/sfc/coprocessor/sdd1/decompressor.hpp +++ b/bsnes/sfc/coprocessor/sdd1/decompressor.hpp @@ -3,6 +3,7 @@ struct Decompressor { IM(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; auto getCodeWord(uint8 codeLength) -> uint8; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -13,6 +14,7 @@ struct Decompressor { struct GCD { //golomb-code decoder GCD(SDD1::Decompressor& self) : self(self) {} auto getRunCount(uint8 codeNumber, uint8& mpsCount, bool& lpsIndex) -> void; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -23,6 +25,7 @@ struct Decompressor { BG(SDD1::Decompressor& self, uint8 codeNumber) : self(self), codeNumber(codeNumber) {} auto init() -> void; auto getBit(bool& endOfRun) -> uint8; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -35,6 +38,7 @@ struct Decompressor { PEM(SDD1::Decompressor& self) : self(self) {} auto init() -> void; auto getBit(uint8 context) -> uint8; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -54,6 +58,7 @@ struct Decompressor { CM(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; auto getBit() -> uint8; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -68,6 +73,7 @@ struct Decompressor { OL(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; auto decompress() -> uint8; + auto serialize(serializer&) -> void; private: Decompressor& self; @@ -78,6 +84,7 @@ struct Decompressor { Decompressor(); auto init(uint offset) -> void; auto read() -> uint8; + auto serialize(serializer&) -> void; IM im; GCD gcd; diff --git a/bsnes/sfc/coprocessor/sdd1/serialization.cpp b/bsnes/sfc/coprocessor/sdd1/serialization.cpp index 216b056e..be381b9b 100644 --- a/bsnes/sfc/coprocessor/sdd1/serialization.cpp +++ b/bsnes/sfc/coprocessor/sdd1/serialization.cpp @@ -11,4 +11,56 @@ auto SDD1::serialize(serializer& s) -> void { s.integer(dma[n].size); } s.integer(dmaReady); + + decompressor.serialize(s); +} + +auto SDD1::Decompressor::serialize(serializer& s) -> void { + im.serialize(s); + gcd.serialize(s); + bg0.serialize(s); + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + bg5.serialize(s); + bg6.serialize(s); + bg7.serialize(s); + cm.serialize(s); + ol.serialize(s); +} + +auto SDD1::Decompressor::IM::serialize(serializer& s) -> void { + s.integer(offset); + s.integer(bitCount); +} + +auto SDD1::Decompressor::GCD::serialize(serializer& s) -> void { +} + +auto SDD1::Decompressor::BG::serialize(serializer& s) -> void { + s.integer(mpsCount); + s.integer(lpsIndex); +} + +auto SDD1::Decompressor::PEM::serialize(serializer& s) -> void { + for(auto& info : contextInfo) { + s.integer(info.status); + s.integer(info.mps); + } +} + +auto SDD1::Decompressor::CM::serialize(serializer& s) -> void { + s.integer(bitplanesInfo); + s.integer(contextBitsInfo); + s.integer(bitNumber); + s.integer(currentBitplane); + s.array(previousBitplaneBits); +} + +auto SDD1::Decompressor::OL::serialize(serializer& s) -> void { + s.integer(bitplanesInfo); + s.integer(r0); + s.integer(r1); + s.integer(r2); } diff --git a/bsnes/sfc/ppu-fast/background.cpp b/bsnes/sfc/ppu-fast/background.cpp index da64dd1b..547a503d 100644 --- a/bsnes/sfc/ppu-fast/background.cpp +++ b/bsnes/sfc/ppu-fast/background.cpp @@ -23,6 +23,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi bool hires = io.bgMode == 5 || io.bgMode == 6; bool offsetPerTileMode = io.bgMode == 2 || io.bgMode == 4 || io.bgMode == 6; bool directColorMode = io.col.directColor && source == Source::BG1 && (io.bgMode == 3 || io.bgMode == 4); + uint colorShift = 3 + self.tileMode; int width = 256 << hires; uint tileHeight = 3 + self.tileSize; @@ -91,14 +92,36 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi if(tileHeight == 4 && (bool(voffset & 8) ^ bool(mirrorY))) tileNumber += 16; tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask; - auto tiledata = ppu.tilecache[self.tileMode] + (tileNumber << 6); - tiledata += (voffset & 7 ^ mirrorY) << 3; + uint16 address; + address = (tileNumber << colorShift) + (voffset & 7 ^ mirrorY); + + uint64 data; + data = (uint64)ppu.vram[address + 0] << 0; + data |= (uint64)ppu.vram[address + 8] << 16; + data |= (uint64)ppu.vram[address + 16] << 32; + data |= (uint64)ppu.vram[address + 24] << 48; for(uint tileX = 0; tileX < 8; tileX++, x++) { if(x & width) continue; //x < 0 || x >= width if(!self.mosaicEnable || --mosaicCounter == 0) { + uint color, shift = mirrorX ? tileX : 7 - tileX; + /*if(self.tileMode >= TileMode::BPP2)*/ { + color = data >> shift + 0 & 1; + color += data >> shift + 7 & 2; + } + if(self.tileMode >= TileMode::BPP4) { + color += data >> shift + 14 & 4; + color += data >> shift + 21 & 8; + } + if(self.tileMode >= TileMode::BPP8) { + color += data >> shift + 28 & 16; + color += data >> shift + 35 & 32; + color += data >> shift + 42 & 64; + color += data >> shift + 49 & 128; + } + mosaicCounter = 1 + io.mosaicSize; - mosaicPalette = tiledata[tileX ^ mirrorX]; + mosaicPalette = color; mosaicPriority = tilePriority; if(directColorMode) { mosaicColor = directColor(paletteNumber, mosaicPalette); diff --git a/bsnes/sfc/ppu-fast/io.cpp b/bsnes/sfc/ppu-fast/io.cpp index fd52ce50..2ee16095 100644 --- a/bsnes/sfc/ppu-fast/io.cpp +++ b/bsnes/sfc/ppu-fast/io.cpp @@ -42,6 +42,7 @@ auto PPU::writeVRAM(uint8 data) -> void { } auto PPU::updateTiledata(uint address) -> void { +/* auto word = vram[address & 0x7fff]; auto line2bpp = tilecache[TileMode::BPP2] + (address << 3 & 0x3fff8); auto line4bpp = tilecache[TileMode::BPP4] + (address << 2 & 0x1ffc0) + (address << 3 & 0x38); @@ -53,6 +54,7 @@ auto PPU::updateTiledata(uint address) -> void { line4bpp[7 - x] = line4bpp[7 - x] & ~(3 << plane4bpp) | (word >> x & 1) << plane4bpp | (word >> x + 7 & 2) << plane4bpp; line8bpp[7 - x] = line8bpp[7 - x] & ~(3 << plane8bpp) | (word >> x & 1) << plane8bpp | (word >> x + 7 & 2) << plane8bpp; } +*/ } auto PPU::readOAM(uint10 address) -> uint8 { diff --git a/bsnes/sfc/ppu-fast/object.cpp b/bsnes/sfc/ppu-fast/object.cpp index d1401831..9074dff1 100644 --- a/bsnes/sfc/ppu-fast/object.cpp +++ b/bsnes/sfc/ppu-fast/object.cpp @@ -83,7 +83,9 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { uint mirrorX = !object.hflip ? tileX : tileWidth - 1 - tileX; uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); - tile.number = address >> 4 & 0x7ff; + address = (address & 0x7ff0) + (y & 7); + tile.data = ppu.vram[address + 0] << 0; + tile.data |= ppu.vram[address + 8] << 16; if(tileCount++ >= ppu.TileLimit) break; tiles[tileCount - 1] = tile; @@ -97,16 +99,19 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { uint8_t priority[256] = {}; for(uint n : range(ppu.TileLimit)) { - const auto& tile = tiles[n]; + auto& tile = tiles[n]; if(!tile.valid) continue; - auto tiledata = ppu.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3); uint tileX = tile.x; - uint mirrorX = tile.hflip ? 7 : 0; for(uint x : range(8)) { tileX &= 511; if(tileX < 256) { - if(uint color = tiledata[x ^ mirrorX]) { + uint color, shift = tile.hflip ? x : 7 - x; + color = tile.data >> shift + 0 & 1; + color += tile.data >> shift + 7 & 2; + color += tile.data >> shift + 14 & 4; + color += tile.data >> shift + 21 & 8; + if(color) { palette[tileX] = tile.palette + color; priority[tileX] = self.priority[tile.priority]; } diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index 0701e8b6..2848ec71 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -51,10 +51,6 @@ PPU::PPU() { } } - tilecache[TileMode::BPP2] = new uint8_t[4096 * 8 * 8](); - tilecache[TileMode::BPP4] = new uint8_t[2048 * 8 * 8](); - tilecache[TileMode::BPP8] = new uint8_t[1024 * 8 * 8](); - for(uint y : range(240)) { lines[y].y = y; } @@ -63,9 +59,6 @@ PPU::PPU() { PPU::~PPU() { delete[] output; for(uint l : range(16)) delete[] lightTable[l]; - delete[] tilecache[TileMode::BPP2]; - delete[] tilecache[TileMode::BPP4]; - delete[] tilecache[TileMode::BPP8]; } auto PPU::synchronizeCPU() -> void { diff --git a/bsnes/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp index 8e2e9b57..9b29278f 100644 --- a/bsnes/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -235,7 +235,7 @@ public: uint8 priority = 0; uint8 palette = 0; bool hflip = 0; - uint16 number = 0; + uint32 data = 0; }; struct Pixel { @@ -276,7 +276,6 @@ public: //[unserialized] uint16* output = {}; uint16* lightTable[16] = {}; - uint8* tilecache[3] = {}; //bitplane -> bitmap tiledata uint ItemLimit = 0; uint TileLimit = 0; diff --git a/bsnes/sfc/ppu-fast/serialization.cpp b/bsnes/sfc/ppu-fast/serialization.cpp index 119eea61..7dbdb6b0 100644 --- a/bsnes/sfc/ppu-fast/serialization.cpp +++ b/bsnes/sfc/ppu-fast/serialization.cpp @@ -8,8 +8,6 @@ auto PPU::serialize(serializer& s) -> void { s.array(cgram); for(auto& object : objects) object.serialize(s); - if (s.mode() == s.Load) - for(auto address : range(32768)) updateTiledata(address); Line::start = 0; Line::count = 0; } diff --git a/bsnes/sfc/system/serialization.cpp b/bsnes/sfc/system/serialization.cpp index 25b1c5ac..5900b273 100644 --- a/bsnes/sfc/system/serialization.cpp +++ b/bsnes/sfc/system/serialization.cpp @@ -1,4 +1,11 @@ auto System::serialize(bool synchronize) -> serializer { + //deterministic serialization (synchronize=false) is only possible with select libco methods. + if(co_method() != "x86" + && co_method() != "amd64" + && co_method() != "arm" + && co_method() != "aarch64" + ) synchronize = true; + if(!information.serializeSize[synchronize]) return {}; //should never occur if(synchronize) runToSave(); diff --git a/bsnes/target-libretro/GNUmakefile b/bsnes/target-libretro/GNUmakefile index f64c7242..71e156d4 100644 --- a/bsnes/target-libretro/GNUmakefile +++ b/bsnes/target-libretro/GNUmakefile @@ -3,6 +3,14 @@ local := false openmp := true flags += -Wno-narrowing -Wno-multichar -g -fPIC +ifeq ($(platform), ios-arm64) + flags += -fPIC -miphoneos-version-min=11.0 -Wno-error=implicit-function-declaration -DHAVE_POSIX_MEMALIGN + options += -dynamiclib +else ifeq ($(platform), tvos-arm64) + flags += -fPIC -mtvos-version-min=11.0 -Wno-error=implicit-function-declaration -DHAVE_POSIX_MEMALIGN + options += -dynamiclib +endif + objects := libretro $(objects) objects := $(patsubst %,obj/%.o,$(objects)) @@ -10,9 +18,9 @@ obj/libretro.o: target-libretro/libretro.cpp all: $(objects) ifeq ($(platform),linux) - $(strip $(compiler) -o out/$(name).so -shared $(objects) -Wl,--no-undefined -Wl,--version-script=target-libretro/link.T -Wl,-Bdynamic $(options)) + $(strip $(compiler) -o out/$(name).so -shared $(objects) -Wl,--no-undefined -Wl,--version-script=target-libretro/link.T -lgomp -Wl,-Bdynamic $(options)) else ifeq ($(platform),windows) - $(strip $(compiler) -o out/$(name).dll -shared $(objects) -Wl,--no-undefined -Wl,--version-script=target-libretro/link.T -Wl,-Bdynamic $(options)) + $(strip $(compiler) -o out/$(name).dll -shared $(objects) -Wl,--no-undefined -Wl,--version-script=target-libretro/link.T -lgomp -Wl,-Bdynamic $(options)) else ifeq ($(platform),macos) $(strip $(compiler) -o out/$(name).dylib -shared $(objects) $(options)) else ifeq ($(platform), ios-arm64) diff --git a/bsnes/target-libretro/libretro.cpp b/bsnes/target-libretro/libretro.cpp index 3a804e9d..0e5e75e4 100644 --- a/bsnes/target-libretro/libretro.cpp +++ b/bsnes/target-libretro/libretro.cpp @@ -490,38 +490,18 @@ RETRO_API void retro_run() RETRO_API size_t retro_serialize_size() { - // To avoid having to serialize twice to query the size -> serialize. - if (program->has_cached_serialize) - { - return program->cached_serialize.size(); - } - else - { - program->cached_serialize = emulator->serialize(); - program->has_cached_serialize = true; - return program->cached_serialize.size(); - } + return emulator->serialize().size(); } RETRO_API bool retro_serialize(void *data, size_t size) { - if (!program->has_cached_serialize) - { - program->cached_serialize = emulator->serialize(); - program->has_cached_serialize = true; - } - - if (program->cached_serialize.size() != size) - return false; - - memcpy(data, program->cached_serialize.data(), size); + memcpy(data, emulator->serialize().data(), size); return true; } RETRO_API bool retro_unserialize(const void *data, size_t size) { serializer s(static_cast(data), size); - program->has_cached_serialize = false; return emulator->unserialize(s); } diff --git a/bsnes/target-libretro/program.cpp b/bsnes/target-libretro/program.cpp index 23948642..2c4d3649 100644 --- a/bsnes/target-libretro/program.cpp +++ b/bsnes/target-libretro/program.cpp @@ -44,9 +44,6 @@ struct Program : Emulator::Platform auto hackPatchMemory(vector& data) -> void; - serializer cached_serialize; - bool has_cached_serialize = false; - string base_name; bool overscan = false; diff --git a/libco/aarch64.c b/libco/aarch64.c index e153cd46..59162f20 100644 --- a/libco/aarch64.c +++ b/libco/aarch64.c @@ -59,6 +59,10 @@ static void co_init() { #endif } +const char* co_method() { + return "aarch64"; +} + cothread_t co_active() { if(!co_active_handle) co_active_handle = &co_active_buffer; return co_active_handle; @@ -73,7 +77,8 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) if(!co_active_handle) co_active_handle = &co_active_buffer; if(handle = (unsigned long*)memory) { - unsigned long* p = (unsigned long*)((unsigned char*)handle + size); + unsigned int offset = (size & ~15); + unsigned long* p = (unsigned long*)((unsigned char*)handle + offset); handle[19] = (unsigned long)p; /* x29 (frame pointer) */ handle[20] = (unsigned long)p; /* x30 (stack pointer) */ handle[21] = (unsigned long)entrypoint; /* x31 (link register) */ @@ -83,23 +88,9 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) } cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { - unsigned long* handle; - if(!co_swap) { - co_init(); - co_swap = (void (*)(cothread_t, cothread_t))co_swap_function; - } - if(!co_active_handle) co_active_handle = &co_active_buffer; - size += 256; - size &= ~15; - - if(handle = (unsigned long*)malloc(size)) { - unsigned long* p = (unsigned long*)((unsigned char*)handle + size); - handle[19] = (unsigned long)p; /* x29 (frame pointer) */ - handle[20] = (unsigned long)p; /* x30 (stack pointer) */ - handle[21] = (unsigned long)entrypoint; /* x31 (link register) */ - } - - return handle; + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); } void co_delete(cothread_t handle) { diff --git a/libco/amd64.c b/libco/amd64.c index 664730a1..e9aef889 100755 --- a/libco/amd64.c +++ b/libco/amd64.c @@ -115,6 +115,10 @@ static void crash() { assert(0); /* called only if cothread_t entrypoint returns */ } +const char* co_method() { + return "amd64"; +} + cothread_t co_active() { if(!co_active_handle) co_active_handle = &co_active_buffer; return co_active_handle; @@ -140,22 +144,9 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) } cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { - cothread_t handle; - if(!co_swap) { - co_init(); - co_swap = (void (*)(cothread_t, cothread_t))co_swap_function; - } - if(!co_active_handle) co_active_handle = &co_active_buffer; - - if(handle = (cothread_t)malloc(size)) { - unsigned int offset = (size & ~15) - 32; - long long *p = (long long*)((char*)handle + offset); /* seek to top of stack */ - *--p = (long long)crash; /* crash if entrypoint returns */ - *--p = (long long)entrypoint; /* start of function */ - *(long long*)handle = (long long)p; /* stack pointer */ - } - - return handle; + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); } void co_delete(cothread_t handle) { diff --git a/libco/arm.c b/libco/arm.c index 20c95310..8d872bf5 100644 --- a/libco/arm.c +++ b/libco/arm.c @@ -35,6 +35,10 @@ static void co_init() { #endif } +const char* co_method() { + return "arm"; +} + cothread_t co_active() { if(!co_active_handle) co_active_handle = &co_active_buffer; return co_active_handle; @@ -49,7 +53,8 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) if(!co_active_handle) co_active_handle = &co_active_buffer; if(handle = (unsigned long*)memory) { - unsigned long* p = (unsigned long*)((unsigned char*)handle + size); + unsigned int offset = (size & ~15); + unsigned long* p = (unsigned long*)((unsigned char*)handle + offset); handle[8] = (unsigned long)p; handle[9] = (unsigned long)entrypoint; } @@ -58,22 +63,9 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) } cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { - unsigned long* handle; - if(!co_swap) { - co_init(); - co_swap = (void (*)(cothread_t, cothread_t))co_swap_function; - } - if(!co_active_handle) co_active_handle = &co_active_buffer; - size += 256; - size &= ~15; - - if(handle = (unsigned long*)malloc(size)) { - unsigned long* p = (unsigned long*)((unsigned char*)handle + size); - handle[8] = (unsigned long)p; - handle[9] = (unsigned long)entrypoint; - } - - return handle; + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); } void co_delete(cothread_t handle) { diff --git a/libco/fiber.c b/libco/fiber.c index bdf4dd4e..f508b0f8 100755 --- a/libco/fiber.c +++ b/libco/fiber.c @@ -16,6 +16,10 @@ static void __stdcall co_thunk(void* coentry) { ((void (*)(void))coentry)(); } +const char* co_method() { + return "fiber"; +} + cothread_t co_active() { if(!co_active_) { ConvertThreadToFiber(0); diff --git a/libco/libco.c b/libco/libco.c index f9c79bf4..21fe4cab 100755 --- a/libco/libco.c +++ b/libco/libco.c @@ -1,7 +1,7 @@ #if defined(__clang__) #pragma clang diagnostic ignored "-Wparentheses" - //placing code in section(text) does not mark it executable with Clang. + /* placing code in section(text) does not mark it executable with Clang. */ #undef LIBCO_MPROTECT #define LIBCO_MPROTECT #endif diff --git a/libco/libco.h b/libco/libco.h index a436957c..0b94c2e9 100755 --- a/libco/libco.h +++ b/libco/libco.h @@ -1,5 +1,5 @@ /* - libco v20 (2019-10-14) + libco v20 (2019-10-16) author: byuu license: ISC */ @@ -13,6 +13,7 @@ extern "C" { typedef void* cothread_t; +const char* co_method(); cothread_t co_active(); cothread_t co_derive(void*, unsigned int, void (*)(void)); cothread_t co_create(unsigned int, void (*)(void)); diff --git a/libco/ppc.c b/libco/ppc.c index 969fcec2..314997c8 100755 --- a/libco/ppc.c +++ b/libco/ppc.c @@ -413,6 +413,10 @@ static void co_init_(void) { co_active_handle = co_create_(state_size, (uintptr_t)&co_switch); } +const char* co_method() { + return "ppc"; +} + cothread_t co_active() { if(!co_active_handle) co_init_(); diff --git a/libco/ppc64v2.c b/libco/ppc64v2.c index b1f153d4..fac464a6 100644 --- a/libco/ppc64v2.c +++ b/libco/ppc64v2.c @@ -221,6 +221,10 @@ __asm__( ".size swap_context, .-swap_context\n" ); +const char* co_method() { + return "ppc64v2"; +} + cothread_t co_active() { if(!co_active_handle) { co_active_handle = (struct ppc64_context*)malloc(MIN_STACK + sizeof(struct ppc64_context)); @@ -255,11 +259,9 @@ cothread_t co_derive(void* memory, unsigned int size, void (*coentry)(void)) { } cothread_t co_create(unsigned int size, void (*coentry)(void)) { - size_t total = MAX(size, MIN_STACK) + sizeof(struct ppc64_context); - void* memory = malloc(total); - + void* memory = malloc(size); if(!memory) return (cothread_t)0; - return co_derive(memory, total, coentry); + return co_derive(memory, size, coentry); } void co_delete(cothread_t handle) { diff --git a/libco/sjlj.c b/libco/sjlj.c index d99572a3..b4faf17b 100755 --- a/libco/sjlj.c +++ b/libco/sjlj.c @@ -33,6 +33,10 @@ static void springboard(int ignored) { } } +const char* co_method() { + return "sjlj"; +} + cothread_t co_active() { if(!co_running) co_running = &co_primary; return (cothread_t)co_running; diff --git a/libco/ucontext.c b/libco/ucontext.c index edf513d4..49fa976c 100755 --- a/libco/ucontext.c +++ b/libco/ucontext.c @@ -26,6 +26,10 @@ extern "C" { static thread_local ucontext_t co_primary; static thread_local ucontext_t* co_running = 0; +const char* co_module() { + return "ucontext"; +} + cothread_t co_active() { if(!co_running) co_running = &co_primary; return (cothread_t)co_running; diff --git a/libco/x86.c b/libco/x86.c index 3eb2e21e..8effa0d4 100755 --- a/libco/x86.c +++ b/libco/x86.c @@ -69,6 +69,10 @@ static void crash() { assert(0); /* called only if cothread_t entrypoint returns */ } +const char* co_method() { + return "x86"; +} + cothread_t co_active() { if(!co_active_handle) co_active_handle = &co_active_buffer; return co_active_handle; @@ -94,22 +98,9 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) } cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { - cothread_t handle; - if(!co_swap) { - co_init(); - co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function; - } - if(!co_active_handle) co_active_handle = &co_active_buffer; - - if(handle = (cothread_t)malloc(size)) { - unsigned int offset = (size & ~15) - 32; - long *p = (long*)((char*)handle + offset); /* seek to top of stack */ - *--p = (long)crash; /* crash if entrypoint returns */ - *--p = (long)entrypoint; /* start of function */ - *(long*)handle = (long)p; /* stack pointer */ - } - - return handle; + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); } void co_delete(cothread_t handle) { diff --git a/nall/dsp/resampler/cubic.hpp b/nall/dsp/resampler/cubic.hpp index bd8cd5d3..7f0bccfd 100644 --- a/nall/dsp/resampler/cubic.hpp +++ b/nall/dsp/resampler/cubic.hpp @@ -9,7 +9,7 @@ namespace nall::DSP::Resampler { struct Cubic { inline auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void; inline auto setInputFrequency(double inputFrequency) -> void; - inline auto pending() const -> uint; + inline auto pending() const -> bool; inline auto read() -> double; inline auto write(double sample) -> void; inline auto serialize(serializer&) -> void; @@ -39,7 +39,7 @@ auto Cubic::setInputFrequency(double inputFrequency) -> void { ratio = inputFrequency / outputFrequency; } -auto Cubic::pending() const -> uint { +auto Cubic::pending() const -> bool { return samples.pending(); } diff --git a/nall/http/response.hpp b/nall/http/response.hpp index 0e8f5524..a55d8701 100755 --- a/nall/http/response.hpp +++ b/nall/http/response.hpp @@ -241,11 +241,26 @@ auto Response::setFile(const string& value) -> type& { } if(!valid) return *this; + //cache images for seven days + auto suffix = Location::suffix(value); + uint maxAge = 0; + if(suffix == ".svg" + || suffix == ".ico" + || suffix == ".png" + || suffix == ".gif" + || suffix == ".jpg" + || suffix == ".jpeg") { + maxAge = 7 * 24 * 60 * 60; + } + _file = value; - string eTag = {"\"", chrono::utc::datetime(file::timestamp(value, file::time::modify)), "\""}; header.assign("Content-Length", file::size(value)); - header.assign("Cache-Control", "public"); - header.assign("ETag", eTag); + header.assign("ETag", {"\"", chrono::utc::datetime(file::timestamp(value, file::time::modify)), "\""}); + if(maxAge == 0) { + header.assign("Cache-Control", {"public"}); + } else { + header.assign("Cache-Control", {"public, max-age=", maxAge}); + } return *this; } diff --git a/nall/queue.hpp b/nall/queue.hpp index 1a380d42..062eda77 100644 --- a/nall/queue.hpp +++ b/nall/queue.hpp @@ -41,7 +41,7 @@ struct queue { template auto capacity() const -> uint { return _capacity * sizeof(T) / sizeof(U); } template auto size() const -> uint { return _size * sizeof(T) / sizeof(U); } auto empty() const -> bool { return _size == 0; } - auto pending() const -> uint { return _size; } + auto pending() const -> bool { return _size > 0; } auto full() const -> bool { return _size >= (int)_capacity; } auto underflow() const -> bool { return _size < 0; } auto overflow() const -> bool { return _size > (int)_capacity; } diff --git a/nall/serializer.hpp b/nall/serializer.hpp index 0fd086ca..0993e8cc 100755 --- a/nall/serializer.hpp +++ b/nall/serializer.hpp @@ -51,13 +51,9 @@ struct serializer { return _capacity; } - auto setMode(Mode mode) -> bool { - if(_mode == Mode::Save && mode == Mode::Load) { - _mode = mode; - _size = 0; - return true; - } - return false; + auto setMode(Mode mode) -> void { + _mode = mode; + _size = 0; } template auto real(T& value) -> serializer& { @@ -110,35 +106,38 @@ struct serializer { return *this; } - template auto array(uint8_t (&array_)[N]) -> serializer& { - array(array_, N); - return *this; - } - auto array(uint8_t* array, uint size) -> serializer& { - if(_mode == Save) { - memcpy(_data+_size, array, size); - } else if(_mode == Load) { - memcpy(array, _data+_size, size); - } - _size += size; - return *this; - } -#ifdef ENDIAN_LSB - template auto array(uint16_t (&array_)[N]) -> serializer& { - array(array_, N); - return *this; - } - auto array(uint16_t* array_, uint size) -> serializer& { - array((uint8_t*)array_, size*2); - return *this; - } -#endif - template auto array(nall::array& array) -> serializer& { for(auto& value : array) operator()(value); return *this; } + //optimized specializations + + auto array(uint8_t* data, uint size) -> serializer& { + if(_mode == Save) { + memory::copy(_data + _size, data, size); + } else if(_mode == Load) { + memory::copy(data, _data + _size, size); + } else { + } + _size += size; + return *this; + } + + template auto array(uint8_t (&data)[N]) -> serializer& { + return array(data, N); + } + + //nall/serializer saves data in little-endian ordering + #if defined(ENDIAN_LSB) + auto array(uint16_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint16_t)); } + auto array(uint32_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint32_t)); } + auto array(uint64_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint64_t)); } + template auto array(uint16_t (&data)[N]) -> serializer& { return array(data, N); } + template auto array(uint32_t (&data)[N]) -> serializer& { return array(data, N); } + template auto array(uint64_t (&data)[N]) -> serializer& { return array(data, N); } + #endif + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; } template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return integer(value); } template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return real(value); } diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp index 5a866933..616d6232 100755 --- a/nall/string/transform/dml.hpp +++ b/nall/string/transform/dml.hpp @@ -1,7 +1,7 @@ #pragma once /* Document Markup Language (DML) v1.0 parser - * revision 0.04 + * revision 0.05 */ #include @@ -9,6 +9,11 @@ namespace nall { struct DML { + inline auto title() const -> string { return state.title; } + inline auto subtitle() const -> string { return state.subtitle; } + inline auto description() const -> string { return state.description; } + inline auto content() const -> string { return state.output; } + auto& setAllowHTML(bool allowHTML) { settings.allowHTML = allowHTML; return *this; } auto& setHost(const string& hostname) { settings.host = {hostname, "/"}; return *this; } auto& setPath(const string& pathname) { settings.path = pathname; return *this; } @@ -28,6 +33,9 @@ private: } settings; struct State { + string title; + string subtitle; + string description; string output; uint sections = 0; } state; @@ -41,12 +49,14 @@ private: }; inline auto DML::parse(const string& filedata, const string& pathname) -> string { + state = {}; settings.path = pathname; parseDocument(filedata, settings.path, 0); return state.output; } inline auto DML::parse(const string& filename) -> string { + state = {}; if(!settings.path) settings.path = Location::path(filename); string document = settings.reader ? settings.reader(filename) : string::read(filename); parseDocument(document, settings.path, 0); @@ -83,8 +93,8 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) - //title else if(block.beginsWith("! ")) { - auto name = lines.takeLeft().trimLeft("! ", 1L); - state.output.append("

", markup(name)); + state.title = lines.takeLeft().trimLeft("! ", 1L); + state.output.append("

", markup(state.title)); for(auto& line : lines) { if(!line.beginsWith("! ")) continue; state.output.append("", markup(line.trimLeft("! ", 1L)), ""); @@ -92,6 +102,14 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) - state.output.append("

\n"); } + //description + else if(block.beginsWith("? ")) { + while(lines) { + state.description.append(lines.takeLeft().trimLeft("? ", 1L), " "); + } + state.description.strip(); + } + //section else if(block.beginsWith("# ")) { if(settings.sectioned) { @@ -101,6 +119,7 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) - auto content = lines.takeLeft().trimLeft("# ", 1L).split("::", 1L).strip(); auto data = markup(content[0]); auto name = escape(content(1, data.hash())); + state.subtitle = content[0]; state.output.append("

", data); for(auto& line : lines) { if(!line.beginsWith("# ")) continue; @@ -226,13 +245,14 @@ inline auto DML::markup(const string& s) -> string { natural link, linkBase; natural embed, embedBase; + natural photo, photoBase; natural iframe, iframeBase; for(uint n = 0; n < s.size();) { char a = s[n]; char b = s[n + 1]; - if(!link && !embed && !iframe) { + if(!link && !embed && !photo && !iframe) { if(a == '*' && b == '*') { t.append(strong.flip() ? "" : ""); n += 2; continue; } if(a == '/' && b == '/') { t.append(emphasis.flip() ? "" : ""); n += 2; continue; } if(a == '_' && b == '_') { t.append(insertion.flip() ? "" : ""); n += 2; continue; } @@ -244,7 +264,15 @@ inline auto DML::markup(const string& s) -> string { if(iframe == 0 && a == '<' && b == '<') { t.append(""); iframe = 0; n += 2; continue; } - if(!embed) { + if(!embed && !link) { + if(photo == 0 && a == '[' && b == '{') { t.append("\"\""); n += 2; photo = 0; continue; } + if(photo == 1 && a == ':' && b == ':') { t.append(slice(s, photoBase, n - photoBase).replace("@/", settings.host), "\">\"");"); n += 2; photo = 0; continue; } + if(photo != 0) { n++; continue; } + } + + if(!photo && !embed) { if(link == 0 && a == '[' && b == '[') { t.append(""); link = 2; n += 2; continue; } if(link == 1 && a == ']' && b == ']') { t.append("\">", slice(s, linkBase, n - linkBase), ""); n += 2; link = 0; continue; } @@ -252,7 +280,7 @@ inline auto DML::markup(const string& s) -> string { if(link == 1 && a == '@' && b == '/') { t.append(settings.host); n += 2; continue; } } - if(!link) { + if(!photo && !link) { if(embed == 0 && a == '{' && b == '{') { t.append("\"");"); embed = 0; n += 2; continue; }