Merge branch 'master' into audio

This commit is contained in:
wheremyfoodat 2024-02-24 00:05:42 +00:00 committed by GitHub
commit 02cba8a576
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 194 additions and 39 deletions

View file

@ -45,8 +45,11 @@ jobs:
git apply ./.github/gles.patch
# Build the project with CMake
cmake --build ${{github.workspace}}/build --config ${{ env.BUILD_TYPE }}
# Move the generated library to the appropriate location
# Strip the generated library and move it to the appropriate location
${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --strip-unneeded ./build/libAlber.so
mv ./build/libAlber.so ./src/pandroid/app/src/main/jniLibs/x86_64/
# Build the Android app with Gradle
cd src/pandroid
./gradlew assemble${{ env.BUILD_TYPE }}
@ -97,8 +100,11 @@ jobs:
git apply ./.github/gles.patch
# Build the project with CMake
cmake --build ${{github.workspace}}/build --config ${{ env.BUILD_TYPE }}
# Move the generated library to the appropriate location
# Strip the generated library and move it to the appropriate location
${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --strip-unneeded ./build/libAlber.so
mv ./build/libAlber.so ./src/pandroid/app/src/main/jniLibs/arm64-v8a/
# Build the Android app with Gradle
cd src/pandroid
./gradlew assemble${{ env.BUILD_TYPE }}

View file

@ -40,6 +40,7 @@ namespace Audio {
enum class Type { Null, Teakra };
DSPCore(Memory& mem, Scheduler& scheduler, DSPService& dspService)
: mem(mem), scheduler(scheduler), dspService(dspService) {}
virtual ~DSPCore() {}
virtual void reset() = 0;
virtual void runAudioFrame() = 0;

View file

@ -24,6 +24,7 @@ namespace Audio {
public:
NullDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService) : DSPCore(mem, scheduler, dspService) {}
~NullDSP() override {}
void reset() override;
void runAudioFrame() override;

View file

@ -78,6 +78,7 @@ namespace Audio {
public:
TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService);
~TeakraDSP() override {}
void reset() override;

View file

@ -135,6 +135,7 @@ class Emulator {
ServiceManager& getServiceManager() { return kernel.getServiceManager(); }
LuaManager& getLua() { return lua; }
Scheduler& getScheduler() { return scheduler; }
Memory& getMemory() { return memory; }
RendererType getRendererType() const { return config.rendererType; }
Renderer* getRenderer() { return gpu.getRenderer(); }

View file

@ -36,6 +36,7 @@ struct NCCH {
};
u64 partitionIndex = 0;
u64 programID = 0;
u64 fileOffset = 0;
bool isNew3DS = false;

View file

@ -2,7 +2,6 @@
#include <string>
#include "helpers.hpp"
#include "memory.hpp"
// The kinds of events that can cause a Lua call.
// Frame: Call program on frame end
@ -11,6 +10,8 @@ enum class LuaEvent {
Frame,
};
class Emulator;
#ifdef PANDA3DS_ENABLE_LUA
extern "C" {
#include <lauxlib.h>
@ -30,9 +31,9 @@ class LuaManager {
public:
// For Lua we must have some global pointers to our emulator objects to use them in script code via thunks. See the thunks in lua.cpp as an
// example
static Memory* g_memory;
static Emulator* g_emulator;
LuaManager(Memory& mem) { g_memory = &mem; }
LuaManager(Emulator& emulator) { g_emulator = &emulator; }
void close();
void initialize();
@ -51,7 +52,7 @@ class LuaManager {
#else // Lua not enabled, Lua manager does nothing
class LuaManager {
public:
LuaManager(Memory& mem) {}
LuaManager(Emulator& emulator) {}
void close() {}
void initialize() {}

View file

@ -275,6 +275,8 @@ private:
// File handle for reading the loaded ncch
IOFile CXIFile;
std::optional<u64> getProgramID();
u8* getDSPMem() { return dspRam; }
u8* getDSPDataMem() { return &dspRam[DSP_DATA_MEMORY_OFFSET]; }
u8* getDSPCodeMem() { return &dspRam[DSP_CODE_MEMORY_OFFSET]; }

View file

@ -32,7 +32,7 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
size = u64(*(u32*)&header[0x104]) * mediaUnit; // TODO: Maybe don't type pun because big endian will break
exheaderSize = *(u32*)&header[0x180];
const u64 programID = *(u64*)&header[0x118];
programID = *(u64*)&header[0x118];
// Read NCCH flags
secondaryKeySlot = header[0x188 + 3];

View file

@ -525,3 +525,13 @@ void Memory::copySharedFont(u8* pointer) {
auto font = fonts.open("CitraSharedFontUSRelocated.bin");
std::memcpy(pointer, font.begin(), font.size());
}
std::optional<u64> Memory::getProgramID() {
auto cxi = getCXI();
if (cxi) {
return cxi->programID;
}
return std::nullopt;
}

View file

@ -37,7 +37,8 @@ void NwmUdsService::initializeWithVersion(u32 messagePointer) {
initialized = true;
mem.write32(messagePointer + 4, Result::Success);
// Stubbed to fail temporarily, since some games will break trying to establish networks otherwise
mem.write32(messagePointer + 4, Result::FailurePlaceholder);
mem.write32(messagePointer + 8, 0);
mem.write32(messagePointer + 12, eventHandle.value());
}

View file

@ -18,7 +18,7 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1;
Emulator::Emulator()
: config(getConfigPath()), kernel(cpu, memory, gpu, config), cpu(memory, kernel, *this), gpu(memory, config), memory(cpu.getTicksRef(), config),
cheats(memory, kernel.getServiceManager().getHID()), lua(memory), running(false), programRunning(false)
cheats(memory, kernel.getServiceManager().getHID()), lua(*this), running(false), programRunning(false)
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
,
httpServer(this)

View file

@ -1,4 +1,5 @@
#ifdef PANDA3DS_ENABLE_LUA
#include "emulator.hpp"
#include "lua_manager.hpp"
#ifndef __ANDROID__
@ -103,28 +104,105 @@ void LuaManager::reset() {
// Initialize C++ thunks for Lua code to call here
// All code beyond this point is terrible and full of global state, don't judge
Memory* LuaManager::g_memory = nullptr;
Emulator* LuaManager::g_emulator = nullptr;
#define MAKE_MEMORY_FUNCTIONS(size) \
static int read##size##Thunk(lua_State* L) { \
const u32 vaddr = (u32)lua_tonumber(L, 1); \
lua_pushnumber(L, LuaManager::g_memory->read##size(vaddr)); \
lua_pushnumber(L, LuaManager::g_emulator->getMemory().read##size(vaddr)); \
return 1; \
} \
static int write##size##Thunk(lua_State* L) { \
const u32 vaddr = (u32)lua_tonumber(L, 1); \
const u##size value = (u##size)lua_tonumber(L, 2); \
LuaManager::g_memory->write##size(vaddr, value); \
LuaManager::g_emulator->getMemory().write##size(vaddr, value); \
return 0; \
}
MAKE_MEMORY_FUNCTIONS(8)
MAKE_MEMORY_FUNCTIONS(16)
MAKE_MEMORY_FUNCTIONS(32)
MAKE_MEMORY_FUNCTIONS(64)
#undef MAKE_MEMORY_FUNCTIONS
static int getAppIDThunk(lua_State* L) {
std::optional<u64> id = LuaManager::g_emulator->getMemory().getProgramID();
// If the app has an ID, return true + its ID
// Otherwise return false and 0 as the ID
if (id.has_value()) {
lua_pushboolean(L, 1); // Return true
lua_pushnumber(L, u32(*id)); // Return bottom 32 bits
lua_pushnumber(L, u32(*id >> 32)); // Return top 32 bits
} else {
lua_pushboolean(L, 0); // Return false
// Return no ID
lua_pushnumber(L, 0);
lua_pushnumber(L, 0);
}
return 3;
}
static int pauseThunk(lua_State* L) {
LuaManager::g_emulator->pause();
return 0;
}
static int resumeThunk(lua_State* L) {
LuaManager::g_emulator->resume();
return 0;
}
static int resetThunk(lua_State* L) {
LuaManager::g_emulator->reset(Emulator::ReloadOption::Reload);
return 0;
}
static int loadROMThunk(lua_State* L) {
// Path argument is invalid, report that loading failed and exit
if (lua_type(L, -1) != LUA_TSTRING) {
lua_pushboolean(L, 0);
return 1;
}
size_t pathLength;
const char* const str = lua_tolstring(L, -1, &pathLength);
const auto path = std::filesystem::path(std::string(str, pathLength));
// Load ROM and reply if it succeeded or not
lua_pushboolean(L, LuaManager::g_emulator->loadROM(path) ? 1 : 0);
return 1;
}
static int getButtonsThunk(lua_State* L) {
auto buttons = LuaManager::g_emulator->getServiceManager().getHID().getOldButtons();
lua_pushinteger(L, static_cast<lua_Integer>(buttons));
return 1;
}
static int getCirclepadThunk(lua_State* L) {
auto& hid = LuaManager::g_emulator->getServiceManager().getHID();
s16 x = hid.getCirclepadX();
s16 y = hid.getCirclepadY();
lua_pushinteger(L, static_cast<lua_Number>(x));
lua_pushinteger(L, static_cast<lua_Number>(y));
return 2;
}
static int getButtonThunk(lua_State* L) {
auto& hid = LuaManager::g_emulator->getServiceManager().getHID();
// This function accepts a mask. You can use it to check if one or more buttons are pressed at a time
const u32 mask = (u32)lua_tonumber(L, 1);
const bool result = (hid.getOldButtons() & mask) == mask;
// Return whether the selected buttons are all pressed
lua_pushboolean(L, result ? 1 : 0);
return 1;
}
// clang-format off
static constexpr luaL_Reg functions[] = {
{ "__read8", read8Thunk },
@ -135,6 +213,14 @@ static constexpr luaL_Reg functions[] = {
{ "__write16", write16Thunk },
{ "__write32", write32Thunk },
{ "__write64", write64Thunk },
{ "__getAppID", getAppIDThunk },
{ "__pause", pauseThunk},
{ "__resume", resumeThunk},
{ "__reset", resetThunk},
{ "__loadROM", loadROMThunk},
{ "__getButtons", getButtonsThunk},
{ "__getCirclepad", getCirclepadThunk},
{ "__getButton", getButtonThunk},
{ nullptr, nullptr },
};
// clang-format on
@ -150,7 +236,35 @@ void LuaManager::initializeThunks() {
write16 = function(addr, value) GLOBALS.__write16(addr, value) end,
write32 = function(addr, value) GLOBALS.__write32(addr, value) end,
write64 = function(addr, value) GLOBALS.__write64(addr, value) end,
getAppID = function()
local ffi = require("ffi")
result, low, high = GLOBALS.__getAppID()
id = bit.bor(ffi.cast("uint64_t", low), (bit.lshift(ffi.cast("uint64_t", high), 32)))
return result, id
end,
pause = function() GLOBALS.__pause() end,
resume = function() GLOBALS.__resume() end,
reset = function() GLOBALS.__reset() end,
loadROM = function(path) return GLOBALS.__loadROM(path) end,
getButtons = function() return GLOBALS.__getButtons() end,
getButton = function(button) return GLOBALS.__getButton(button) end,
getCirclepad = function() return GLOBALS.__getCirclepad() end,
Frame = __Frame,
ButtonA = __ButtonA,
ButtonB = __ButtonB,
ButtonX = __ButtonX,
ButtonY = __ButtonY,
ButtonL = __ButtonL,
ButtonR = __ButtonR,
ButtonUp = __ButtonUp,
ButtonDown = __ButtonDown,
ButtonLeft = __ButtonLeft,
ButtonRight= __ButtonRight,
}
)";
@ -160,8 +274,21 @@ void LuaManager::initializeThunks() {
};
luaL_register(L, "GLOBALS", functions);
// Add values for event enum
addIntConstant(LuaEvent::Frame, "__Frame");
// Add enums for 3DS keys
addIntConstant(HID::Keys::A, "__ButtonA");
addIntConstant(HID::Keys::B, "__ButtonB");
addIntConstant(HID::Keys::X, "__ButtonX");
addIntConstant(HID::Keys::Y, "__ButtonY");
addIntConstant(HID::Keys::Up, "__ButtonUp");
addIntConstant(HID::Keys::Down, "__ButtonDown");
addIntConstant(HID::Keys::Left, "__ButtonLeft");
addIntConstant(HID::Keys::Right, "__ButtonRight");
addIntConstant(HID::Keys::L, "__ButtonL");
addIntConstant(HID::Keys::R, "__ButtonR");
// Call our Lua runtime initialization before any Lua script runs
luaL_loadstring(L, runtimeInit);
int ret = lua_pcall(L, 0, 0, 0); // tell Lua to run the script

View file

@ -22,8 +22,8 @@ android {
buildTypes {
getByName("release") {
isMinifyEnabled = false
isShrinkResources = false
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
signingConfig = signingConfigs.getByName("debug")
proguardFiles(

View file

@ -1,16 +1,19 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# Pandroid Proguard Rules
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Keep all JNI and C++ related classes and methods
-keepclasseswithmembernames class * {
native <methods>;
}
# Keep all native libraries and their methods
-keep class * {
native <methods>;
}
# Keep all classes in the specified package and its subpackages
-keep class com.panda3ds.pandroid.** {*;}
# Uncomment this to preserve the line number information for
# debugging stack traces.