Fixed crash when idling with the snow effect enabled.
Added Android target to libretro port [rtretiakov]
Various nall library improvements.
This commit is contained in:
byuu 2019-09-13 22:15:11 +09:00
parent c6d90d3ff1
commit 1e626e75ef
14 changed files with 1105 additions and 3890 deletions

View File

@ -29,7 +29,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "109.2";
static const string Version = "109.3";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org";

View File

@ -91,7 +91,7 @@ auto Program::viewportRefresh() -> void {
for(; SnowMover != 0; --SnowMover) {
if(--SnowTimer == 0) {
++NumSnow;
if(NumSnow < 400) ++NumSnow;
SnowTimer = 18;
}
uint32_t i = 0;

View File

@ -0,0 +1,58 @@
LOCAL_PATH := $(call my-dir)
SRCDIR := $(LOCAL_PATH)/../../..
INCFLAGS := -I$(SRCDIR) -I$(SRCDIR)/bsnes
COREFLAGS := -fomit-frame-pointer -ffast-math -D__LIBRETRO__ $(INCFLAGS)
COREFLAGS += -DGB_INTERNAL -DDISABLE_DEBUGGER -DPLATFORM_ANDROID
GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
ifneq ($(GIT_VERSION)," unknown")
COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
endif
SRCFILES := $(SRCDIR)/bsnes/target-libretro/libretro.cpp \
$(SRCDIR)/bsnes/emulator/emulator.cpp \
$(SRCDIR)/libco/libco.c \
$(SRCDIR)/bsnes/filter/filter.cpp \
$(SRCDIR)/bsnes/lzma/lzma.cpp \
$(SRCDIR)/bsnes/sfc/interface/interface.cpp \
$(SRCDIR)/bsnes/sfc/system/system.cpp \
$(SRCDIR)/bsnes/sfc/controller/controller.cpp \
$(SRCDIR)/bsnes/sfc/cartridge/cartridge.cpp \
$(SRCDIR)/bsnes/sfc/memory/memory.cpp \
$(SRCDIR)/bsnes/sfc/cpu/cpu.cpp \
$(SRCDIR)/bsnes/sfc/smp/smp.cpp \
$(SRCDIR)/bsnes/sfc/dsp/dsp.cpp \
$(SRCDIR)/bsnes/sfc/ppu/ppu.cpp \
$(SRCDIR)/bsnes/sfc/ppu-fast/ppu.cpp \
$(SRCDIR)/bsnes/sfc/expansion/expansion.cpp \
$(SRCDIR)/bsnes/sfc/coprocessor/coprocessor.cpp \
$(SRCDIR)/bsnes/sfc/slot/slot.cpp \
$(SRCDIR)/bsnes/gb/Core/apu.c \
$(SRCDIR)/bsnes/gb/Core/camera.c \
$(SRCDIR)/bsnes/gb/Core/display.c \
$(SRCDIR)/bsnes/gb/Core/gb.c \
$(SRCDIR)/bsnes/gb/Core/joypad.c \
$(SRCDIR)/bsnes/gb/Core/mbc.c \
$(SRCDIR)/bsnes/gb/Core/memory.c \
$(SRCDIR)/bsnes/gb/Core/printer.c \
$(SRCDIR)/bsnes/gb/Core/random.c \
$(SRCDIR)/bsnes/gb/Core/rewind.c \
$(SRCDIR)/bsnes/gb/Core/save_state.c \
$(SRCDIR)/bsnes/gb/Core/sgb.c \
$(SRCDIR)/bsnes/gb/Core/sm83_cpu.c \
$(SRCDIR)/bsnes/gb/Core/symbol_hash.c \
$(SRCDIR)/bsnes/gb/Core/timing.c \
$(SRCDIR)/bsnes/processor/arm7tdmi/arm7tdmi.cpp \
$(SRCDIR)/bsnes/processor/spc700/spc700.cpp \
$(SRCDIR)/bsnes/processor/wdc65816/wdc65816.cpp
include $(CLEAR_VARS)
LOCAL_MODULE := retro
LOCAL_SRC_FILES := $(SRCFILES)
LOCAL_CPPFLAGS := -std=c++17 $(COREFLAGS)
LOCAL_CFLAGS := $(COREFLAGS)
LOCAL_LDFLAGS := -Wl,-version-script=$(SRCDIR)/bsnes/target-libretro/link.T
LOCAL_CPP_FEATURES := exceptions rtti
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,2 @@
APP_ABI := all
APP_STL := c++_static

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,10 @@ inline auto create(array_view<uint8_t> source, array_view<uint8_t> target, strin
encode(source.size()), encode(target.size()), encode(manifest.size());
for(auto& byte : manifest) write(byte);
auto sourceArray = SuffixArray(source).lrcp();
//generating lrcp() arrays for source requires O(4n) computations, and O(16m) memory,
//but it reduces find() complexity from O(n log m) to O(n + log m). and yet in practice,
//no matter how large n scales to, the O(n + log m) find() is paradoxically slower.
auto sourceArray = SuffixArray(source);
auto targetArray = SuffixArray(target).lpf();
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
@ -39,12 +42,12 @@ inline auto create(array_view<uint8_t> source, array_view<uint8_t> target, strin
while(targetReadLength) write(target[offset++]), targetReadLength--;
};
uint longestSize = max(source.size(), target.size());
uint overlap = min(source.size(), target.size());
while(outputOffset < target.size()) {
uint mode = TargetRead, longestLength = 3, longestOffset = 0;
int length = 0, offset = outputOffset;
while(offset < longestSize) {
while(offset < overlap) {
if(source[offset] != target[offset]) break;
length++, offset++;
}

View File

@ -10,7 +10,8 @@ namespace nall {
//where the first character is the empty suffix, equal to size
template<typename T>
inline auto induced_sort(const T* data, const uint size, const uint characters = 256) -> vector<int> {
inline auto induced_sort(array_view<T> data, const uint characters = 256) -> vector<int> {
const uint size = data.size();
if(size == 0) return vector<int>{0}; //required to avoid out-of-bounds accesses
if(size == 1) return vector<int>{1, 0}; //not strictly necessary; but more performant
@ -153,14 +154,14 @@ inline auto induced_sort(const T* data, const uint size, const uint characters =
}
} else {
//recurse until every character in summaryData is unique ...
summaries = induced_sort(summaryData.data(), summaryData.size() - 1, summaryCharacters);
summaries = induced_sort<int>({summaryData.data(), summaryData.size()}, summaryCharacters);
}
suffixes.fill(-1); //reuse existing buffer for accurate sort
//accurate LMS sort
getTails();
for(uint n : reverse(range(1, summaries.size()))) {
for(uint n : reverse(range(2, summaries.size()))) {
auto index = summaryOffsets[summaries[n]];
suffixes[tails[data[index]]--] = index; //advance from the tail of the bucket
}

View File

@ -4,7 +4,7 @@ namespace nall {
using uint = unsigned;
enum class Compiler : uint { Clang, GCC, Microsoft, Unknown };
enum class Platform : uint { Windows, MacOS, Linux, BSD, Unknown };
enum class Platform : uint { Windows, MacOS, Linux, BSD, Android, Unknown };
enum class API : uint { Windows, Posix, Unknown };
enum class DisplayServer : uint { Windows, Quartz, Xorg, Unknown };
enum class Architecture : uint { x86, amd64, ARM32, ARM64, PPC32, PPC64, Unknown };
@ -82,6 +82,13 @@ namespace nall {
constexpr auto platform() -> Platform { return Platform::MacOS; }
constexpr auto api() -> API { return API::Posix; }
constexpr auto display() -> DisplayServer { return DisplayServer::Quartz; }
#elif defined(__ANDROID__)
#define PLATFORM_ANDROID
#define API_POSIX
#define DISPLAY_UNKNOWN
constexpr auto platform() -> Platform { return Platform::Android; }
constexpr auto api() -> API { return API::Posix; }
constexpr auto display() -> DisplayServer { return DisplayServer::Unknown; }
#elif defined(linux) || defined(__linux__)
#define PLATFORM_LINUX
#define API_POSIX

13
nall/property.hpp Normal file
View File

@ -0,0 +1,13 @@
#if !defined(property)
#define property1(declaration) public: declaration
#define property2(declaration, getter) public: __declspec(property(get=getter)) declaration; protected: declaration##_
#define property3(declaration, getter, setter) public: __declspec(property(get=getter, put=setter)) declaration; protected: declaration##_
#define property_(_1, _2, _3, name, ...) name
#define property(...) property_(__VA_ARGS__, property3, property2, property1)(__VA_ARGS__)
#else
#undef property1
#undef property2
#undef property3
#undef property_
#undef property
#endif

View File

@ -9,6 +9,8 @@
#if defined(PLATFORM_LINUX) && __has_include(<sys/random.h>)
#include <sys/random.h>
#elif defined(PLATFORM_ANDROID) && __has_include(<sys/syscall.h>)
#include <sys/syscall.h>
#elif defined(PLATFORM_WINDOWS) && __has_include(<wincrypt.h>)
#include <wincrypt.h>
#else
@ -41,6 +43,8 @@ protected:
for(uint n : range(8)) seed = seed << 32 | (uint32_t)arc4random();
#elif defined(PLATFORM_LINUX) && __has_include(<sys/random.h>)
getrandom(&seed, 32, GRND_NONBLOCK);
#elif defined(PLATFORM_ANDROID) && __has_include(<sys/syscall.h>)
syscall(__NR_getrandom, &seed, 32, 0x0001); //GRND_NONBLOCK
#elif defined(PLATFORM_WINDOWS) && __has_include(<wincrypt.h>)
HCRYPTPROV provider;
if(CryptAcquireContext(&provider, nullptr, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
@ -63,6 +67,8 @@ namespace PRNG {
//Galois linear feedback shift register using CRC64 polynomials
struct LFSR : RNG<LFSR> {
LFSR() { seed(); }
auto seed(maybe<uint64_t> seed = {}) -> void {
lfsr = seed ? seed() : (uint64_t)randomSeed();
for(uint n : range(8)) read(); //hide the CRC64 polynomial from initial output
@ -84,6 +90,8 @@ private:
};
struct PCG : RNG<PCG> {
PCG() { seed(); }
auto seed(maybe<uint32_t> seed = {}, maybe<uint32_t> sequence = {}) -> void {
if(!seed) seed = (uint32_t)randomSeed();
if(!sequence) sequence = 0;

View File

@ -45,6 +45,7 @@ struct string_view {
inline auto operator=(const string_view& source) -> type&;
inline auto operator=(string_view&& source) -> type&;
inline explicit operator bool() const;
inline operator const char*() const;
inline auto data() const -> const char*;
inline auto size() const -> uint;

View File

@ -81,6 +81,17 @@ 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("<h1>", markup(name));
for(auto& line : lines) {
if(!line.beginsWith("! ")) continue;
state.output.append("<span>", markup(line.trimLeft("! ", 1L)), "</span>");
}
state.output.append("</h1>\n");
}
//section
else if(block.beginsWith("# ")) {
if(settings.sectioned) {
@ -90,12 +101,12 @@ 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.output.append("<h1 id=\"", name, "\">", data);
state.output.append("<h2 id=\"", name, "\">", data);
for(auto& line : lines) {
if(!line.beginsWith("# ")) continue;
state.output.append("<span>", line.trimLeft("# ", 1L), "</span>");
}
state.output.append("</h1>\n");
state.output.append("</h2>\n");
}
//header
@ -103,13 +114,13 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) -
auto content = slice(lines.takeLeft(), depth + 1).split("::", 1L).strip();
auto data = markup(content[0]);
auto name = escape(content(1, data.hash()));
if(depth <= 5) {
state.output.append("<h", depth + 1, " id=\"", name, "\">", data);
if(depth <= 4) {
state.output.append("<h", depth + 2, " id=\"", name, "\">", data);
for(auto& line : lines) {
if(count(line, '=') != depth) continue;
state.output.append("<span>", slice(line, depth + 1), "</span>");
}
state.output.append("</h", depth + 1, ">\n");
state.output.append("</h", depth + 2, ">\n");
}
}

View File

@ -69,6 +69,10 @@ auto string_view::operator=(string_view&& source) -> type& {
return *this;
};
string_view::operator bool() const {
return _size > 0;
}
string_view::operator const char*() const {
return _data;
}

View File

@ -71,8 +71,8 @@ suffix_array_plcp:
plcp = [1,0,0,3,2,2,1,1,0,0]
suffix_array_lrcp:
llcp = [0,0,0,3,1,0,0,0,0,1] => llcp[m] == lcp(l, m)
rlcp = [0,1,1,1,2,0,2,0,0,0] => rlcp[m] == lcp(m, r)
llcp = [0,0,0,3,0,2,0,2,0,0] => llcp[m] == lcp(l, m)
rlcp = [0,1,1,1,0,0,0,0,0,0] => rlcp[m] == lcp(m, r)
suffix_array_lpf:
lengths = [0,0,1,3,2,1,0,2,1,0]
@ -93,7 +93,7 @@ suffix_array_lpf:
// suffix array via induced sorting
// O(n)
inline auto suffix_array(array_view<uint8_t> input) -> vector<int> {
return induced_sort(input.data(), input.size());
return induced_sort(input);
}
// inverse
@ -192,17 +192,17 @@ inline auto suffix_array_lrcp(vector<int>& llcp, vector<int>& rlcp, array_view<i
rlcp.reset(), rlcp.reallocate(size + 1);
function<int (int, int)> recurse = [&](int l, int r) -> int {
if(l == r - 1) {
if(r > size) return 0;
if(lcp) return lcp[r];
return plcp[sa[r]];
if(l >= r - 1) {
if(l >= size) return 0;
if(lcp) return lcp[l];
return plcp[sa[l]];
}
int m = l + r >> 1;
llcp[m] = recurse(l, m);
rlcp[m] = recurse(m, r);
return min(llcp[m], rlcp[m]);
llcp[m - 1] = recurse(l, m);
rlcp[m - 1] = recurse(m, r);
return min(llcp[m - 1], rlcp[m - 1]);
};
recurse(0, size + 1);
recurse(1, size + 1);
llcp[0] = 0;
rlcp[0] = 0;
@ -274,6 +274,8 @@ inline auto suffix_array_find(int& length, int& offset, array_view<int> sa, arra
if(k == match.size()) return true;
}
if(k == match.size() || s + k == input.size()) k--;
if(match[k] < input[s + k]) {
r = m;
} else {
@ -304,6 +306,8 @@ inline auto suffix_array_find(int& length, int& offset, array_view<int> llcp, ar
if(k == match.size()) return true;
}
if(k == match.size() || s + k == input.size()) k--;
if(match[k] < input[s + k]) {
r = m;
k = min(k, llcp[m]);