From d2a31b2053ce8400e9281971bc079b0dd3708093 Mon Sep 17 00:00:00 2001 From: Gabriel Correia Date: Mon, 22 Jan 2024 22:27:01 -0300 Subject: [PATCH] `Project`: Makes several corrections; there are still more to come - JNIEnv is now correctly propagated throughout the entire backend - Fixed improper access to JNIEnv* objects through an incorrect thread - Addresses memory leaks in objects (JNIString, BiosInfo, among others) - Corrects mishandling of BIOS files in both the frontend and backend - Fixes interface crashes - Reduces memory consumption - Improves the logging system (now the parser can check the syntax of the text format before compilation) - Enhances security in the code (libfmt) --- .idea/inspectionProfiles/Project_Default.xml | 2 + app/src/main/CMakeLists.txt | 3 +- app/src/main/cpp/bios_jni.cpp | 12 +- app/src/main/cpp/cosmic/common/app.cpp | 6 +- app/src/main/cpp/cosmic/common/except.cpp | 39 ++++++ app/src/main/cpp/cosmic/common/except.h | 30 ++-- app/src/main/cpp/cosmic/common/global.h | 3 + app/src/main/cpp/cosmic/common/logger.h | 33 ++--- .../cpp/cosmic/creeper/ee/mipsiv_opcodes.cpp | 12 +- app/src/main/cpp/cosmic/fs/bios_loader.cpp | 10 +- app/src/main/cpp/cosmic/fs/bios_loader.h | 6 +- .../main/cpp/cosmic/gpu/exhibition_engine.cpp | 13 +- .../main/cpp/cosmic/gpu/exhibition_engine.h | 3 +- .../main/cpp/cosmic/gpu/graphics_layer.cpp | 30 ++-- app/src/main/cpp/cosmic/hle/bios_class.cpp | 30 ---- app/src/main/cpp/cosmic/hle/bios_info.cpp | 35 +++++ .../cosmic/hle/{bios_class.h => bios_info.h} | 5 +- app/src/main/cpp/cosmic/hle/bios_patch.h | 6 +- app/src/main/cpp/cosmic/hle/group_mgr.cpp | 33 +++-- app/src/main/cpp/cosmic/hle/group_mgr.h | 5 +- app/src/main/cpp/cosmic/iop/iop_core.cpp | 2 +- .../main/cpp/cosmic/java/device_handler.cpp | 5 +- app/src/main/cpp/cosmic/java/device_handler.h | 2 - app/src/main/cpp/cosmic/java/env.h | 52 +++++++ app/src/main/cpp/cosmic/java/jclasses.cpp | 47 +++++-- app/src/main/cpp/cosmic/java/jclasses.h | 53 +++----- app/src/main/cpp/cosmic/os/system_state.cpp | 17 ++- app/src/main/cpp/cosmic/os/system_state.h | 128 ++++++++++-------- app/src/main/cpp/cosmic/vm/emu_vm.cpp | 9 +- app/src/main/cpp/cosmic/vm/emu_vm.h | 2 +- app/src/main/cpp/emu_user.cpp | 4 +- app/src/main/cpp/jvm_comm.cpp | 2 +- .../main/java/emu/cosmic/EmulationActivity.kt | 21 +++ app/src/main/java/emu/cosmic/data/BiosInfo.kt | 18 ++- .../java/emu/cosmic/data/CosmicSettings.kt | 15 +- .../java/emu/cosmic/helpers/BiosHelper.kt | 7 +- .../java/emu/cosmic/settings/BiosActivity.kt | 5 +- app/src/main/res/values/strings.xml | 11 +- 38 files changed, 455 insertions(+), 261 deletions(-) create mode 100644 app/src/main/cpp/cosmic/common/except.cpp delete mode 100644 app/src/main/cpp/cosmic/hle/bios_class.cpp create mode 100644 app/src/main/cpp/cosmic/hle/bios_info.cpp rename app/src/main/cpp/cosmic/hle/{bios_class.h => bios_info.h} (86%) create mode 100644 app/src/main/cpp/cosmic/java/env.h diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 5e77455f..0d50a6d2 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,7 +1,9 @@ \ No newline at end of file diff --git a/app/src/main/CMakeLists.txt b/app/src/main/CMakeLists.txt index 488084e0..b0eb39a3 100644 --- a/app/src/main/CMakeLists.txt +++ b/app/src/main/CMakeLists.txt @@ -22,6 +22,7 @@ set(COSMIC_MISC_DIR ${CMAKE_SOURCE_DIR}/cpp) target_sources(cosmic PRIVATE ${COSMIC_DIR}/common/app.cpp ${COSMIC_DIR}/common/logger.cpp + ${COSMIC_DIR}/common/except.cpp ${COSMIC_DIR}/cpu/cyclic32.cpp ${COSMIC_DIR}/cpu/verify_features.cpp ${COSMIC_DIR}/engine/ee_core.cpp @@ -63,7 +64,7 @@ target_sources(cosmic PRIVATE ${COSMIC_DIR}/vu/vif_fifo.cpp ${COSMIC_DIR}/hle/bios_patch.cpp ${COSMIC_DIR}/hle/group_mgr.cpp - ${COSMIC_DIR}/hle/bios_class.cpp + ${COSMIC_DIR}/hle/bios_info.cpp ${COSMIC_DIR}/hle/syscall_gate.cpp ${COSMIC_DIR}/fs/bios_loader.cpp ${COSMIC_DIR}/iop/iop_core.cpp diff --git a/app/src/main/cpp/bios_jni.cpp b/app/src/main/cpp/bios_jni.cpp index dfae8bfc..4a0d0ab6 100644 --- a/app/src/main/cpp/bios_jni.cpp +++ b/app/src/main/cpp/bios_jni.cpp @@ -7,22 +7,21 @@ extern "C" JNIEXPORT jobject JNICALL Java_emu_cosmic_helpers_BiosHelper_00024Companion_addBios(JNIEnv* env, jobject thiz, jobject descriptor, jint position) { - cosmic::hle::BiosInfo info{env}; + cosmic::hle::BiosInfo info{}; info.position = position; + auto biosHld{AFileDescriptor_getFd(env, descriptor)}; auto biosMgr{cosmic::app->getBiosMgr()}; - auto object{info.createInstance()}; cosmic::i32 find[2]{biosHld, 0}; + auto object{info.createInstance()}; if (biosMgr->isAlreadyAdded(find)) { biosMgr->loadBiosBy(object, find, false); - info.fillInstance(object); return object; } - info.chkAndLoad(biosHld); + info.chkAndLoad(biosHld); biosMgr->storeAndFill(object, std::move(info)); - return object; } extern "C" @@ -30,6 +29,7 @@ JNIEXPORT jint JNICALL Java_emu_cosmic_helpers_BiosHelper_00024Companion_setBios(JNIEnv* env, jobject thiz, jint pos) { auto group{cosmic::app->getBiosMgr()}; cosmic::i32 by[2]{0, pos}; + return group->choice(by, true); } extern "C" @@ -41,7 +41,9 @@ Java_emu_cosmic_helpers_BiosHelper_00024Companion_removeBios(JNIEnv* env, jobjec } auto group{cosmic::app->getBiosMgr()}; jint* mangled{env->GetIntArrayElements(posFd, nullptr)}; + bool hasRemoved{group->rmFromStorage(mangled)}; + env->ReleaseIntArrayElements(posFd, mangled, 0); return hasRemoved; } diff --git a/app/src/main/cpp/cosmic/common/app.cpp b/app/src/main/cpp/cosmic/common/app.cpp index 98287340..336f7a5c 100644 --- a/app/src/main/cpp/cosmic/common/app.cpp +++ b/app/src/main/cpp/cosmic/common/app.cpp @@ -12,6 +12,8 @@ namespace cosmic { std::shared_ptr user; std::shared_ptr app; + thread_local java::CosmicEnv cosmicEnv; + CoreApplication::CoreApplication() : simulated(std::make_shared()) { @@ -26,8 +28,8 @@ namespace cosmic { user->success("Device {} accepted as the host device, Android API {}", getDeviceName(), apiLevel); - scene = std::make_shared(device->android); - vm = std::make_unique(device->android, simulated, scene); + scene = std::make_shared(); + vm = std::make_unique(simulated, scene); } std::shared_ptr CoreApplication::getBiosMgr() { auto group{vm->biosHigh->group}; diff --git a/app/src/main/cpp/cosmic/common/except.cpp b/app/src/main/cpp/cosmic/common/except.cpp new file mode 100644 index 00000000..8c0f8f56 --- /dev/null +++ b/app/src/main/cpp/cosmic/common/except.cpp @@ -0,0 +1,39 @@ +#include +#include + +namespace cosmic { + jclass exceptionActivity{}; + CosmicException::CosmicException(const std::string& format) : + std::runtime_error(format) { + user->error("{}", format); + + msg = cosmicEnv->NewStringUTF(format.c_str()); + title = lookupByActivity(); + alertUser(); + } + jstring CosmicException::lookupByActivity() { + const jclass emulation{cosmicEnv->FindClass("emu/cosmic/EmulationActivity$Companion")}; + if (cosmicEnv->IsSameObject(exceptionActivity, emulation)) { + return cosmicEnv->NewStringUTF("Emulation Scene"); + } + return cosmicEnv->NewStringUTF("General Exception"); + } + + void CosmicException::alertUser() { + alert = cosmicEnv->GetMethodID(exceptionActivity, + "displayAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); + + if (alert) { + cosmicEnv->CallStaticVoidMethod(exceptionActivity, alert, title, msg); + } + cosmicEnv->DeleteLocalRef(title); + cosmicEnv->DeleteLocalRef(msg); + } + + void CosmicException::setExceptionClass(jobject super) { + const jclass emuClass{cosmicEnv->FindClass("emu/cosmic/EmulationActivity")}; + if (cosmicEnv->IsInstanceOf(super, emuClass)) { + exceptionActivity = cosmicEnv->FindClass("emu/cosmic/EmulationActivity$Companion"); + } + } +} \ No newline at end of file diff --git a/app/src/main/cpp/cosmic/common/except.h b/app/src/main/cpp/cosmic/common/except.h index c23580d6..5508326a 100644 --- a/app/src/main/cpp/cosmic/common/except.h +++ b/app/src/main/cpp/cosmic/common/except.h @@ -3,24 +3,30 @@ #include #include #include + +#include namespace cosmic { - class FatalError : public std::runtime_error { + class CosmicException : public std::runtime_error { protected: - template - FatalError(const T& format, Args&&... args) - : std::runtime_error(fmt::format(fmt::runtime(format), args...)) {} - template - FatalError(const T& format) - : std::runtime_error(format) {} + CosmicException(const std::string& format); + + public: + static void setExceptionClass(jobject super); + private: + jstring lookupByActivity(); + void alertUser(); + + jstring msg{}; + jstring title{}; + jmethodID alert{}; }; #define DECLARE_EXCEPTION_TYPE(name, tag)\ - class name : FatalError {\ + class name : public CosmicException {\ public:\ - template \ - name(T& format, Args&&... args) : FatalError("(" tag ") " + std::string(format), args...) {}\ - template \ - name(T& format) : FatalError("(" tag ") " + std::string(format)) {}\ + template \ + name(fmt::format_string format, Args&&... args) :\ + CosmicException("(" tag ") " + fmt::format(format, std::forward(args)...)) {}\ } DECLARE_EXCEPTION_TYPE(Cop0Fail, "Cop0"); diff --git a/app/src/main/cpp/cosmic/common/global.h b/app/src/main/cpp/cosmic/common/global.h index eda1d899..3a669a84 100644 --- a/app/src/main/cpp/cosmic/common/global.h +++ b/app/src/main/cpp/cosmic/common/global.h @@ -3,8 +3,11 @@ #include #include #include +#include namespace cosmic { extern std::unique_ptr device; extern std::shared_ptr user; extern std::shared_ptr app; + + extern thread_local java::CosmicEnv cosmicEnv; } diff --git a/app/src/main/cpp/cosmic/common/logger.h b/app/src/main/cpp/cosmic/common/logger.h index ac2fa58e..c80da876 100644 --- a/app/src/main/cpp/cosmic/common/logger.h +++ b/app/src/main/cpp/cosmic/common/logger.h @@ -17,36 +17,37 @@ namespace cosmic { class GlobalLogger { public: GlobalLogger(); - template - void bind(LoggerLevel msgLevel, const T& format, Args&&... args) { + template + void bind(LoggerLevel msgLevel, fmt::format_string& format, Args&&... args) { for (auto deny : disableLevels) { - if (deny == msgLevel) + if (deny == msgLevel) { return; + } } fmt::format_to(std::back_inserter(out), "{}", prodPrefix(msgLevel)); - fmt::format_to(std::back_inserter(out), fmt::runtime(format), args...); + fmt::format_to(std::back_inserter(out), fmt::runtime(format), std::forward(args)...); fmt::format_to(std::back_inserter(out), "\n"); __android_log_write(static_cast(msgLevel), tag, out.data()); out.clear(); } - template - void success(const T& format, Args&&... args) { - bind(Verbose, format, args...); + template + void success(fmt::format_string format, Args&&... args) { + bind(Verbose, format, std::forward(args)...); } - template - void info(const T& format, Args&&... args) { - bind(Info, format, args...); + template + void info(fmt::format_string format, Args&&... args) { + bind(Info, format, std::forward(args)...); } - template - void debug(const T& format, Args&&... args) { - bind(Debug, format, args...); + template + void debug(fmt::format_string format, Args&&... args) { + bind(Debug, format, std::forward(args)...); } - template - void error(const T& format, Args&&... args) { - bind(Error, format, args...); + template + void error(fmt::format_string format, Args&&... args) { + bind(Error, format, std::forward(args)...); } [[noreturn]] static void cause(const char* fail) { __android_log_assert(fail, tag, "Assertion with a cause, execution flow has been broken"); diff --git a/app/src/main/cpp/cosmic/creeper/ee/mipsiv_opcodes.cpp b/app/src/main/cpp/cosmic/creeper/ee/mipsiv_opcodes.cpp index d62c6cfb..08b5e6d0 100644 --- a/app/src/main/cpp/cosmic/creeper/ee/mipsiv_opcodes.cpp +++ b/app/src/main/cpp/cosmic/creeper/ee/mipsiv_opcodes.cpp @@ -81,21 +81,25 @@ namespace cosmic::creeper::ee { return {}; } - [[maybe_unused]] thread_local std::array translatedGPRs{"Unk", "Unk", "Unk"}; + thread_local std::array translatedGprs{"Unk", "Unk", "Unk"}; InvokeOpInfo MipsIvInterpreter::execBlackBox(u32 opcode) { InvokeOpInfo decode{}; std::array operands{}; for (u8 opi{}; opi < 3; opi++) { operands[opi] = (opcode >> (11 + opi * 5)) & 0x1f; #if TRANSLATE_REGISTERS - translatedGPRs[opi] = gprsId[operands.at(opi)]; + translatedGprs[opi] = gprsId[operands.at(opi)]; #endif } #if TRANSLATE_REGISTERS - user->debug("(Mips FETCH) Opcode # {} PC # {} Decoded # 11, 16, 21: {}", - opcode, *cpu.eePc, fmt::join(translatedGPRs, " - ")); + user->debug("(Mips FETCH) Opcode # {} pc # {} decoded # 11, 16, 21: {}", + opcode, *cpu->eePc, fmt::join(translatedGprs, " - ")); #endif decode.ops = Operands(opcode, operands); + decode.execute = [](InvokeOpInfo& err) { + throw AppFail("Invalid or unrecognized opcode {:#x}, parameters: {}", err.ops.inst, + fmt::join(err.ops.gprs, "; ")); + }; switch (opcode >> 26) { case SpecialOpcodes: decode.execute = execSpecial(opcode, decode); break; diff --git a/app/src/main/cpp/cosmic/fs/bios_loader.cpp b/app/src/main/cpp/cosmic/fs/bios_loader.cpp index 1cad3f49..2d584175 100644 --- a/app/src/main/cpp/cosmic/fs/bios_loader.cpp +++ b/app/src/main/cpp/cosmic/fs/bios_loader.cpp @@ -20,7 +20,7 @@ namespace cosmic::fs { void BiosLoader::triggerBios(hle::BiosInfo& info) { biosf = info.fd; } - bool BiosLoader::fetchBiosInfo(JNIEnv* android, hle::BiosInfo& bios) { + bool BiosLoader::fetchBiosInfo(hle::BiosInfo& bios) { if (!romHeader) romHeader = std::make_unique>(hdrSize); @@ -36,7 +36,7 @@ namespace cosmic::fs { } bios.dataCRC = cpu::check32(romGroup); - fillVersion(android, bios, std::span{BitCast(romGroup.data()), romGroup.size()}); + fillVersion(bios, std::span{BitCast(romGroup.data()), romGroup.size()}); return true; } bool BiosLoader::isABios() { @@ -87,7 +87,7 @@ namespace cosmic::fs { return true; } - void BiosLoader::fillVersion(JNIEnv* android, hle::BiosInfo& bios, std::span info) { + void BiosLoader::fillVersion(hle::BiosInfo& bios, std::span info) { using namespace ranges::views; const std::string month{&info[10], 2}; @@ -106,8 +106,8 @@ namespace cosmic::fs { fmt::join(info | drop(8) | take(6), ""))}; // 12345678–123456 - bios.dspName = java::JniString(android, biosName); - bios.details = java::JniString(android, biosDetails); + bios.dspName = java::JniString(biosName); + bios.details = java::JniString(biosDetails); } } diff --git a/app/src/main/cpp/cosmic/fs/bios_loader.h b/app/src/main/cpp/cosmic/fs/bios_loader.h index ac1aa4fb..6cd73ee7 100644 --- a/app/src/main/cpp/cosmic/fs/bios_loader.h +++ b/app/src/main/cpp/cosmic/fs/bios_loader.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace cosmic::fs { @@ -20,7 +20,7 @@ namespace cosmic::fs { static constexpr u16 hdrSize{0x3000}; BiosLoader() = default; - bool fetchBiosInfo(JNIEnv* android, hle::BiosInfo& bios); + bool fetchBiosInfo(hle::BiosInfo& bios); void placeBios(std::span here); void triggerBios(hle::BiosInfo& info); private: @@ -28,7 +28,7 @@ namespace cosmic::fs { Ref getModule(const std::string model); bool loadVersionInfo(Ref entry, std::span info); - void fillVersion(JNIEnv* android, hle::BiosInfo& bios, std::span info); + void fillVersion(hle::BiosInfo& bios, std::span info); DescriptorRaii biosf{}; std::unique_ptr> romHeader; diff --git a/app/src/main/cpp/cosmic/gpu/exhibition_engine.cpp b/app/src/main/cpp/cosmic/gpu/exhibition_engine.cpp index a299862a..ffaa7c6e 100644 --- a/app/src/main/cpp/cosmic/gpu/exhibition_engine.cpp +++ b/app/src/main/cpp/cosmic/gpu/exhibition_engine.cpp @@ -1,24 +1,25 @@ #include #include #include +#include namespace cosmic::gpu { - ExhibitionEngine::ExhibitionEngine(JNIEnv* env) : associated(env) { + ExhibitionEngine::ExhibitionEngine() { } ExhibitionEngine::~ExhibitionEngine() { if (globalSurface) - associated->DeleteGlobalRef(globalSurface); + cosmicEnv->DeleteGlobalRef(globalSurface); } void ExhibitionEngine::inheritSurface(jobject surface) { - if (associated->IsSameObject(surface, nullptr)) + if (cosmicEnv->IsSameObject(surface, nullptr)) return; if (globalSurface) - associated->DeleteGlobalRef(globalSurface); + cosmicEnv->DeleteGlobalRef(globalSurface); - globalSurface = associated->NewGlobalRef(surface); + globalSurface = cosmicEnv->NewGlobalRef(surface); if (!globalSurface) { throw GpuFail("A Surface is required for us to control and inherit to the screen"); } - window = ANativeWindow_fromSurface(associated, globalSurface); + window = ANativeWindow_fromSurface(*cosmicEnv, globalSurface); ANativeWindow_acquire(window); if (scene.notifySurfaceChange) scene.notifySurfaceChange(scene, surface); diff --git a/app/src/main/cpp/cosmic/gpu/exhibition_engine.h b/app/src/main/cpp/cosmic/gpu/exhibition_engine.h index 74cb95e6..ca0d7f87 100644 --- a/app/src/main/cpp/cosmic/gpu/exhibition_engine.h +++ b/app/src/main/cpp/cosmic/gpu/exhibition_engine.h @@ -7,12 +7,11 @@ namespace cosmic::gpu { class ExhibitionEngine { public: - ExhibitionEngine(JNIEnv* env); + ExhibitionEngine(); ~ExhibitionEngine(); void inheritSurface(jobject surface); private: jobject globalSurface{}; - JNIEnv* associated{}; ANativeWindow* window{}; RenderApi graphics{HardwareOpenGL}; diff --git a/app/src/main/cpp/cosmic/gpu/graphics_layer.cpp b/app/src/main/cpp/cosmic/gpu/graphics_layer.cpp index 35725a3e..40af733b 100644 --- a/app/src/main/cpp/cosmic/gpu/graphics_layer.cpp +++ b/app/src/main/cpp/cosmic/gpu/graphics_layer.cpp @@ -1,10 +1,10 @@ #include #include namespace cosmic::gpu { - static void displayVersion(GraphicsLayer& gpu) { + static void displayVersion(Ref gpu) { #if !defined(NDEBUG) - if (gpu.graphicsApi == HardwareVulkan) { - u32 version{gpu.app->enumerateInstanceVersion()}; + if (gpu->graphicsApi == HardwareVulkan) { + u32 version{gpu->app->enumerateInstanceVersion()}; std::array vkVA64{ version >> 22 & 0x3ff, version >> 12 & 0x3ff, version & 0xfff}; user->info("Vulkan version: {}", fmt::join(vkVA64, ".")); @@ -46,21 +46,25 @@ namespace cosmic::gpu { }); displayApiVersion = displayVersion; } - static void startVulkanLayer(GraphicsLayer& gpu) { - auto getInstance{gpu.backend->vulkanInstanceAddr}; - gpu.app = vk::raii::Context(getInstance); - gpu.instance = vulcano::createVulkanInstance(*gpu.app, gpu.haveValidation); + static void startVulkanLayer(Ref gpu) { + gpu->app.reset(); + gpu->instance.reset(); - auto vulkanGpu{vulcano::createPhysicalDevice(*gpu.instance)}; + auto getInstance{gpu->backend->vulkanInstanceAddr}; + gpu->app = vk::raii::Context(getInstance); + gpu->instance = vulcano::createVulkanInstance(*gpu->app, gpu->haveValidation); - gpu.vkDev = std::move(vulkanGpu.gpuUser); - gpu.deviceInfo = vulkanGpu.info; - gpu.queueFamilyId = vulkanGpu.desiredQueueId; + struct vulcano::PhysicalDevice vulkanGpu{ + vulcano::createPhysicalDevice(*gpu->instance)}; + + gpu->vkDev = std::move(vulkanGpu.gpuUser); + gpu->deviceInfo = vulkanGpu.info; + gpu->queueFamilyId = vulkanGpu.desiredQueueId; #ifndef NDEBUG - if (gpu.haveValidation) { + if (gpu->haveValidation) { auto debugInfoMsg{vulcano::createDebugInfo()}; vulcano::createDebugLayer( - getInstance, *gpu.instance, debugInfoMsg, {}, gpu.debugMessenger); + getInstance, *gpu->instance, debugInfoMsg, {}, gpu->debugMessenger); } #endif } diff --git a/app/src/main/cpp/cosmic/hle/bios_class.cpp b/app/src/main/cpp/cosmic/hle/bios_class.cpp deleted file mode 100644 index b78802e6..00000000 --- a/app/src/main/cpp/cosmic/hle/bios_class.cpp +++ /dev/null @@ -1,30 +0,0 @@ - -#include -namespace cosmic::hle { - jobject BiosInfo::createInstance() { - auto ioClass{findClass()}; - - auto modelInit{classEnv->GetMethodID(ioClass, "", "()V")}; - auto kotlinBios{classEnv->NewObject(ioClass, modelInit)}; - - return kotlinBios; - } - void BiosInfo::fillInstance(jobject kotlin) { - auto kotlinModel{findClass()}; - - auto posBrains{classEnv->GetFieldID(kotlinModel, "position", "I")}; - auto selectedBrains{classEnv->GetFieldID(kotlinModel, "selected", "Z")}; - auto biosNameBrains{classEnv->GetFieldID(kotlinModel, "biosName", "Ljava/lang/String;")}; - auto biosDetailsBrains{classEnv->GetFieldID(kotlinModel, "biosDetails", "Ljava/lang/String;")}; - - classEnv->SetIntField(kotlin, posBrains, position); - - classEnv->SetBooleanField(kotlin, selectedBrains, selected); - - classEnv->SetObjectField(kotlin, biosNameBrains, dspName.javaRef); - classEnv->SetObjectField(kotlin, biosDetailsBrains, details.javaRef); - } - void BiosInfo::chkAndLoad(i32 descriptor) { - fd = DescriptorRaii(descriptor, true); - } -} \ No newline at end of file diff --git a/app/src/main/cpp/cosmic/hle/bios_info.cpp b/app/src/main/cpp/cosmic/hle/bios_info.cpp new file mode 100644 index 00000000..11a3f5e4 --- /dev/null +++ b/app/src/main/cpp/cosmic/hle/bios_info.cpp @@ -0,0 +1,35 @@ + +#include +#include +namespace cosmic::hle { + jobject BiosInfo::createInstance() { + auto ioClass{findClass()}; + + auto modelInit{cosmicEnv->GetMethodID(ioClass, "", "()V")}; + auto kotlinBios{cosmicEnv->NewObject(ioClass, modelInit)}; + + return kotlinBios; + } + void BiosInfo::deleteInstance(jobject kotlinBios) { + cosmicEnv->DeleteLocalRef(kotlinBios); + } + + void BiosInfo::fillInstance(jobject kotlin) { + auto kotlinModel{findClass()}; + + auto posBrains{cosmicEnv->GetFieldID(kotlinModel, "position", "I")}; + auto selectedBrains{cosmicEnv->GetFieldID(kotlinModel, "selected", "Z")}; + auto biosNameBrains{cosmicEnv->GetFieldID(kotlinModel, "biosName", "Ljava/lang/String;")}; + auto biosDetailsBrains{cosmicEnv->GetFieldID(kotlinModel, "biosDetails", "Ljava/lang/String;")}; + + cosmicEnv->SetIntField(kotlin, posBrains, position); + + cosmicEnv->SetBooleanField(kotlin, selectedBrains, selected); + + cosmicEnv->SetObjectField(kotlin, biosNameBrains, dspName.javaRef); + cosmicEnv->SetObjectField(kotlin, biosDetailsBrains, details.javaRef); + } + void BiosInfo::chkAndLoad(i32 descriptor) { + fd = DescriptorRaii(descriptor, true); + } +} \ No newline at end of file diff --git a/app/src/main/cpp/cosmic/hle/bios_class.h b/app/src/main/cpp/cosmic/hle/bios_info.h similarity index 86% rename from app/src/main/cpp/cosmic/hle/bios_class.h rename to app/src/main/cpp/cosmic/hle/bios_info.h index bb27c232..b68c01b8 100644 --- a/app/src/main/cpp/cosmic/hle/bios_class.h +++ b/app/src/main/cpp/cosmic/hle/bios_info.h @@ -6,7 +6,8 @@ namespace cosmic::hle { class BiosInfo : java::JavaClass { public: - BiosInfo(JNIEnv* env) : java::JavaClass(env, "emu/cosmic/data/BiosInfo") {} + BiosInfo() : java::JavaClass("emu/cosmic/data/BiosInfo") { + } i32 position; DescriptorRaii fd; u32 dataCRC; @@ -16,6 +17,8 @@ namespace cosmic::hle { java::JniString details; jobject createInstance() override; + void deleteInstance(jobject kotlinBios) override; + void fillInstance(jobject kotlin) override; void chkAndLoad(i32 descriptor); diff --git a/app/src/main/cpp/cosmic/hle/bios_patch.h b/app/src/main/cpp/cosmic/hle/bios_patch.h index e50a2f59..05ab9d66 100644 --- a/app/src/main/cpp/cosmic/hle/bios_patch.h +++ b/app/src/main/cpp/cosmic/hle/bios_patch.h @@ -9,9 +9,9 @@ namespace cosmic::hle { class BiosPatcher { public: - BiosPatcher(JNIEnv* env, std::shared_ptr& core) - : group(std::make_shared(env)), - mips(core) {} + BiosPatcher(std::shared_ptr& core) : + group(std::make_shared()), + mips(core) {} void resetBios(); void emit(u32 address); diff --git a/app/src/main/cpp/cosmic/hle/group_mgr.cpp b/app/src/main/cpp/cosmic/hle/group_mgr.cpp index 68c91cdf..2ff91994 100644 --- a/app/src/main/cpp/cosmic/hle/group_mgr.cpp +++ b/app/src/main/cpp/cosmic/hle/group_mgr.cpp @@ -5,18 +5,16 @@ #include namespace cosmic::hle { - HleBiosGroup::HleBiosGroup(JNIEnv* env) : android(env) {} + HleBiosGroup::HleBiosGroup() {} void HleBiosGroup::readBios(std::span loadHere) { - if (slotBios) - // Todo: There is an issue involving the destruction of JniString due to: DeleteGlobalRef + const auto biosPath{*(device->getStates()->biosPath)}; + BiosInfo info{}; + if (slotBios) { slotBios.reset(); + } - const auto biosPath{*(device->getStates()->biosPath)}; - BiosInfo info{android}; info.fd = DescriptorRaii(open(biosPath.c_str(), O_RDONLY), true); - slotBios = std::make_unique(std::move(info)); - if (!slotBios) { throw NonAbort("Wait, there is no BIOS available in the slot"); } @@ -26,6 +24,9 @@ namespace cosmic::hle { bool HleBiosGroup::isAlreadyAdded(i32 is[2], bool usePos) { bool alreadyAdded{}; + if (slotBios && slotBios->isSame(is, usePos)) + return true; + for (const auto& bios : biosList) { if (alreadyAdded) break; @@ -51,6 +52,7 @@ namespace cosmic::hle { i32 previous{}; if (slotBios) { previous = slotBios->position; + biosList.push_back(std::move(*slotBios)); slotBios.reset(); } @@ -63,12 +65,18 @@ namespace cosmic::hle { if (picked == biosList.end()) return -1; - slotBios = std::make_unique(*picked); + slotBios = std::make_unique(std::move(*picked)); + biosList.erase(picked); return previous; } bool HleBiosGroup::loadBiosBy(jobject model, i32 ldBy[2], bool usePos) { bool loaded{}; + if (slotBios && slotBios->isSame(ldBy, usePos)) { + slotBios->fillInstance(model); + return true; + } + auto biosSelected{ranges::find_if(biosList, [ldBy, usePos](const auto& bios) { return bios.isSame(ldBy, usePos); })}; @@ -82,11 +90,16 @@ namespace cosmic::hle { bool HleBiosGroup::storeAndFill(jobject model, BiosInfo&& bios) { if (!isCrucial && bios.selected) isCrucial = true; - if (!loader.fetchBiosInfo(android, bios)) + if (!loader.fetchBiosInfo(bios)) return false; bios.fillInstance(model); - biosList.push_back(std::move(bios)); + if (!slotBios) { + slotBios = std::make_unique(std::move(bios)); + } else { + biosList.emplace_back(std::move(bios)); + } + return true; } } diff --git a/app/src/main/cpp/cosmic/hle/group_mgr.h b/app/src/main/cpp/cosmic/hle/group_mgr.h index ef5cab2f..7191e59b 100644 --- a/app/src/main/cpp/cosmic/hle/group_mgr.h +++ b/app/src/main/cpp/cosmic/hle/group_mgr.h @@ -2,12 +2,12 @@ #include -#include +#include #include namespace cosmic::hle { class HleBiosGroup { public: - HleBiosGroup(JNIEnv* env); + HleBiosGroup(); bool storeAndFill(jobject model, BiosInfo&& bios); bool isAlreadyAdded(i32 is[2], bool usePos = false); @@ -24,6 +24,5 @@ namespace cosmic::hle { std::list biosList; fs::BiosLoader loader{}; - JNIEnv* android{}; }; } diff --git a/app/src/main/cpp/cosmic/iop/iop_core.cpp b/app/src/main/cpp/cosmic/iop/iop_core.cpp index 36445ed3..aa34e84e 100644 --- a/app/src/main/cpp/cosmic/iop/iop_core.cpp +++ b/app/src/main/cpp/cosmic/iop/iop_core.cpp @@ -35,7 +35,7 @@ namespace cosmic::iop { i64 calcPc{static_cast(ioPc) + pcAddr}; waitPc = static_cast(calcPc); if (waitPc & 0x3) { - throw AppFail("Next IOP PC {::x}: lowest 3 bits couldn't be set", waitPc); + throw AppFail("Next IOP PC {:x}: lowest 3 bits couldn't be set", waitPc); } onBranch = true; branchDelay = 1; diff --git a/app/src/main/cpp/cosmic/java/device_handler.cpp b/app/src/main/cpp/cosmic/java/device_handler.cpp index 5825f99e..d9c083b3 100644 --- a/app/src/main/cpp/cosmic/java/device_handler.cpp +++ b/app/src/main/cpp/cosmic/java/device_handler.cpp @@ -1,3 +1,4 @@ +#include #include namespace cosmic::java { @@ -5,8 +6,8 @@ namespace cosmic::java { androidRuntime(jvm) { void* env{}; androidRuntime->GetEnv(&env, JNI_VERSION_1_6); - android = reinterpret_cast(env); + cosmicEnv.feedVm(BitCast(env)); - state = std::make_shared(android); + state = std::make_shared(); } } diff --git a/app/src/main/cpp/cosmic/java/device_handler.h b/app/src/main/cpp/cosmic/java/device_handler.h index 52271376..9d936cc3 100644 --- a/app/src/main/cpp/cosmic/java/device_handler.h +++ b/app/src/main/cpp/cosmic/java/device_handler.h @@ -11,8 +11,6 @@ namespace cosmic::java { return state; } JavaVM* androidRuntime{}; - JNIEnv* android{}; - private: std::shared_ptr state; }; diff --git a/app/src/main/cpp/cosmic/java/env.h b/app/src/main/cpp/cosmic/java/env.h new file mode 100644 index 00000000..b5d1f599 --- /dev/null +++ b/app/src/main/cpp/cosmic/java/env.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +namespace cosmic::java { + struct CosmicEnv { + CosmicEnv(CosmicEnv&) = delete; + CosmicEnv(CosmicEnv&&) = delete; + CosmicEnv() { + if (jvm) { + jvm->GetEnv(BitCast(&gnv), jv); + } + if (!gnv && jvm) { + jvm->AttachCurrentThread(&gnv, nullptr); + attached = true; + } + } + void feedVm(JNIEnv* e) { + if ((jv = e->GetVersion()) != JNI_VERSION_1_6) + ; + if (!jvm) + e->GetJavaVM(&jvm); + gnv = e; + } + void reload() { + jvm->GetEnv(BitCast(&gnv), jv); + } + void reload(JNIEnv* e) { + if (!gnv) + feedVm(e); + else + gnv = e; + } + ~CosmicEnv() { + if (attached) { + jvm->DetachCurrentThread(); + } + } + auto operator*() { + return gnv; + } + auto operator->() { + return gnv; + } + + static inline JavaVM* jvm{}; + static inline i32 jv; + // Means that it was created by a native thread + bool attached{}; + JNIEnv* gnv{}; + }; +} \ No newline at end of file diff --git a/app/src/main/cpp/cosmic/java/jclasses.cpp b/app/src/main/cpp/cosmic/java/jclasses.cpp index 1d48f87d..464881ab 100644 --- a/app/src/main/cpp/cosmic/java/jclasses.cpp +++ b/app/src/main/cpp/cosmic/java/jclasses.cpp @@ -1,27 +1,46 @@ #include +#include namespace cosmic::java { - JniString::JniString(JNIEnv* env, const char* str) : - validEnv(env) { - readableStr = std::string(str); - auto kotlinStr{env->NewStringUTF(str)}; - javaRef = validEnv->NewGlobalRef(kotlinStr); + JniString::JniString(const char* str) { + utfSide = std::string(str); + auto kotlinStr{cosmicEnv->NewStringUTF(str)}; + javaRef = cosmicEnv->NewGlobalRef(kotlinStr); } - JniString::JniString(JNIEnv* env, jstring validJniString) : - validEnv(env) { - auto rawStr{env->GetStringUTFChars(validJniString, nullptr)}; - readableStr = std::string(BitCast(rawStr)); + JniString::JniString(jstring validJniString) { + auto rawStr{ + cosmicEnv->GetStringUTFChars(validJniString, nullptr)}; + utfSide = std::string(BitCast(rawStr)); - env->ReleaseStringUTFChars(validJniString, rawStr); + cosmicEnv->ReleaseStringUTFChars(validJniString, rawStr); } JniString::~JniString() { if (javaRef) - validEnv->DeleteGlobalRef(javaRef); + cosmicEnv->DeleteGlobalRef(javaRef); + javaRef = {}; + utfSide = {}; } + JniString::JniString(JniString&& str) { + javaRef = std::exchange(str.javaRef, nullptr); + utfSide = std::move(str.utfSide); + } + + JniString::JniString(const std::string str) : + utfSide(str) { + javaRef = cosmicEnv->NewGlobalRef(cosmicEnv->NewStringUTF(str.c_str())); + } + auto JniString::operator=(const JniString& str) -> JniString& { + if (javaRef) { + if (!cosmicEnv->IsSameObject(javaRef, nullptr)) + cosmicEnv->DeleteGlobalRef(javaRef); + } + javaRef = cosmicEnv->NewGlobalRef(str.javaRef); + utfSide = str.utfSide; - JniString::JniString(JNIEnv* env, const std::string str) : - validEnv(env), readableStr(str) { - javaRef = env->NewGlobalRef(env->NewStringUTF(str.c_str())); + return *this; + } + jclass JavaClass::findClass() { + return cosmicEnv->FindClass(modelName); } } diff --git a/app/src/main/cpp/cosmic/java/jclasses.h b/app/src/main/cpp/cosmic/java/jclasses.h index dc88f16c..ff991a5b 100644 --- a/app/src/main/cpp/cosmic/java/jclasses.h +++ b/app/src/main/cpp/cosmic/java/jclasses.h @@ -8,60 +8,43 @@ namespace cosmic::java { using JniInteger = jint; using JniBool = jboolean; - struct JniString { + class JniString { public: - JniString() = default; - JniString(JNIEnv* env, const char* str); - JniString(JNIEnv* env, const std::string str); - JniString(JNIEnv* env, jstring validJniString); - JniString(JniString&& str) { - *this = std::move(str); - } - JniString(JniString& str) { - validEnv = str.validEnv; - javaRef = validEnv->NewGlobalRef(str.javaRef); - readableStr = str.readableStr; + JniString() { } + JniString(const char* str); + JniString(const std::string str); + JniString(jstring validJniString); ~JniString(); - JniString& operator=(JniString&& str) noexcept { - validEnv = str.validEnv; - if (javaRef) { - if (!validEnv->IsSameObject(javaRef, nullptr)) - validEnv->DeleteGlobalRef(javaRef); - } - javaRef = std::exchange(str.javaRef, nullptr); - readableStr = str.readableStr; - - return *this; - } + auto operator =(const JniString& str) -> JniString&; + JniString(JniString&& str); auto operator *() { - return readableStr; + return utfSide; } auto operator !=(JniString& differ) { - return readableStr != differ.readableStr; + return utfSide != differ.utfSide; + } + auto get() { + return utfSide; } - - JNIEnv* validEnv{}; - std::string readableStr{""}; jobject javaRef{}; - jboolean isCopy{false}; + private: + std::string utfSide{""}; }; class JavaClass { protected: - JavaClass(JNIEnv* env, const char* className) : - classEnv(env), + JavaClass(const char* className) : modelName(className) {} virtual ~JavaClass() = default; virtual jobject createInstance() = 0; virtual void fillInstance(jobject kotlin) = 0; - jclass findClass() { - return classEnv->FindClass(modelName); - } + virtual void deleteInstance(jobject kotlinBios) = 0; + + jclass findClass(); - JNIEnv* classEnv{}; const char* modelName; }; } diff --git a/app/src/main/cpp/cosmic/os/system_state.cpp b/app/src/main/cpp/cosmic/os/system_state.cpp index eff6fb4d..57384d0e 100644 --- a/app/src/main/cpp/cosmic/os/system_state.cpp +++ b/app/src/main/cpp/cosmic/os/system_state.cpp @@ -1,12 +1,17 @@ #include +#include namespace cosmic::os { std::array dsKeys{ - "dsdbAppStorage", - "dsdbGpuTurboMode", - "dsdbGpuCustomDriver", - "dsdbEeMode", - "dsdbBiosPath", - "dsdbSchedAffinity" + "dsdb_app_storage", + + "dsdb_gpu_turbo_mode", + + "dsdb_gpu_custom_driver", + + "dsdb_ee_mode", + + "dsdb_bios_path", + "dsdb_sched_affinity" }; void OsMachState::addObserver(StateId state, ObserverFunc observer) { if (state == AppStorage) { diff --git a/app/src/main/cpp/cosmic/os/system_state.h b/app/src/main/cpp/cosmic/os/system_state.h index 79b6e3f3..5cb67fa3 100644 --- a/app/src/main/cpp/cosmic/os/system_state.h +++ b/app/src/main/cpp/cosmic/os/system_state.h @@ -6,7 +6,12 @@ #include #include +#include #include + +namespace cosmic { + extern thread_local java::CosmicEnv cosmicEnv; +} namespace cosmic::os { enum StateId : u16 { AppStorage, @@ -22,83 +27,86 @@ namespace cosmic::os { template class OsVariable { public: - OsVariable(JNIEnv* androidEnv, const std::string& stateName) : - osEnv(androidEnv), cachedState() { - - auto state{osEnv->NewStringUTF(stateName.data())}; - varName = static_cast(osEnv->NewGlobalRef(state)); - osEnv->DeleteLocalRef(state); + OsVariable(const std::string& stateName) { + auto state{cosmicEnv->NewStringUTF(stateName.data())}; + varName = BitCast(cosmicEnv->NewGlobalRef(state)); + if (varName) { + cosmicEnv->DeleteLocalRef(state); + } } ~OsVariable() { - osEnv->DeleteGlobalRef(varName); - } - void operator=(const T&& variable) { - cachedState = variable; + cosmicEnv->DeleteGlobalRef(varName); } - auto operator*() { - if constexpr (std::is_same::value) - return cachedState.operator*(); - else - return cachedState; - } - void updateValue(); - std::vector observers{2}; - private: - JNIEnv* osEnv; - T cachedState; - jstring varName; + void updateValue() { + auto settingsClass{ + cosmicEnv->FindClass("emu/cosmic/data/CosmicSettings")}; + auto updateEnvMethod{ + cosmicEnv->GetStaticMethodID(settingsClass, + "getDataStoreValue", + "(Ljava/lang/String;)Ljava/lang/Object;")}; - }; + if (cosmicEnv->ExceptionCheck()) + cosmicEnv->ExceptionOccurred(); - template - void OsVariable::updateValue() { - auto settingsClass{osEnv->FindClass("emu/cosmic/data/CosmicSettings")}; - auto updateEnvMethod{osEnv->GetStaticMethodID(settingsClass, "getDataStoreValue", "(Ljava/lang/String;)Ljava/lang/Object;")}; + auto result{cosmicEnv->CallStaticObjectMethod(settingsClass, updateEnvMethod, varName)}; + bool isModified{false}; + std::optional stateValue{}; - if (osEnv->ExceptionCheck()) - osEnv->ExceptionOccurred(); + if constexpr (std::is_same::value) { + cachedState = java::JniString(BitCast(result)); + isModified = *stateValue != *cachedState; - auto result{osEnv->CallStaticObjectMethod(settingsClass, updateEnvMethod, varName)}; - bool isModified{false}; - T stateValue; + } else if constexpr (std::is_same::value) { + auto getInt{cosmicEnv->GetMethodID(cosmicEnv->GetObjectClass(result), + "intValue", "()I")}; + stateValue = cosmicEnv->CallIntMethod(result, getInt); + isModified = *stateValue != *cachedState; - if constexpr (std::is_same::value) { - stateValue = java::JniString(osEnv, BitCast(result)); - isModified = stateValue != cachedState; - } else if constexpr (std::is_same::value) { - auto getInt{osEnv->GetMethodID(osEnv->GetObjectClass(result), "intValue", "()I")}; - stateValue = osEnv->CallIntMethod(result, getInt); - isModified = stateValue != cachedState; - } else if constexpr (std::is_same::value) { - assert(osEnv->IsInstanceOf(result, osEnv->FindClass("java/lang/Boolean"))); - auto getBool{osEnv->GetMethodID(osEnv->GetObjectClass(result), "booleanValue", "()Z")}; - stateValue = osEnv->CallBooleanMethod(result, getBool); - isModified = stateValue != cachedState; + } else if constexpr (std::is_same::value) { + assert(cosmicEnv->IsInstanceOf(result, cosmicEnv->FindClass("java/lang/Boolean"))); + auto getBool{cosmicEnv->GetMethodID(cosmicEnv->GetObjectClass(result), + "booleanValue", "()Z")}; + stateValue = cosmicEnv->CallBooleanMethod(result, getBool); + isModified = *stateValue != *cachedState; + } + if (isModified && stateValue.has_value()) { + if constexpr (std::is_same::value) + cachedState = std::move(*stateValue); + else + cachedState = *stateValue; + for (auto& observer : observers) { + if (observer) + observer(); + } + } + cosmicEnv->DeleteLocalRef(result); } - if (isModified) { + void operator=(const T&& variable) { + cachedState = std::move(variable); + } + auto operator*() { if constexpr (std::is_same::value) - cachedState = std::move(stateValue); + return *(cachedState.value()); else - cachedState = stateValue; - for (auto& observer : observers) { - if (observer) - observer(); - } + return cachedState.value(); } - osEnv->DeleteLocalRef(result); - } + std::vector observers{2}; + private: + std::optional cachedState{}; + jstring varName{}; + }; class OsMachState { public: - OsMachState(JNIEnv* androidEnv) : - appStorage(androidEnv, dsKeys.at(AppStorage)), - turboMode(androidEnv, dsKeys.at(GpuTurboMode)), - customDriver(androidEnv, dsKeys.at(GpuCustomDriver)), - eeMode(androidEnv, dsKeys.at(EeMode)), - biosPath(androidEnv, dsKeys.at(BiosPath)), - schedAffinity(androidEnv, dsKeys.at(SchedulerAffinity)) { + OsMachState() : + appStorage(dsKeys.at(AppStorage)), + turboMode(dsKeys.at(GpuTurboMode)), + customDriver(dsKeys.at(GpuCustomDriver)), + eeMode(dsKeys.at(EeMode)), + biosPath(dsKeys.at(BiosPath)), + schedAffinity(dsKeys.at(SchedulerAffinity)) { } void addObserver(StateId state, ObserverFunc observe); diff --git a/app/src/main/cpp/cosmic/vm/emu_vm.cpp b/app/src/main/cpp/cosmic/vm/emu_vm.cpp index 44a2b1b3..916278e9 100644 --- a/app/src/main/cpp/cosmic/vm/emu_vm.cpp +++ b/app/src/main/cpp/cosmic/vm/emu_vm.cpp @@ -7,9 +7,10 @@ #include #define TEST_BIOS_ACCESS 0 namespace cosmic::vm { - EmuVm::EmuVm(JNIEnv* env, std::shared_ptr& devices, - std::shared_ptr& dsp) : - screenEngine(dsp), + EmuVm::EmuVm( + std::shared_ptr& devices, + std::shared_ptr& dsp) : + screenEngine(dsp), emuThread(*this) { outside = std::make_shared(*this); sharedPipe = std::make_shared(devices); @@ -23,7 +24,7 @@ namespace cosmic::vm { mpegDecoder = devices->decoderMpeg12; vu01 = devices->VUs; - biosHigh = std::make_shared(env, mips); + biosHigh = std::make_shared(mips); scheduler = std::make_shared(); intc = std::make_shared(*this); // Our way to perform interconnection between different isolated components diff --git a/app/src/main/cpp/cosmic/vm/emu_vm.h b/app/src/main/cpp/cosmic/vm/emu_vm.h index 8fed9066..359456c2 100644 --- a/app/src/main/cpp/cosmic/vm/emu_vm.h +++ b/app/src/main/cpp/cosmic/vm/emu_vm.h @@ -12,7 +12,7 @@ namespace cosmic::vm { class EmuVm { public: - EmuVm(JNIEnv* env, + EmuVm( std::shared_ptr& devices, std::shared_ptr& dsp); diff --git a/app/src/main/cpp/emu_user.cpp b/app/src/main/cpp/emu_user.cpp index c03330c9..cc7afa3e 100644 --- a/app/src/main/cpp/emu_user.cpp +++ b/app/src/main/cpp/emu_user.cpp @@ -11,7 +11,9 @@ Java_emu_cosmic_EmulationActivity_swtSurfaceContext(JNIEnv* env, jobject thiz, j std::atomic is{false}; extern "C" JNIEXPORT void JNICALL -Java_emu_cosmic_EmulationActivity_runEmulatorVm(JNIEnv* env, jobject thiz) { +Java_emu_cosmic_EmulationActivity_runEmulatorVm(JNIEnv* env, [[maybe_unused]] jobject thiz) { + cosmic::CosmicException::setExceptionClass(thiz); + cosmic::app->vm->resetVm(); is = 1; cosmic::app->vm->startVm(); diff --git a/app/src/main/cpp/jvm_comm.cpp b/app/src/main/cpp/jvm_comm.cpp index b50a72bb..0a26e864 100644 --- a/app/src/main/cpp/jvm_comm.cpp +++ b/app/src/main/cpp/jvm_comm.cpp @@ -18,7 +18,7 @@ extern "C" JNIEXPORT void JNICALL Java_emu_cosmic_MainActivity_syncSettings(JNIEnv* env, jobject thiz, jstring dateTime) { auto osState{cosmic::device->getStates()}; - cosmic::app->lastSetSync = cosmic::java::JniString(env, dateTime).readableStr; + cosmic::app->lastSetSync = cosmic::java::JniString(dateTime).get(); osState->syncAllSettings(); cosmic::user->success("Time of the last synchronization of global settings: {}", cosmic::app->lastSetSync); diff --git a/app/src/main/java/emu/cosmic/EmulationActivity.kt b/app/src/main/java/emu/cosmic/EmulationActivity.kt index 50e88cf7..2c7b0545 100644 --- a/app/src/main/java/emu/cosmic/EmulationActivity.kt +++ b/app/src/main/java/emu/cosmic/EmulationActivity.kt @@ -9,6 +9,7 @@ import android.view.SurfaceHolder import android.view.WindowInsets import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import emu.cosmic.databinding.EmulationActivityBinding import emu.cosmic.models.EmulationModel @@ -25,6 +26,26 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback { runEmulatorVm() goBackToMain() } + init { + activity = this + } + + companion object { + lateinit var activity: EmulationActivity + + @Suppress("unused") @JvmStatic + fun displayAlert(title: String, msg: String) { + AlertDialog.Builder(activity.applicationContext) + .setTitle(title) + .setMessage(msg) + .setPositiveButton(activity.getString(R.string.positive)) { _, _ -> + activity.goBackToMain() + }.show() + + activity.fps = 0 + } + } + @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/emu/cosmic/data/BiosInfo.kt b/app/src/main/java/emu/cosmic/data/BiosInfo.kt index cc19b8f5..e35bb02a 100644 --- a/app/src/main/java/emu/cosmic/data/BiosInfo.kt +++ b/app/src/main/java/emu/cosmic/data/BiosInfo.kt @@ -14,4 +14,20 @@ data class BiosInfo( var biosPath: String, var biosName: String, var biosDetails: String -) \ No newline at end of file +) { + override fun equals(other: Any?): Boolean { + val info = other as BiosInfo + return (biosPath == info.biosPath) && + (biosName == info.biosName) && + (biosDetails == info.biosDetails) + } + override fun hashCode(): Int { + var result = position + result = 31 * result + fileAlive.hashCode() + result = 31 * result + selected.hashCode() + result = 31 * result + biosPath.hashCode() + result = 31 * result + biosName.hashCode() + result = 31 * result + biosDetails.hashCode() + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/emu/cosmic/data/CosmicSettings.kt b/app/src/main/java/emu/cosmic/data/CosmicSettings.kt index b0dadc2b..17c4dc26 100644 --- a/app/src/main/java/emu/cosmic/data/CosmicSettings.kt +++ b/app/src/main/java/emu/cosmic/data/CosmicSettings.kt @@ -20,20 +20,19 @@ class CosmicSettings private constructor(context: Context) { companion object { val globalSettings by lazy { CosmicSettings(CosmicApplication.context) } var updateSettings: Boolean = false - @Suppress("unused") - @JvmStatic + @Suppress("unused") @JvmStatic fun getDataStoreValue(config: String) : Any { return when (config) { - "dsdbAppStorage" -> globalSettings.appStorage - "dsdbGpuTurboMode" -> globalSettings.gpuTurboMode + "dsdb_app_storage" -> globalSettings.appStorage + "dsdb_gpu_turbo_mode" -> globalSettings.gpuTurboMode - "dsdbGpuCustomDriver" -> globalSettings.customDriver - "dsdbEeMode" -> globalSettings.eeMode + "dsdb_gpu_custom_driver" -> globalSettings.customDriver + "dsdb_ee_mode" -> globalSettings.eeMode - "dsdbBiosPath" -> globalSettings.biosPath + "dsdb_bios_path" -> globalSettings.biosPath else -> { - throw NotFoundException("") + throw NotFoundException(config) } } } diff --git a/app/src/main/java/emu/cosmic/helpers/BiosHelper.kt b/app/src/main/java/emu/cosmic/helpers/BiosHelper.kt index 6e2a115c..2c3cd413 100644 --- a/app/src/main/java/emu/cosmic/helpers/BiosHelper.kt +++ b/app/src/main/java/emu/cosmic/helpers/BiosHelper.kt @@ -76,8 +76,10 @@ class BiosHelper : ViewModel() { model.fileAlive = biosStream model } - if (injection.isSuccess) - biosList.add(injection.getOrThrow()) + if (injection.isSuccess) { + if (!biosList.contains(injection.getOrThrow())) + biosList.add(injection.getOrThrow()) + } } fun unloadBios(position: Int) { @@ -91,7 +93,6 @@ class BiosHelper : ViewModel() { if (removed.isSuccess) biosList.remove(model) } - fun activateBios(position: Int) : Int { val previous = setBios(position) if (previous != position) { diff --git a/app/src/main/java/emu/cosmic/settings/BiosActivity.kt b/app/src/main/java/emu/cosmic/settings/BiosActivity.kt index 1ee08b8b..96938554 100644 --- a/app/src/main/java/emu/cosmic/settings/BiosActivity.kt +++ b/app/src/main/java/emu/cosmic/settings/BiosActivity.kt @@ -28,7 +28,10 @@ class BiosActivity : AppCompatActivity() { private val adapter = SelectableViewAdapter(BiosHelper.getInUse(0)) val install = registerForActivityResult(OpenASFContract()) { result: Uri? -> - val bios = File(result?.path!!) + if (result == null) + return@registerForActivityResult + + val bios = File(result.path!!) val storageFile = contentResolver.openInputStream(result) val destNameExt = pathSolver(bios.toUri(), "").substringAfterLast("/") val installationDir = File("${BiosHelper.biosDir}/$destNameExt") diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 043df963..908cd474 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ Cosmic + Ok God be praised Commit version @@ -29,11 +30,11 @@ Forces the GPU to operate at the highest possible clock speed Oh God, run under an AC - dsdbAppStorage - dsdbGpuTurboMode - dsdbGpuCustomDriver - dsdbEeMode - dsdbBiosPath + dsdb_app_storage + dsdb_gpu_turbo_mode + dsdb_gpu_custom_driver + dsdb_ee_mode + dsdb_bios_path Add 0000000000000.bin