diff --git a/.gitignore b/.gitignore index 8653e8e05..a5d2265bf 100644 --- a/.gitignore +++ b/.gitignore @@ -46,13 +46,6 @@ shell/linux/dispframe.elf generated .vs -# Android Studio -*.iml -shell/android-studio/.gradle/ -shell/android-studio/flycast/.cxx/ -shell/android-studio/flycast/build/ -shell/android-studio/flycast/local.properties - # JetBrains IDES .idea/ cmake-build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d1bd9cdc..4896b1aa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake") if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum macOS deployment version") + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "") endif() project(flycast) @@ -986,7 +987,7 @@ if(WIN32 AND NOT LIBRETRO) target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3dx9) endif() -if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)" AND NOT APPLE) target_include_directories(${PROJECT_NAME} PRIVATE core/deps/vixl) target_sources(${PROJECT_NAME} PRIVATE core/rec-ARM/rec_arm.cpp @@ -1020,7 +1021,9 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)") core/deps/vixl/pool-manager-impl.h core/deps/vixl/utils-vixl.cc core/deps/vixl/utils-vixl.h) -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") + set(KNOWN_ARCHITECTURE_DETECTED ON) +endif() +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*)" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64") target_include_directories(${PROJECT_NAME} PRIVATE core/deps/vixl) target_sources(${PROJECT_NAME} PRIVATE core/deps/vixl/aarch64/abi-aarch64.h @@ -1065,7 +1068,9 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") core/deps/vixl/utils-vixl.cc core/deps/vixl/utils-vixl.h) target_sources(${PROJECT_NAME} PRIVATE core/rec-ARM64/rec_arm64.cpp core/rec-ARM64/arm64_regalloc.h) -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*") + set(KNOWN_ARCHITECTURE_DETECTED ON) +endif() +if(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD64.*" OR CMAKE_OSX_ARCHITECTURES MATCHES "x86_64") add_subdirectory(core/deps/xbyak) target_link_libraries(${PROJECT_NAME} PRIVATE xbyak::xbyak) if(CMAKE_SIZEOF_VOID_P EQUAL 4) @@ -1081,7 +1086,9 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|x86_64.*|AMD6 core/rec-x64/rec_x64.cpp core/rec-x64/x64_regalloc.h) endif() -else() + set(KNOWN_ARCHITECTURE_DETECTED ON) +endif() +if(NOT KNOWN_ARCHITECTURE_DETECTED) message(FATAL_ERROR "Unknown target processor: ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -1089,9 +1096,7 @@ if(NOT LIBRETRO) if(ANDROID) target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES3) - target_sources(${PROJECT_NAME} PRIVATE - shell/android-studio/flycast/src/main/jni/src/Android.cpp - shell/android-studio/flycast/src/main/jni/src/utils.cpp) + target_sources(${PROJECT_NAME} PRIVATE shell/android-studio/flycast/src/main/jni/src/Android.cpp) target_link_libraries(${PROJECT_NAME} PRIVATE android EGL GLESv2 log) elseif(APPLE) diff --git a/core/deps/libchdr b/core/deps/libchdr index 00319cf31..d3ffd20ca 160000 --- a/core/deps/libchdr +++ b/core/deps/libchdr @@ -1 +1 @@ -Subproject commit 00319cf31f034e4d468a49a60265c7c5b8305b70 +Subproject commit d3ffd20ca71686877372dea7f9eed359dbf65ba2 diff --git a/core/hw/arm7/arm7_rec_arm64.cpp b/core/hw/arm7/arm7_rec_arm64.cpp index ebdd37389..e39a6ae7d 100644 --- a/core/hw/arm7/arm7_rec_arm64.cpp +++ b/core/hw/arm7/arm7_rec_arm64.cpp @@ -109,10 +109,18 @@ class Arm7Compiler : public MacroAssembler void call(void *loc) { - ptrdiff_t offset = reinterpret_cast(loc) - reinterpret_cast(recompiler::writeToExec(GetBuffer()->GetStartAddress())); - Label function_label; - BindToOffset(&function_label, offset); - Bl(&function_label); + ptrdiff_t offset = reinterpret_cast(loc) - reinterpret_cast(recompiler::writeToExec(GetBuffer()->GetStartAddress())); + if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024) + { + Mov(x4, reinterpret_cast(loc)); + Blr(x4); + } + else + { + Label function_label; + BindToOffset(&function_label, offset); + Bl(&function_label); + } } Operand getOperand(const ArmOp::Operand& arg, const Register& scratch_reg) @@ -546,6 +554,7 @@ public: void compile(const std::vector& block_ops, u32 cycles) { + JITWriteProtect(false); Ldr(w1, arm_reg_operand(CYCL_CNT)); Sub(w1, w1, cycles); Str(w1, arm_reg_operand(CYCL_CNT)); @@ -625,6 +634,7 @@ public: #endif delete regalloc; regalloc = nullptr; + JITWriteProtect(true); } void generateMainLoop() @@ -635,6 +645,7 @@ public: verify(arm_compilecode != nullptr); return; } + JITWriteProtect(false); Label arm_dispatch_label; Label arm_dofiq; Label arm_exit; @@ -710,6 +721,7 @@ public: recompiler::writeToExec(GetBuffer()->GetStartAddress()), recompiler::writeToExec(GetBuffer()->GetEndAddress()), GetBuffer()->GetStartAddress(), GetBuffer()->GetEndAddress()); recompiler::advance(GetBuffer()->GetSizeInBytes()); + JITWriteProtect(true); } }; diff --git a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp index 1ebab685e..9a0bd213d 100644 --- a/core/hw/sh4/dyna/driver.cpp +++ b/core/hw/sh4/dyna/driver.cpp @@ -409,7 +409,6 @@ static void recSh4_Init() // Ensure the pointer returned is non-null verify(CodeCache != NULL); - memset(CodeCache, 0xFF, CODE_SIZE + TEMP_CODE_SIZE); TempCodeCache = CodeCache + CODE_SIZE; ngen_init(); bm_ResetCache(); diff --git a/core/linux/posix_vmem.cpp b/core/linux/posix_vmem.cpp index 797f58d35..69f32fcac 100644 --- a/core/linux/posix_vmem.cpp +++ b/core/linux/posix_vmem.cpp @@ -245,11 +245,21 @@ bool vmem_platform_prepare_jit_block(void *code_area, unsigned size, void **code { // Well it failed, use another approach, unmap the memory area and remap it back. // Seems it works well on Darwin according to reicast code :P + #ifndef __ARM_MAC__ munmap(code_area, size); void *ret_ptr = mmap(code_area, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0); // Ensure it's the area we requested if (ret_ptr != code_area) return false; // Couldn't remap it? Perhaps RWX is disabled? This should never happen in any supported Unix platform. + #else + // MAP_JIT and toggleable write protection is required on Apple Silicon + // Cannot use MAP_FIXED with MAP_JIT + void *ret_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1, 0); + if ( ret_ptr == MAP_FAILED ) + return false; + *code_area_rwx = ret_ptr; + return true; + #endif } // Pointer location should be same: diff --git a/core/rec-ARM64/rec_arm64.cpp b/core/rec-ARM64/rec_arm64.cpp index 08dc38329..045be856c 100644 --- a/core/rec-ARM64/rec_arm64.cpp +++ b/core/rec-ARM64/rec_arm64.cpp @@ -280,6 +280,7 @@ public: void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) { //printf("REC-ARM64 compiling %08x\n", block->addr); + JITWriteProtect(false); this->block = block; CheckBlock(force_checks, block); @@ -961,6 +962,7 @@ public: RelinkBlock(block); Finalize(); + JITWriteProtect(true); } void ngen_CC_Start(shil_opcode* op) @@ -1550,11 +1552,18 @@ private: void GenCallRuntime(R (*function)(P...)) { ptrdiff_t offset = reinterpret_cast(function) - reinterpret_cast(CC_RW2RX(GetBuffer()->GetStartAddress())); - verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024); verify((offset & 3) == 0); - Label function_label; - BindToOffset(&function_label, offset); - Bl(&function_label); + if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024) + { + Mov(x4, reinterpret_cast(function)); + Blr(x4); + } + else + { + Label function_label; + BindToOffset(&function_label, offset); + Bl(&function_label); + } } void GenCall(DynaCode *function) @@ -1571,14 +1580,34 @@ private: void GenBranchRuntime(R (*target)(P...), Condition cond = al) { ptrdiff_t offset = reinterpret_cast(target) - reinterpret_cast(CC_RW2RX(GetBuffer()->GetStartAddress())); - verify(offset >= -128 * 1024 * 1024 && offset <= 128 * 1024 * 1024); verify((offset & 3) == 0); - Label target_label; - BindToOffset(&target_label, offset); - if (cond == al) - B(&target_label); + if (offset < -128 * 1024 * 1024 || offset > 128 * 1024 * 1024) + { + if (cond == al) + { + Mov(x4, reinterpret_cast(target)); + Br(x4); + } + else + { + Label skip_target; + Condition inverse_cond = (Condition)((u32)cond ^ 1); + + B(&skip_target, inverse_cond); + Mov(x4, reinterpret_cast(target)); + Br(x4); + Bind(&skip_target); + } + } else - B(&target_label, cond); + { + Label target_label; + BindToOffset(&target_label, offset); + if (cond == al) + B(&target_label); + else + B(&target_label, cond); + } } void GenBranch(DynaCode *code, Condition cond = al) @@ -2150,8 +2179,8 @@ private: std::vector call_fregs; Arm64RegAlloc regalloc; RuntimeBlockInfo* block = NULL; - const int read_memory_rewrite_size = 3; // ubfx, add, ldr - const int write_memory_rewrite_size = 3; // ubfx, add, str + const int read_memory_rewrite_size = 5; // ubfx, add, ldr + const int write_memory_rewrite_size = 5; // ubfx, add, str }; static Arm64Assembler* compiler; @@ -2222,6 +2251,7 @@ static const u32 op_sizes[] = { }; bool ngen_Rewrite(host_context_t &context, void *faultAddress) { + JITWriteProtect(false); //LOGI("ngen_Rewrite pc %zx\n", context.pc); u32 *code_ptr = (u32 *)CC_RX2RW(context.pc); u32 armv8_op = *code_ptr; @@ -2253,6 +2283,7 @@ bool ngen_Rewrite(host_context_t &context, void *faultAddress) assembler->Finalize(true); delete assembler; context.pc = (unat)CC_RW2RX(code_rewrite); + JITWriteProtect(true); return true; } @@ -2261,12 +2292,14 @@ static void generate_mainloop() { if (mainloop != nullptr) return; + JITWriteProtect(false); compiler = new Arm64Assembler(); compiler->GenMainloop(); delete compiler; compiler = nullptr; + JITWriteProtect(true); } RuntimeBlockInfo* ngen_AllocateBlock() @@ -2284,11 +2317,13 @@ u32 DynaRBI::Relink() { #ifndef NO_BLOCK_LINKING //printf("DynaRBI::Relink %08x\n", this->addr); + JITWriteProtect(false); Arm64Assembler *compiler = new Arm64Assembler((u8 *)this->code + this->relink_offset); u32 code_size = compiler->RelinkBlock(this); compiler->Finalize(true); delete compiler; + JITWriteProtect(true); return code_size; #else diff --git a/core/stdclass.h b/core/stdclass.h index 7965ffa03..d47265818 100644 --- a/core/stdclass.h +++ b/core/stdclass.h @@ -12,7 +12,11 @@ #undef PAGE_MASK #define PAGE_MASK (PAGE_SIZE-1) #else +#if defined(__APPLE__) && defined(__aarch64__) +#define PAGE_SIZE 16384 +#else #define PAGE_SIZE 4096 +#endif #define PAGE_MASK (PAGE_SIZE-1) #endif diff --git a/core/types.h b/core/types.h index a00554975..a7a73af23 100644 --- a/core/types.h +++ b/core/types.h @@ -139,6 +139,14 @@ enum HollyInterruptID int darw_printf(const char* Text,...); #endif +#if defined(__APPLE__) && defined(__MACH__) && HOST_CPU == CPU_ARM64 + #define __ARM_MAC__ + #include "pthread.h" + static void JITWriteProtect(bool enabled) { if (__builtin_available(macOS 11.0, *)) pthread_jit_write_protect_np(enabled); } +#else + __forceinline static void JITWriteProtect(bool enabled) {} +#endif + //includes from c++rt #include #include diff --git a/shell/android-studio/.gitignore b/shell/android-studio/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/shell/android-studio/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/shell/android-studio/build.gradle b/shell/android-studio/build.gradle index dc16a262c..5fce4d0c8 100644 --- a/shell/android-studio/build.gradle +++ b/shell/android-studio/build.gradle @@ -2,16 +2,16 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath "com.android.tools.build:gradle:7.0.0" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files } } -allprojects { - repositories { - google() - jcenter() - } +task clean(type: Delete) { + delete rootProject.buildDir } diff --git a/shell/android-studio/flycast/.gitignore b/shell/android-studio/flycast/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/shell/android-studio/flycast/.gitignore @@ -0,0 +1 @@ +/build diff --git a/shell/android-studio/flycast/build.gradle b/shell/android-studio/flycast/build.gradle index c26542a0b..1e58aedef 100644 --- a/shell/android-studio/flycast/build.gradle +++ b/shell/android-studio/flycast/build.gradle @@ -1,17 +1,5 @@ -apply plugin: 'com.android.application' - -def getBuildId = { -> - def build_id = System.getenv("TRAVIS_JOB_ID") ?: "8" - return Integer.parseInt(build_id) -} - -def getVersionHash = { -> - def stdout = new ByteArrayOutputStream() - exec { - commandLine 'git', 'rev-parse', '--short', 'HEAD' - standardOutput = stdout - } - return stdout.toString().trim() +plugins { + id 'com.android.application' } def getVersionName = { -> @@ -24,13 +12,13 @@ def getVersionName = { -> } android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "com.flycast.emulator" minSdkVersion 16 - targetSdkVersion 28 - versionCode getBuildId() + targetSdkVersion 29 + versionCode 8 versionName getVersionName() vectorDrawables.useSupportLibrary = true @@ -52,56 +40,31 @@ android { } buildTypes { - debug { - debuggable true - minifyEnabled true - zipAlignEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } release { - debuggable false minifyEnabled true - zipAlignEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug } } - + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } externalNativeBuild { cmake { + path file('../../../CMakeLists.txt') version '3.10.2+' - path '../../../CMakeLists.txt' } } - lintOptions { - abortOnError false - } buildFeatures { prefab true } } -afterEvaluate { - android.applicationVariants.all { v -> - if (v.buildType.name == "release") { -// def hashtag = getVersionHash() -// v.outputs[0].outputFileName = "flycast-android-" + hashtag + ".apk" - } - } -} - dependencies { - implementation 'com.android.support:support-v4:28.0.0' - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support:design:28.0.0' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - implementation 'org.bouncycastle:bcprov-jdk16:1.46' - implementation 'commons-io:commons-io:2.6' - implementation 'org.apache.commons:commons-lang3:3.10' - implementation('com.googlecode.json-simple:json-simple:1.1.1') { - exclude module: 'junit' - } - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.google.oboe:oboe:1.5.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.oboe:oboe:1.6.1' + implementation 'org.apache.commons:commons-lang3:3.12.0' + implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: []) } diff --git a/shell/android-studio/flycast/libs/image-uniload.jar b/shell/android-studio/flycast/libs/image-uniload.jar deleted file mode 100644 index c13c71cac..000000000 Binary files a/shell/android-studio/flycast/libs/image-uniload.jar and /dev/null differ diff --git a/shell/android-studio/flycast/proguard-rules.pro b/shell/android-studio/flycast/proguard-rules.pro new file mode 100644 index 000000000..03b500879 --- /dev/null +++ b/shell/android-studio/flycast/proguard-rules.pro @@ -0,0 +1,24 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-keep class com.reicast.** {*;} +-keepclassmembers class com.reicast.** {*;} diff --git a/shell/android-studio/flycast/proguard-rules.txt b/shell/android-studio/flycast/proguard-rules.txt deleted file mode 100644 index 7b3d38a1d..000000000 --- a/shell/android-studio/flycast/proguard-rules.txt +++ /dev/null @@ -1,69 +0,0 @@ -# This is a configuration file for ProGuard. -# http://proguard.sourceforge.net/index.html#manual/usage.html -# Optimizations: If you don't want to optimize, use the -# proguard-android.txt configuration file instead of this one, which -# turns off the optimization flags. Adding optimization introduces -# certain risks, since for example not all optimizations performed by -# ProGuard works on all versions of Dalvik. The following flags turn -# off various optimizations known to have issues, but the list may not -# be complete or up to date. (The "arithmetic" optimization can be -# used if you are only targeting Android 2.0 or later.) Make sure you -# test thoroughly if you go this route. --optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* --optimizationpasses 5 --allowaccessmodification --dontpreverify -# The remainder of this file is identical to the non-optimized version -# of the Proguard configuration file (except that the other file has -# flags to turn off optimization). --dontusemixedcaseclassnames --dontskipnonpubliclibraryclasses --verbose --keepattributes *Annotation* -# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native --keepclasseswithmembernames class * { - native ; -} -# keep setters in Views so that animations can still work. -# see http://proguard.sourceforge.net/manual/examples.html#beans --keepclassmembers public class * extends android.view.View { - void set*(***); - *** get*(); -} -# We want to keep methods in Activity that could be used in the XML attribute onClick --keepclassmembers class * extends android.app.Activity { - public void *(android.view.View); -} -# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} --keepclassmembers class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator CREATOR; -} --keepclassmembers class **.R$* { - public static ; -} - --keep class com.reicast.** {*;} --keepclassmembers class com.reicast.** {*;} - -# The support library contains references to newer platform versions. -# Don't warn about those in case this app is linking against an older -# platform version. We know about them, and they are safe. --dontwarn android.support.** --dontwarn okio.** --dontwarn okhttp3.** --dontwarn com.squareup.okhttp.** --dontwarn com.google.appengine.** --dontwarn java.io.** --dontwarn java.nio.file.** --dontwarn javax.naming.** --dontwarn javax.servlet.** --dontwarn junit.textui.** - --keepattributes Signature --keepattributes InnerClasses - --keepattributes Exceptions,SourceFile,LineNumberTable diff --git a/shell/android-studio/flycast/src/main/AndroidManifest.xml b/shell/android-studio/flycast/src/main/AndroidManifest.xml index b4488550f..e61bfb451 100644 --- a/shell/android-studio/flycast/src/main/AndroidManifest.xml +++ b/shell/android-studio/flycast/src/main/AndroidManifest.xml @@ -42,7 +42,8 @@ android:banner="@drawable/ic_banner" android:logo="@drawable/ic_banner" android:hardwareAccelerated="true" - android:isGame="true"> + android:isGame="true" + android:requestLegacyExternalStorage="true"> diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java index 8103cb351..282802e25 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java @@ -13,18 +13,18 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityCompat; import android.util.Log; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.View; import android.view.ViewConfiguration; import android.view.Window; import android.view.WindowManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; + import com.reicast.emulator.config.Config; import com.reicast.emulator.debug.GenerateLogs; import com.reicast.emulator.emu.AudioBackend; @@ -236,7 +236,15 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat. return true; } else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { - InputDeviceManager.getInstance().mouseEvent(Math.round(event.getX()), Math.round(event.getY()), event.getButtonState()); + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: + InputDeviceManager.getInstance().mouseScrollEvent(Math.round(-event.getAxisValue(MotionEvent.AXIS_VSCROLL))); + break; + default: + InputDeviceManager.getInstance().mouseEvent(Math.round(event.getX()), Math.round(event.getY()), event.getButtonState()); + break; + } + return true; } return super.onGenericMotionEvent(event); } diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/Emulator.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/Emulator.java index 54961da0f..9aa53d8d4 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/Emulator.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/Emulator.java @@ -4,9 +4,10 @@ import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.v7.app.AppCompatDelegate; import android.util.Log; +import androidx.appcompat.app.AppCompatDelegate; + import com.reicast.emulator.config.Config; import com.reicast.emulator.emu.JNIdc; diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/FileBrowser.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/FileBrowser.java index b32e103d6..9885256e0 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/FileBrowser.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/FileBrowser.java @@ -6,7 +6,7 @@ import java.io.InputStream; import java.util.HashSet; public class FileBrowser { - android.support.v4.content.FileProvider provider; // To avoid ClassNotFoundException at runtime + androidx.core.content.FileProvider provider; // To avoid ClassNotFoundException at runtime public static HashSet getExternalMounts() { final HashSet out = new HashSet<>(); diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/NativeGLActivity.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/NativeGLActivity.java index ab1efebc4..a906ec042 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/NativeGLActivity.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/NativeGLActivity.java @@ -1,11 +1,12 @@ package com.reicast.emulator; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.ViewGroup; import android.view.Window; import android.widget.RelativeLayout; +import androidx.annotation.Nullable; + import com.reicast.emulator.emu.JNIdc; import com.reicast.emulator.emu.NativeGLView; import com.reicast.emulator.periph.VJoy; diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/JNIdc.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/JNIdc.java index aa97c9ca2..9bafdcf9a 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/JNIdc.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/JNIdc.java @@ -19,7 +19,7 @@ public final class JNIdc public static native void rendinitNative(Surface surface, int w, int h); - public static native void vjoy(int id,float x, float y, float w, float h); + public static native void vjoy(int id, float x, float y, float w, float h); public static native void getControllers(int[] controllers, int[][] peripherals); @@ -37,5 +37,5 @@ public final class JNIdc } public static native void hideOsd(); - public static native void setButtons(byte data[]); + public static native void setButtons(byte[] data); } diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java index dabcf05aa..814a9e355 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java @@ -15,8 +15,7 @@ import android.view.View; import android.view.WindowInsets; import com.reicast.emulator.Emulator; -import com.reicast.emulator.NativeGLActivity; -import com.reicast.emulator.config.Config; +import com.reicast.emulator.periph.InputDeviceManager; public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback { private boolean surfaceReady = false; @@ -87,7 +86,13 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback @Override public boolean onTouchEvent(final MotionEvent event) { - return vjoyDelegate.onTouchEvent(event, getWidth(), getHeight()); + if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { + // Mouse motion events are reported by onTouchEvent when mouse button is down. Go figure... + InputDeviceManager.getInstance().mouseEvent(Math.round(event.getX()), Math.round(event.getY()), event.getButtonState()); + return true; + } + else + return vjoyDelegate.onTouchEvent(event, getWidth(), getHeight()); } @Override diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java index 984f490d2..687fbd076 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java @@ -10,7 +10,6 @@ import android.view.ScaleGestureDetector; import android.view.View; import com.reicast.emulator.Emulator; -import com.reicast.emulator.R; import com.reicast.emulator.periph.InputDeviceManager; import com.reicast.emulator.periph.VJoy; diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/periph/InputDeviceManager.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/periph/InputDeviceManager.java index 0523d7ac8..33c461dab 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/periph/InputDeviceManager.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/periph/InputDeviceManager.java @@ -96,6 +96,7 @@ public final class InputDeviceManager implements InputManager.InputDeviceListene public native boolean joystickButtonEvent(int id, int button, boolean pressed); public native boolean joystickAxisEvent(int id, int button, int value); public native void mouseEvent(int xpos, int ypos, int buttons); + public native void mouseScrollEvent(int scrollValue); private native void joystickAdded(int id, String name, int maple_port, String uniqueId); private native void joystickRemoved(int id); } diff --git a/shell/android-studio/flycast/src/main/jni/src/Android.cpp b/shell/android-studio/flycast/src/main/jni/src/Android.cpp index 8470a9854..62b6d7bf5 100644 --- a/shell/android-studio/flycast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/flycast/src/main/jni/src/Android.cpp @@ -1,17 +1,4 @@ -#include -#include -#include -#include -#include -#include -#include -#include - #include "types.h" -#include -#include -#include - #include "hw/maple/maple_cfg.h" #include "rend/osd.h" #include "hw/maple/maple_devs.h" @@ -31,6 +18,17 @@ #include "client/linux/handler/exception_handler.h" #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + JavaVM* g_jvm; // Convenience class to get the java environment for the current thread. @@ -77,55 +75,12 @@ static thread_local JVMAttacher jvm_attacher; #include "android_gamepad.h" -#define SETTINGS_ACCESSORS(setting, type) \ -JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## setting(JNIEnv *env, jobject obj) __attribute__((visibility("default"))); \ -JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## setting(JNIEnv *env, jobject obj) \ -{ \ - return (type)config::setting; \ +extern "C" JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_getVirtualGamepadVibration(JNIEnv *env, jobject obj) +{ + return (jint)config::VirtualGamepadVibration; } -extern "C" -{ -JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator, jstring filesDirectory, jstring homeDirectory, jstring locale) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setExternalStorageDirectories(JNIEnv *env, jobject obj, jobjectArray pathList) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setGameUri(JNIEnv *env,jobject obj,jstring fileName) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jobject obj,int id,float x, float y, float w, float h) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_hideOsd(JNIEnv * env, jobject obj) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv *env, jobject obj, jintArray controllers, jobjectArray peripherals) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) __attribute__((visibility("default"))); - -SETTINGS_ACCESSORS(VirtualGamepadVibration, jint); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env,jobject obj, jint screenDpi) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsContentBrowser(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setButtons(JNIEnv *env, jobject obj, jbyteArray data) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiSetInsets(JNIEnv *env, jobject obj, jint left, jint right, jint top, jint bottom) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port, jstring junique_id) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickRemoved(JNIEnv *env, jobject obj, jint id) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_virtualGamepadEvent(JNIEnv *env, jobject obj, jint kcode, jint joyx, jint joyy, jint lt, jint rt) __attribute__((visibility("default"))); -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickButtonEvent(JNIEnv *env, jobject obj, jint id, jint key, jboolean pressed) __attribute__((visibility("default"))); -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAxisEvent(JNIEnv *env, jobject obj, jint id, jint key, jint value) __attribute__((visibility("default"))); -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouseEvent(JNIEnv *env, jobject obj, jint xpos, jint ypos, jint buttons) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance) __attribute__((visibility("default"))); - -JNIEXPORT void JNICALL Java_com_reicast_emulator_BaseGLActivity_register(JNIEnv *env, jobject obj, jobject activity) __attribute__((visibility("default"))); -}; - -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env,jobject obj, jint screenDpi) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env, jobject obj, jint screenDpi) { screen_dpi = screenDpi; } @@ -191,7 +146,7 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, static google_breakpad::ExceptionHandler *exceptionHandler; #endif -JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator, jstring filesDirectory, jstring homeDirectory, jstring locale) +extern "C" JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JNIEnv *env, jobject obj, jobject emulator, jstring filesDirectory, jstring homeDirectory, jstring locale) { #if defined(USE_BREAKPAD) if (exceptionHandler == nullptr) @@ -272,7 +227,7 @@ JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JN return NULL; } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setExternalStorageDirectories(JNIEnv *env, jobject obj, jobjectArray pathList) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setExternalStorageDirectories(JNIEnv *env, jobject obj, jobjectArray pathList) { std::string paths; int obj_len = env->GetArrayLength(pathList); @@ -289,7 +244,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setExternalStorageDir gui_refresh_files(); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setGameUri(JNIEnv *env,jobject obj,jstring fileName) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setGameUri(JNIEnv *env,jobject obj,jstring fileName) { if (fileName != NULL) { @@ -321,7 +276,7 @@ jmethodID audioInitMid; jmethodID audioTermMid; static jobject g_audioBackend; -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) { sipemu = env->NewGlobalRef(sip); getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","(I)[B"); @@ -329,7 +284,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env, stopRecordingMid = env->GetMethodID(env->GetObjectClass(sipemu),"stopRecording","()V"); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) { if (game_started) { @@ -340,13 +295,13 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,job } } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj) { if (game_started) dc_resume(); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) { if (dc_is_running()) { dc_stop(); @@ -358,7 +313,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobj settings.imgread.ImagePath[0] = '\0'; } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) { dc_term(); } @@ -382,7 +337,7 @@ static void *render_thread_func(void *) static cThread render_thread(render_thread_func, NULL); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height) { if (render_thread.thread.joinable()) { @@ -405,7 +360,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv } } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jobject obj,int id,float x, float y, float w, float h) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jobject obj,int id,float x, float y, float w, float h) { if (id < ARRAY_SIZE(vjoy_pos)) { @@ -416,11 +371,12 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jo } } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_hideOsd(JNIEnv * env, jobject obj) { +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_hideOsd(JNIEnv * env, jobject obj) +{ HideOSD(); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv *env, jobject obj, jintArray controllers, jobjectArray peripherals) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv *env, jobject obj, jintArray controllers, jobjectArray peripherals) { jint *controllers_body = env->GetIntArrayElements(controllers, 0); for (u32 i = 0; i < config::MapleMainDevices.size(); i++) @@ -438,22 +394,22 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv } } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEnv *env, jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEnv *env, jobject obj) { gui_open_settings(); } -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv *env, jobject obj) +extern "C" JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv *env, jobject obj) { return gui_is_open(); } -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsContentBrowser(JNIEnv *env,jobject obj) +extern "C" JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsContentBrowser(JNIEnv *env,jobject obj) { return gui_is_content_browser(); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiSetInsets(JNIEnv *env, jobject obj, jint left, jint right, jint top, jint bottom) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiSetInsets(JNIEnv *env, jobject obj, jint left, jint right, jint top, jint bottom) { gui_set_insets(left, right, top, bottom); } @@ -517,7 +473,7 @@ audiobackend_t audiobackend_android = { static bool android = RegisterAudioBackend(&audiobackend_android); -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance) { if (g_audioBackend != NULL) env->DeleteGlobalRef(g_audioBackend); @@ -559,7 +515,7 @@ void SaveAndroidSettings() jvm_attacher.getEnv()->DeleteLocalRef(homeDirectory); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) { input_device_manager = env->NewGlobalRef(obj); input_device_manager_rumble = env->GetMethodID(env->GetObjectClass(obj), "rumble", "(IFFI)Z"); @@ -568,7 +524,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init( GamepadDevice::Register(mouse); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port, jstring junique_id) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port, jstring junique_id) { const char* joyname = env->GetStringUTFChars(name,0); const char* unique_id = env->GetStringUTFChars(junique_id, 0); @@ -577,21 +533,21 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joyst env->ReleaseStringUTFChars(name, joyname); env->ReleaseStringUTFChars(name, unique_id); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickRemoved(JNIEnv *env, jobject obj, jint id) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickRemoved(JNIEnv *env, jobject obj, jint id) { std::shared_ptr device = AndroidGamepadDevice::GetAndroidGamepad(id); if (device != NULL) AndroidGamepadDevice::RemoveAndroidGamepad(device); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_virtualGamepadEvent(JNIEnv *env, jobject obj, jint kcode, jint joyx, jint joyy, jint lt, jint rt) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_virtualGamepadEvent(JNIEnv *env, jobject obj, jint kcode, jint joyx, jint joyy, jint lt, jint rt) { std::shared_ptr device = AndroidGamepadDevice::GetAndroidGamepad(AndroidGamepadDevice::VIRTUAL_GAMEPAD_ID); if (device != NULL) device->virtual_gamepad_event(kcode, joyx, joyy, lt, rt); } -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickButtonEvent(JNIEnv *env, jobject obj, jint id, jint key, jboolean pressed) +extern "C" JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickButtonEvent(JNIEnv *env, jobject obj, jint id, jint key, jboolean pressed) { std::shared_ptr device = AndroidGamepadDevice::GetAndroidGamepad(id); if (device != NULL) @@ -603,7 +559,7 @@ JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_j static std::map, jint> previous_axis_values; -JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAxisEvent(JNIEnv *env, jobject obj, jint id, jint key, jint value) +extern "C" JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAxisEvent(JNIEnv *env, jobject obj, jint id, jint key, jint value) { std::shared_ptr device = AndroidGamepadDevice::GetAndroidGamepad(id); // Only handle Left Stick on an Xbox 360 controller if there was actual @@ -617,7 +573,7 @@ JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_j return false; } -JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouseEvent(JNIEnv *env, jobject obj, jint xpos, jint ypos, jint buttons) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouseEvent(JNIEnv *env, jobject obj, jint xpos, jint ypos, jint buttons) { mouse->setAbsPos(xpos, ypos, screen_width, screen_height); mouse->setButton(Mouse::LEFT_BUTTON, (buttons & 1) != 0); @@ -625,12 +581,17 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouse mouse->setButton(Mouse::MIDDLE_BUTTON, (buttons & 4) != 0); } +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouseScrollEvent(JNIEnv *env, jobject obj, jint scrollValue) +{ + mouse->setWheel(scrollValue); +} + static jobject g_activity; static jmethodID VJoyStartEditingMID; static jmethodID VJoyStopEditingMID; static jmethodID VJoyResetEditingMID; -JNIEXPORT void JNICALL Java_com_reicast_emulator_BaseGLActivity_register(JNIEnv *env, jobject obj, jobject activity) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_BaseGLActivity_register(JNIEnv *env, jobject obj, jobject activity) { if (g_activity != NULL) { @@ -667,7 +628,7 @@ void android_send_logs() env->CallVoidMethod(g_activity, generateErrorLogMID); } -JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setButtons(JNIEnv *env, jobject obj, jbyteArray data) +extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setButtons(JNIEnv *env, jobject obj, jbyteArray data) { u32 len = env->GetArrayLength(data); DefaultOSDButtons.resize(len); diff --git a/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h b/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h index 97e2e7417..1c1da7b19 100644 --- a/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h +++ b/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with reicast. If not, see . */ +#pragma once #include "input/gamepad_device.h" diff --git a/shell/android-studio/flycast/src/main/jni/src/utils.cpp b/shell/android-studio/flycast/src/main/jni/src/utils.cpp deleted file mode 100644 index ec29ffbd3..000000000 --- a/shell/android-studio/flycast/src/main/jni/src/utils.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "types.h" -#include - -zip* APKArchive; -void setAPK (const char* apkPath) { - INFO_LOG(COMMON, "Loading APK %s", apkPath); - APKArchive = zip_open(apkPath, 0, NULL); - if (APKArchive == NULL) { - ERROR_LOG(COMMON, "Error loading APK"); - return; - } - - //Just for debug, print APK contents - int numFiles = zip_get_num_files(APKArchive); - for (int i=0; i/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/shell/android-studio/gradlew.bat b/shell/android-studio/gradlew.bat index aec99730b..e95643d6a 100644 --- a/shell/android-studio/gradlew.bat +++ b/shell/android-studio/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/shell/android-studio/settings.gradle b/shell/android-studio/settings.gradle index 033b93719..f471153b0 100644 --- a/shell/android-studio/settings.gradle +++ b/shell/android-studio/settings.gradle @@ -1 +1,10 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + jcenter() // Warning: this repository is going to shut down soon + } +} +rootProject.name = "Flycast" include ':flycast' diff --git a/shell/apple/emulator-osx/emulator-osx/DreamcastConfig.xcconfig b/shell/apple/emulator-osx/emulator-osx/DreamcastConfig.xcconfig index e5ebfd333..6a1970cca 100644 --- a/shell/apple/emulator-osx/emulator-osx/DreamcastConfig.xcconfig +++ b/shell/apple/emulator-osx/emulator-osx/DreamcastConfig.xcconfig @@ -7,5 +7,4 @@ REI_APP_NAME = Flycast PRODUCT_NAME = Flycast CFLAGS = - - +LIBSDL = /usr/local/lib/libSDL2.a diff --git a/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift b/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift index dee89d238..957482c19 100644 --- a/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift +++ b/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift @@ -10,18 +10,30 @@ import Cocoa class EmuGLView: NSOpenGLView, NSWindowDelegate { + var backingRect:NSRect? + override var acceptsFirstResponder: Bool { return true; } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - - openGLContext!.makeCurrentContext() + backingRect = convertToBacking(dirtyRect) - let rect = convertToBacking(dirtyRect) - if (emu_single_frame(Int32(rect.width), Int32(rect.height)) != 0) { - openGLContext!.flushBuffer() + if emu_fast_forward() == false { + draw() + } + } + + func draw() { + var sync: GLint = emu_fast_forward() ? 0 : 1 + CGLSetParameter(openGLContext!.cglContextObj!, kCGLCPSwapInterval, &sync) + + if let backingRect = backingRect { + openGLContext!.makeCurrentContext() + if (emu_single_frame(Int32(backingRect.width), Int32(backingRect.height)) != 0) { + openGLContext!.flushBuffer() + } } } @@ -69,7 +81,11 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate { NSApplication.shared.terminate(self) } else if (emu_frame_pending()) { - self.needsDisplay = true + if emu_fast_forward() { + self.draw() + } else { + self.needsDisplay = true + } } } diff --git a/shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h b/shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h index 3e7820695..980039a65 100644 --- a/shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h +++ b/shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h @@ -18,6 +18,7 @@ void emu_dc_exit(); void emu_dc_term(); void emu_gui_open_settings(); bool emu_renderer_enabled(); +bool emu_fast_forward(); int emu_single_frame(int w, int h); void emu_gles_init(int width, int height); int emu_reicast_init(); diff --git a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm index ef7b293ef..0360e378e 100644 --- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm +++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm @@ -126,6 +126,11 @@ bool emu_renderer_enabled() return mainui_loop_enabled(); } +bool emu_fast_forward() +{ + return settings.input.fastForwardMode; +} + int emu_single_frame(int w, int h) { if (!emu_frame_pending()) diff --git a/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj b/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj index e06e4c3e3..cf9c8be6b 100644 --- a/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj +++ b/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj @@ -306,7 +306,6 @@ AEE6278822131BB500EC7E89 /* mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6278522131BB500EC7E89 /* mapping.cpp */; }; AEE6278E2224762000EC7E89 /* imgui_impl_opengl3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6278B2224762000EC7E89 /* imgui_impl_opengl3.cpp */; }; AEE6279422247C0A00EC7E89 /* gui_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279222247C0A00EC7E89 /* gui_util.cpp */; }; - AEE6279622247C2B00EC7E89 /* keyboard_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */; }; AEF25646227C442F00348550 /* fastmmu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF25644227C442F00348550 /* fastmmu.cpp */; }; AEF2564822886A2E00348550 /* posix_vmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF2564722886A2E00348550 /* posix_vmem.cpp */; }; AEF256502294060400348550 /* ZipArchive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF2564A2294060300348550 /* ZipArchive.cpp */; }; @@ -942,7 +941,6 @@ AEE6278D2224762000EC7E89 /* imgui_impl_opengl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_opengl3.h; sourceTree = ""; }; AEE6279222247C0A00EC7E89 /* gui_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gui_util.cpp; sourceTree = ""; }; AEE6279322247C0A00EC7E89 /* gui_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gui_util.h; sourceTree = ""; }; - AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keyboard_device.cpp; sourceTree = ""; }; AEF25644227C442F00348550 /* fastmmu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fastmmu.cpp; sourceTree = ""; }; AEF25645227C442F00348550 /* wince.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wince.h; sourceTree = ""; }; AEF2564722886A2E00348550 /* posix_vmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = posix_vmem.cpp; sourceTree = ""; }; @@ -1529,6 +1527,7 @@ 84B7BDCF1B72720100F9733F /* dsp.h */, AE8C27332111A31100D4D8F4 /* dsp_interp.cpp */, AE7BCB512406EDB0007285F8 /* dsp_x64.cpp */, + F2D7C89E265B304F002812E2 /* dsp_arm64.cpp */, 84B7BDD01B72720100F9733F /* sgc_if.cpp */, 84B7BDD11B72720100F9733F /* sgc_if.h */, ); @@ -1539,6 +1538,7 @@ isa = PBXGroup; children = ( AE7BCB562415515B007285F8 /* arm7_rec_x64.cpp */, + F2D7C8A2265B3082002812E2 /* arm7_rec_arm64.cpp */, AE7BCB572415515B007285F8 /* arm7_rec.cpp */, AE7BCB552415515B007285F8 /* arm7_rec.h */, 84B7BDD31B72720100F9733F /* arm-new.h */, @@ -2745,6 +2745,7 @@ 84B7BF2A1B72720200F9733F /* arm7.cpp in Sources */, AE90679D235DF80400CE473C /* osd.cpp in Sources */, AE82C67D25B64AE200C79BC2 /* zip_get_name.c in Sources */, + F2D7C8A3265B3082002812E2 /* arm7_rec_arm64.cpp in Sources */, 84B7BF551B72720200F9733F /* sh4_mem.cpp in Sources */, AE82C69F25B64AE200C79BC2 /* zip_open.c in Sources */, AE649C2C218C553A00EF4A81 /* Lzma86Enc.c in Sources */, @@ -2912,6 +2913,7 @@ 84B7BF771B72720200F9733F /* reios_elf.cpp in Sources */, AE9125CC25E3BBDC00ED4594 /* option.cpp in Sources */, 84B7BF5C1B72720200F9733F /* common.cpp in Sources */, + F2D7C89F265B304F002812E2 /* dsp_arm64.cpp in Sources */, AE82C6BE25B64AE200C79BC2 /* zip_source_crc.c in Sources */, 84B7BF681B72720200F9733F /* audiobackend_directsound.cpp in Sources */, AE2A2D5C21D68470004B308D /* awcartridge.cpp in Sources */, @@ -3163,7 +3165,7 @@ ); INFOPLIST_FILE = "emulator-osx/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - OTHER_LDFLAGS = /usr/local/lib/libSDL2.a; + OTHER_LDFLAGS = "$(LIBSDL)"; OTHER_LIBTOOLFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.flyinghead.Flycast; PRODUCT_NAME = "$(REI_APP_NAME)"; @@ -3215,7 +3217,7 @@ ); INFOPLIST_FILE = "emulator-osx/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - OTHER_LDFLAGS = /usr/local/lib/libSDL2.a; + OTHER_LDFLAGS = "$(LIBSDL)"; OTHER_LIBTOOLFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.flyinghead.Flycast; PRODUCT_NAME = "$(REI_APP_NAME)"; diff --git a/shell/apple/emulator-osx/reicast-osx.xcodeproj/xcshareddata/xcschemes/reicast-osx.xcscheme b/shell/apple/emulator-osx/reicast-osx.xcodeproj/xcshareddata/xcschemes/reicast-osx.xcscheme index 544fff583..2f483cec1 100644 --- a/shell/apple/emulator-osx/reicast-osx.xcodeproj/xcshareddata/xcschemes/reicast-osx.xcscheme +++ b/shell/apple/emulator-osx/reicast-osx.xcodeproj/xcshareddata/xcschemes/reicast-osx.xcscheme @@ -1,10 +1,28 @@ + version = "1.7"> + + + + + + + + + +