mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-19 20:19:13 +12:00
Merge branch 'master' into audio
This commit is contained in:
commit
02cba8a576
15 changed files with 194 additions and 39 deletions
10
.github/workflows/Android_Build.yml
vendored
10
.github/workflows/Android_Build.yml
vendored
|
@ -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 }}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -78,6 +78,7 @@ namespace Audio {
|
|||
|
||||
public:
|
||||
TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService);
|
||||
~TeakraDSP() override {}
|
||||
|
||||
void reset() override;
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -36,6 +36,7 @@ struct NCCH {
|
|||
};
|
||||
|
||||
u64 partitionIndex = 0;
|
||||
u64 programID = 0;
|
||||
u64 fileOffset = 0;
|
||||
|
||||
bool isNew3DS = false;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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]; }
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
135
src/lua.cpp
135
src/lua.cpp
|
@ -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
|
||||
|
|
|
@ -22,8 +22,8 @@ android {
|
|||
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
isMinifyEnabled = false
|
||||
isShrinkResources = false
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
isDebuggable = false
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
proguardFiles(
|
||||
|
|
23
src/pandroid/app/proguard-rules.pro
vendored
23
src/pandroid/app/proguard-rules.pro
vendored
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue