diff --git a/.cirrus.yml b/.cirrus.yml index e101e5d7d..e2fd64a7d 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,5 @@ freebsd_instance: - image_family: freebsd-12-2 + image_family: freebsd-13-0 env: CCACHE_DIR: /tmp/ccache diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..8dcaf19dd --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ['https://utip.io/flyinghead', 'https://www.paypal.com/paypalme/FlycastEmu'] diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index a39a4cf0c..bedea4e8b 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -54,7 +54,7 @@ jobs: if: matrix.config.os == 'windows-latest' - name: Download DX2010 - if: steps.cache.outputs.cache-hit != 'true' && matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32' && matrix.config.name != 'libretro-x86_64-w64-mingw32' + if: matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32' && matrix.config.name != 'libretro-x86_64-w64-mingw32' run: | curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe 7z x _DX2010_.exe DXSDK/Include -o_DX2010_ diff --git a/CMakeLists.txt b/CMakeLists.txt index 6542dd131..52914c4ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1178,6 +1178,7 @@ if(NOT LIBRETRO) shell/apple/emulator-ios/emulator/AppDelegate.mm shell/apple/emulator-ios/emulator/ios_main.mm shell/apple/emulator-ios/emulator/ios_gamepad.h + shell/apple/emulator-ios/emulator/ios_keyboard.h shell/apple/emulator-ios/emulator/FlycastViewController.h shell/apple/emulator-ios/emulator/FlycastViewController.mm shell/apple/emulator-ios/emulator/PadViewController.h diff --git a/core/cfg/option.cpp b/core/cfg/option.cpp index c68eb2c91..bd9db6025 100644 --- a/core/cfg/option.cpp +++ b/core/cfg/option.cpp @@ -55,6 +55,7 @@ Option AutoLatency("aica.AutoLatency", ); OptionString AudioBackend("backend", "auto", "audio"); +AudioVolumeOption AudioVolume; // Rendering diff --git a/core/cfg/option.h b/core/cfg/option.h index 87a9a090b..9f0f6c4ee 100644 --- a/core/cfg/option.h +++ b/core/cfg/option.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "cfg.h" #include "hw/maple/maple_cfg.h" #ifdef LIBRETRO @@ -368,6 +369,30 @@ extern Option AutoLatency; extern OptionString AudioBackend; +class AudioVolumeOption : public Option { +public: + AudioVolumeOption() : Option("aica.Volume", 100) {}; + float logarithmic_volume_scale = 1.0; + + void load() override { + Option::load(); + calcDbPower(); + } + + float dbPower() + { + return logarithmic_volume_scale; + } + void calcDbPower() + { + // dB scaling calculation: https://www.dr-lex.be/info-stuff/volumecontrols.html + logarithmic_volume_scale = fmin(exp(4.605 * float(value) / 100.0) / 100.0, 1.0); + if (value < 10) + logarithmic_volume_scale *= value / 10.0; + } +}; +extern AudioVolumeOption AudioVolume; + // Rendering class RendererOption : public Option { diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index 7148174e8..a50f9a549 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -448,10 +448,10 @@ void rend_set_fb_write_addr(u32 fb_w_sof1) fb_w_cur = fb_w_sof1; } -void rend_swap_frame(u32 fb_r_sof1) +void rend_swap_frame(u32 fb_r_sof) { swap_mutex.lock(); - if (fb_r_sof1 == fb_w_cur) + if (fb_r_sof == fb_w_cur) { do_swap = true; if (config::ThreadedRendering) diff --git a/core/hw/pvr/pvr_regs.cpp b/core/hw/pvr/pvr_regs.cpp index 46275ba11..03767ced8 100644 --- a/core/hw/pvr/pvr_regs.cpp +++ b/core/hw/pvr/pvr_regs.cpp @@ -87,12 +87,9 @@ void pvr_WriteReg(u32 paddr,u32 data) return; case FB_R_SOF1_addr: - data &= 0x00fffffc; - rend_swap_frame(data); - break; - case FB_R_SOF2_addr: data &= 0x00fffffc; + rend_swap_frame(data); break; case FB_W_SOF1_addr: diff --git a/core/oslib/audiostream.cpp b/core/oslib/audiostream.cpp index 506bd07a7..f638bb614 100644 --- a/core/oslib/audiostream.cpp +++ b/core/oslib/audiostream.cpp @@ -79,8 +79,8 @@ audiobackend_t* GetAudioBackend(const std::string& slug) void WriteSample(s16 r, s16 l) { - Buffer[writePtr].r = r; - Buffer[writePtr].l = l; + Buffer[writePtr].r = r * config::AudioVolume.dbPower(); + Buffer[writePtr].l = l * config::AudioVolume.dbPower(); if (++writePtr == SAMPLE_COUNT) { diff --git a/core/reios/gdrom_hle.cpp b/core/reios/gdrom_hle.cpp index 90c4b670a..2dfc8035f 100644 --- a/core/reios/gdrom_hle.cpp +++ b/core/reios/gdrom_hle.cpp @@ -23,7 +23,7 @@ #define debugf(...) DEBUG_LOG(REIOS, __VA_ARGS__) -gdrom_hle_state_t gd_hle_state = { 0xffffffff, 2, BIOS_INACTIVE }; +gdrom_hle_state_t gd_hle_state; static void GDROM_HLE_ReadSES() { @@ -644,9 +644,7 @@ void gdrom_hle_op() case GDROM_INIT: // Initialize the GDROM subsystem. Should be called before any requests are enqueued. DEBUG_LOG(REIOS, "GDROM: HLE GDROM_INIT"); - gd_hle_state.last_request_id = 0xFFFFFFFF; - gd_hle_state.next_request_id = 2; - gd_hle_state.status = BIOS_INACTIVE; + gd_hle_state = {}; break; case GDROM_RESET: diff --git a/core/reios/gdrom_hle.h b/core/reios/gdrom_hle.h index b2ed3f1fd..94f61876d 100644 --- a/core/reios/gdrom_hle.h +++ b/core/reios/gdrom_hle.h @@ -49,21 +49,23 @@ void gdrom_hle_op(); typedef enum { BIOS_ERROR = -1, BIOS_INACTIVE, BIOS_ACTIVE, BIOS_COMPLETED, BIOS_DATA_AVAIL } gd_bios_status; struct gdrom_hle_state_t { - u32 last_request_id; - u32 next_request_id; - gd_bios_status status; - u32 command; + gdrom_hle_state_t() : params{}, result{} {} + + u32 last_request_id = 0xFFFFFFFF; + u32 next_request_id = 2; + gd_bios_status status = BIOS_INACTIVE; + u32 command = 0; u32 params[4]; u32 result[4]; - u32 cur_sector; - u32 multi_read_sector; - u32 multi_read_offset; - u32 multi_read_count; - u32 multi_read_total; - u32 multi_callback; - u32 multi_callback_arg; - bool dma_trans_ended; - u64 xfer_end_time; + u32 cur_sector = 0; + u32 multi_read_sector = 0; + u32 multi_read_offset = 0; + u32 multi_read_count = 0; + u32 multi_read_total = 0; + u32 multi_callback = 0; + u32 multi_callback_arg = 0; + bool dma_trans_ended = false; + u64 xfer_end_time = 0; bool Serialize(void **data, unsigned int *total_size) { diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index 97dba83ee..8c47b96a6 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -763,6 +763,7 @@ void reios_reset(u8* rom) else INFO_LOG(REIOS, "font.bin: loaded %zd bytes", size); } + gd_hle_state = {}; } void reios_term() { diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 5b26d2270..a454af79b 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -1476,7 +1476,7 @@ static void gui_display_settings() } OptionCheckbox("Widescreen Game Cheats", config::WidescreenGameHacks, "Modify the game so that it displays in 16:9 anamorphic format and use horizontal screen stretching. Only some games are supported."); -#ifndef __APPLE__ +#ifndef TARGET_IPHONE OptionCheckbox("VSync", config::VSync, "Synchronizes the frame rate with the screen refresh rate. Recommended"); #endif OptionCheckbox("Show FPS Counter", config::ShowFPS, "Show on-screen frame/sec counter"); @@ -1603,6 +1603,10 @@ static void gui_display_settings() ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); OptionCheckbox("Enable DSP", config::DSPEnabled, "Enable the Dreamcast Digital Sound Processor. Only recommended on fast platforms"); + if (OptionSlider("Volume Level", config::AudioVolume, 0, 100, "Adjust the emulator's audio level")) + { + config::AudioVolume.calcDbPower(); + }; #ifdef __ANDROID__ if (config::AudioBackend.get() == "auto" || config::AudioBackend.get() == "android") OptionCheckbox("Automatic Latency", config::AutoLatency, diff --git a/shell/android-studio/build.gradle b/shell/android-studio/build.gradle index 5fce4d0c8..2399827d3 100644 --- a/shell/android-studio/build.gradle +++ b/shell/android-studio/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.0.0" + classpath "com.android.tools.build:gradle:7.0.1" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/shell/android-studio/flycast/src/main/AndroidManifest.xml b/shell/android-studio/flycast/src/main/AndroidManifest.xml index e61bfb451..cd4d29c26 100644 --- a/shell/android-studio/flycast/src/main/AndroidManifest.xml +++ b/shell/android-studio/flycast/src/main/AndroidManifest.xml @@ -50,7 +50,8 @@ android:name="com.reicast.emulator.NativeGLActivity" android:configChanges="orientation|navigation|screenSize|screenLayout|uiMode|keyboard|keyboardHidden" android:screenOrientation="sensorLandscape" - android:exported="true"/> + android:exported="true" + android:theme="@style/Theme.AppCompat.NoActionBar"/> 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 282802e25..1faa9bf7b 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 @@ -42,6 +42,7 @@ import tv.ouya.console.api.OuyaController; import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; public abstract class BaseGLActivity extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback { @@ -66,7 +67,7 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat. // Set the navigation bar color to 0 to avoid left over when it fades out on Android 10 Window window = getWindow(); window.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.clearFlags(FLAG_TRANSLUCENT_STATUS); + window.clearFlags(FLAG_TRANSLUCENT_STATUS | FLAG_TRANSLUCENT_NAVIGATION); window.setNavigationBarColor(0); window.getDecorView().setSystemUiVisibility(SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } 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 687fbd076..90071482b 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 @@ -358,7 +358,8 @@ public class VirtualJoystickDelegate { int joyy = get_anal(11, 1); InputDeviceManager.getInstance().virtualGamepadEvent(rv, joyx, joyy, left_trigger, right_trigger); // Only register the mouse event if no virtual gamepad button is down - if ((!editVjoyMode && rv == 0xFFFFFFFF) || JNIdc.guiIsOpen()) + if ((!editVjoyMode && rv == 0xFFFFFFFF && left_trigger == 0 && right_trigger == 0 && joyx == 0 && joyy == 0) + || JNIdc.guiIsOpen()) InputDeviceManager.getInstance().mouseEvent(mouse_pos[0], mouse_pos[1], mouse_btns); return(true); } 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 1c1da7b19..3b7169c75 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 @@ -269,6 +269,18 @@ public: kcode = 0xffffffff; joyx = joyy = rt = lt = 0; } + if (rt > 0) + { + if ((kcode & DC_BTN_A) == 0) + // RT + A -> D (coin) + kcode &= ~DC_BTN_D; + if ((kcode & DC_BTN_B) == 0) + // RT + B -> C (service) + kcode &= ~DC_BTN_C; + if ((kcode & DC_BTN_X) == 0) + // RT + X -> Z (test) + kcode &= ~DC_BTN_Z; + } u32 changes = kcode ^ previous_kcode; for (int i = 0; i < 32; i++) if (changes & (1 << i)) diff --git a/shell/apple/emulator-ios/emulator/FlycastViewController.mm b/shell/apple/emulator-ios/emulator/FlycastViewController.mm index 4dec6898a..efffc0b64 100644 --- a/shell/apple/emulator-ios/emulator/FlycastViewController.mm +++ b/shell/apple/emulator-ios/emulator/FlycastViewController.mm @@ -36,6 +36,7 @@ #include "stdclass.h" #include "cfg/option.h" #include "ios_gamepad.h" +#include "ios_keyboard.h" //@import AltKit; #import "AltKit/AltKit-Swift.h" @@ -45,6 +46,7 @@ static bool iosJitAuthorized; static __unsafe_unretained FlycastViewController *flycastViewController; std::map> IOSGamepad::controllers; +std::map> IOSKeyboard::keyboards; void common_linux_setup(); @@ -54,8 +56,10 @@ void common_linux_setup(); @property (strong, nonatomic) PadViewController *padController; @property (nonatomic) iCadeReaderView* iCadeReader; -@property (nonatomic, strong) id connectObserver; -@property (nonatomic, strong) id disconnectObserver; +@property (nonatomic, strong) id gamePadConnectObserver; +@property (nonatomic, strong) id gamePadDisconnectObserver; +@property (nonatomic, strong) id keyboardConnectObserver; +@property (nonatomic, strong) id keyboardDisconnectObserver; @property (nonatomic, strong) nw_path_monitor_t monitor; @property (nonatomic, strong) dispatch_queue_t monitorQueue; @@ -125,7 +129,23 @@ extern int screen_dpi; [self setPreferredFramesPerSecond:60]; [EAGLContext setCurrentContext:self.context]; - self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + if (@available(iOS 14.0, *)) { + self.keyboardConnectObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:GCKeyboardDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *note) { + GCKeyboard *keyboard = note.object; + IOSKeyboard::addKeyboard(keyboard); + }]; + + self.keyboardDisconnectObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:GCKeyboardDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *note) { + GCKeyboard *keyboard = note.object; + IOSKeyboard::removeKeyboard(keyboard); + }]; + } + + self.gamePadConnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { GCController *controller = note.object; IOSGamepad::addController(controller); #if !TARGET_OS_TV @@ -133,7 +153,7 @@ extern int screen_dpi; [self.padController hideController]; #endif }]; - self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + self.gamePadDisconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { GCController *controller = note.object; IOSGamepad::removeController(controller); #if !TARGET_OS_TV diff --git a/shell/apple/emulator-ios/emulator/ios_keyboard.h b/shell/apple/emulator-ios/emulator/ios_keyboard.h new file mode 100644 index 000000000..652451d16 --- /dev/null +++ b/shell/apple/emulator-ios/emulator/ios_keyboard.h @@ -0,0 +1,204 @@ +// +// ios.h +// flycast +// +// Created by Cameron Bates on 9/6/21. +// +#pragma once +#import +#include "input/keyboard_device.h" + +class API_AVAILABLE(ios(14.0)) IOSKeyboard : public KeyboardDeviceTemplate +{ +public: + IOSKeyboard(int port, GCKeyboard *keyboard) : KeyboardDeviceTemplate(port, "iOS", false), gcKeyboard(keyboard) + { + set_maple_port(port); + loadMapping(); + + kb_map[GCKeyCodeKeyA] = 0x04; + kb_map[GCKeyCodeKeyB] = 0x05; + kb_map[GCKeyCodeKeyC] = 0x06; + kb_map[GCKeyCodeKeyD] = 0x07; + kb_map[GCKeyCodeKeyE] = 0x08; + kb_map[GCKeyCodeKeyF] = 0x09; + kb_map[GCKeyCodeKeyG] = 0x0A; + kb_map[GCKeyCodeKeyH] = 0x0B; + kb_map[GCKeyCodeKeyI] = 0x0C; + kb_map[GCKeyCodeKeyJ] = 0x0D; + kb_map[GCKeyCodeKeyK] = 0x0E; + kb_map[GCKeyCodeKeyL] = 0x0F; + kb_map[GCKeyCodeKeyM] = 0x10; + kb_map[GCKeyCodeKeyN] = 0x11; + kb_map[GCKeyCodeKeyO] = 0x12; + kb_map[GCKeyCodeKeyP] = 0x13; + kb_map[GCKeyCodeKeyQ] = 0x14; + kb_map[GCKeyCodeKeyR] = 0x15; + kb_map[GCKeyCodeKeyS] = 0x16; + kb_map[GCKeyCodeKeyT] = 0x17; + kb_map[GCKeyCodeKeyU] = 0x18; + kb_map[GCKeyCodeKeyV] = 0x19; + kb_map[GCKeyCodeKeyW] = 0x1A; + kb_map[GCKeyCodeKeyX] = 0x1B; + kb_map[GCKeyCodeKeyY] = 0x1C; + kb_map[GCKeyCodeKeyZ] = 0x1D; + + //1E-27 Number keys 1-0 + kb_map[GCKeyCodeOne] = 0x1E; + kb_map[GCKeyCodeTwo] = 0x1F; + kb_map[GCKeyCodeThree] = 0x20; + kb_map[GCKeyCodeFour] = 0x21; + kb_map[GCKeyCodeFive] = 0x22; + kb_map[GCKeyCodeSix] = 0x23; + kb_map[GCKeyCodeSeven] = 0x24; + kb_map[GCKeyCodeEight] = 0x25; + kb_map[GCKeyCodeNine] = 0x26; + kb_map[GCKeyCodeZero] = 0x27; + + kb_map[GCKeyCodeReturnOrEnter] = 0x28; + kb_map[GCKeyCodeEscape] = 0x29; + kb_map[GCKeyCodeDeleteOrBackspace] = 0x2A; + kb_map[GCKeyCodeTab] = 0x2B; + kb_map[GCKeyCodeSpacebar] = 0x2C; + + kb_map[GCKeyCodeHyphen] = 0x2D; // - + kb_map[GCKeyCodeEqualSign] = 0x2E; // = + kb_map[GCKeyCodeOpenBracket] = 0x2F; // [ + kb_map[GCKeyCodeCloseBracket] = 0x30; // ] + + kb_map[GCKeyCodeBackslash] = 0x31; // \ (US) unsure of keycode + + //32-34 "]", ";" and ":" (the 3 keys right of L) + //kb_map[?] = 0x32; // ~ (non-US) *,ยต in FR layout + kb_map[GCKeyCodeSemicolon] = 0x33; // ; + kb_map[GCKeyCodeQuote] = 0x34; // ' + + //35 hankaku/zenkaku / kanji (top left) + kb_map[GCKeyCodeGraveAccentAndTilde] = 0x35; // `~ (US) + + //36-38 ",", "." and "/" (the 3 keys right of M) + kb_map[GCKeyCodeComma] = 0x36; + kb_map[GCKeyCodePeriod] = 0x37; + kb_map[GCKeyCodeSlash] = 0x38; + + // CAPSLOCK + kb_map[GCKeyCodeCapsLock] = 0x39; + + //3A-45 Function keys F1-F12 + kb_map[GCKeyCodeF1] = 0x3A; + kb_map[GCKeyCodeF2] = 0x3B; + kb_map[GCKeyCodeF3] = 0x3C; + kb_map[GCKeyCodeF4] = 0x3D; + kb_map[GCKeyCodeF5] = 0x3E; + kb_map[GCKeyCodeF6] = 0x3F; + kb_map[GCKeyCodeF7] = 0x40; + kb_map[GCKeyCodeF8] = 0x41; + kb_map[GCKeyCodeF9] = 0x42; + kb_map[GCKeyCodeF10] = 0x43; + kb_map[GCKeyCodeF11] = 0x44; + kb_map[GCKeyCodeF12] = 0x45; + + //46-4E Control keys above cursor keys + kb_map[GCKeyCodePrintScreen] = 0x46; // Print Screen + kb_map[GCKeyCodeScrollLock] = 0x47; // Scroll Lock + kb_map[GCKeyCodePause] = 0x48; // Pause + kb_map[GCKeyCodeInsert] = 0x49; // Insert + kb_map[GCKeyCodeHome] = 0x4A; + kb_map[GCKeyCodePageUp] = 0x4B; + kb_map[GCKeyCodeDeleteForward] = 0x4C; + kb_map[GCKeyCodeEnd] = 0x4D; + kb_map[GCKeyCodePageDown] = 0x4E; + + //4F-52 Cursor keys + kb_map[GCKeyCodeRightArrow] = 0x4F; + kb_map[GCKeyCodeLeftArrow] = 0x50; + kb_map[GCKeyCodeDownArrow] = 0x51; + kb_map[GCKeyCodeUpArrow] = 0x52; + + //53 Num Lock (Numeric keypad) + kb_map[GCKeyCodeKeypadNumLock] = 0x53; + //54 "/" (Numeric keypad) + kb_map[GCKeyCodeKeypadSlash] = 0x54; + //55 "*" (Numeric keypad) + kb_map[GCKeyCodeKeypadAsterisk] = 0x55; + //56 "-" (Numeric keypad) + kb_map[GCKeyCodeKeypadHyphen] = 0x56; + //57 "+" (Numeric keypad) + kb_map[GCKeyCodeKeypadPlus] = 0x57; + //58 Enter (Numeric keypad) + kb_map[GCKeyCodeKeypadEnter] = 0x58; + //59-62 Number keys 1-0 (Numeric keypad) + kb_map[GCKeyCodeKeypad1] = 0x59; + kb_map[GCKeyCodeKeypad2] = 0x5A; + kb_map[GCKeyCodeKeypad3] = 0x5B; + kb_map[GCKeyCodeKeypad4] = 0x5C; + kb_map[GCKeyCodeKeypad5] = 0x5D; + kb_map[GCKeyCodeKeypad6] = 0x5E; + kb_map[GCKeyCodeKeypad7] = 0x5F; + kb_map[GCKeyCodeKeypad8] = 0x60; + kb_map[GCKeyCodeKeypad9] = 0x61; + kb_map[GCKeyCodeKeypad0] = 0x62; + //63 "." (Numeric keypad) + kb_map[GCKeyCodeKeypadPeriod] = 0x63; + //64 #| (non-US) + //kb_map[94] = 0x64; + //65 S3 key + //66-A4 Not used + //A5-DF Reserved + kb_map[GCKeyCodeLeftControl] = 0xE0; + kb_map[GCKeyCodeLeftShift] = 0xE1; + kb_map[GCKeyCodeLeftAlt] = 0xE2; // Left Alt + //E3 Left S1 + kb_map[GCKeyCodeRightControl] = 0xE4; + kb_map[GCKeyCodeRightShift] = 0xE5; + kb_map[GCKeyCodeRightAlt] = 0xE6; // Right Alt + //E7 Right S3 + //E8-FF Reserved + +// kb_map[kVK_ISO_Section] = 0x32; // #, Tilde + + // Japanese keyboards +// kb_map[kVK_JIS_Underscore] = 0x87; // I18n keyboard 1 +// kb_map[kVK_JIS_Yen] = 0x89; // I18n keyboard 3 + + [gcKeyboard.keyboardInput setKeyChangedHandler:^(GCKeyboardInput *keyboard, GCDeviceButtonInput *key, GCKeyCode keyCode, BOOL pressed) { + keyboard_input(keyCode, pressed); + }]; + + } + + void set_maple_port(int port) override + { + KeyboardDevice::set_maple_port(port); + } + + static void addKeyboard(GCKeyboard *keyboard) + { + if (keyboards.count(keyboard) > 0) + return; + + int port = std::min((int)keyboards.size(), 3); + keyboards[keyboard] = std::make_shared(port, keyboard); + KeyboardDevice::Register(keyboards[keyboard]); + } + + static void removeKeyboard(GCKeyboard *keyboard) + { + auto it = keyboards.find(keyboard); + if (it == keyboards.end()) + return; + KeyboardDevice::Unregister(it->second); + keyboards.erase(it); + } + +protected: + u8 convert_keycode(UInt16 keycode) override + { + return kb_map[keycode]; + } + +private: + GCKeyboard * __weak gcKeyboard = nullptr; + static std::map> keyboards; + std::map kb_map; +}; diff --git a/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift b/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift index 957482c19..fd6e2ff3c 100644 --- a/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift +++ b/shell/apple/emulator-osx/emulator-osx/EmuGLView.swift @@ -10,7 +10,8 @@ import Cocoa class EmuGLView: NSOpenGLView, NSWindowDelegate { - var backingRect:NSRect? + var backingRect: NSRect? + var swapOnVSync = emu_vsync_enabled() override var acceptsFirstResponder: Bool { return true; @@ -20,19 +21,22 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate { super.draw(dirtyRect) backingRect = convertToBacking(dirtyRect) - if emu_fast_forward() == false { + if swapOnVSync { draw() } } func draw() { - var sync: GLint = emu_fast_forward() ? 0 : 1 - CGLSetParameter(openGLContext!.cglContextObj!, kCGLCPSwapInterval, &sync) + if swapOnVSync == (emu_fast_forward() || !emu_vsync_enabled()) { + swapOnVSync = (!emu_fast_forward() && emu_vsync_enabled()) + var sync: GLint = swapOnVSync ? 1 : 0 + CGLSetParameter(openGLContext!.cglContextObj!, kCGLCPSwapInterval, &sync) + } if let backingRect = backingRect { openGLContext!.makeCurrentContext() - if (emu_single_frame(Int32(backingRect.width), Int32(backingRect.height)) != 0) { - openGLContext!.flushBuffer() + if emu_single_frame(Int32(backingRect.width), Int32(backingRect.height)) { + openGLContext!.flushBuffer() //Swap for macOS } } } @@ -80,11 +84,11 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate { if (!emu_renderer_enabled()) { NSApplication.shared.terminate(self) } - else if (emu_frame_pending()) { - if emu_fast_forward() { - self.draw() - } else { + else if emu_frame_pending() { + if swapOnVSync { self.needsDisplay = true + } else { + self.draw() } } } 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 980039a65..1e5c98233 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 @@ -19,7 +19,8 @@ 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); +bool emu_vsync_enabled(); +bool emu_single_frame(int w, int h); void emu_gles_init(int width, int height); int emu_reicast_init(); void emu_key_input(UInt16 keyCode, bool pressed, UInt32 modifierFlags); diff --git a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm index 0360e378e..06cc775d1 100644 --- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm +++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm @@ -131,14 +131,27 @@ bool emu_fast_forward() return settings.input.fastForwardMode; } -int emu_single_frame(int w, int h) +bool emu_vsync_enabled() { - if (!emu_frame_pending()) - return 0; + return config::VSync; +} +bool emu_single_frame(int w, int h) +{ screen_width = w; screen_height = h; - return (int)mainui_rend_frame(); + + //For DelayFrameSwapping: use while loop to call multple mainui_rend_frame() until rend_swap_frame(u32 fb_r_sof1) + int counter = 0; + while (mainui_enabled && counter < 5) + { + counter++; + if (mainui_rend_frame()) + { + return true; + } + } + return false; } void emu_gles_init(int width, int height) diff --git a/shell/apple/sdl2.rb b/shell/apple/sdl2.rb index c034be340..b0ca3f267 100644 --- a/shell/apple/sdl2.rb +++ b/shell/apple/sdl2.rb @@ -1,8 +1,8 @@ class Sdl2 < Formula desc "Low-level access to audio, keyboard, mouse, joystick, and graphics" homepage "https://www.libsdl.org/" - url "https://libsdl.org/release/SDL2-2.0.14.tar.gz" - sha256 "d8215b571a581be1332d2106f8036fcb03d12a70bae01e20f424976d275432bc" + url "https://libsdl.org/release/SDL2-2.0.16.tar.gz" + sha256 "65be9ff6004034b5b2ce9927b5a4db1814930f169c4b2dae0a1e4697075f287b" license "Zlib" revision 1 env :std @@ -13,10 +13,10 @@ class Sdl2 < Formula end bottle do - sha256 cellar: :any, arm64_big_sur: "2ae70b6025c4e241400643f2686c8e288d50e3f04311e63d8a1f8180ed4afb07" - sha256 cellar: :any, big_sur: "ccde7145d4334d9274f9588e6b841bf3749729682e1d25f590bdcf7994dfdd89" - sha256 cellar: :any, catalina: "d6ae3300160c5bb495b78a5c5c0fc995f9e797e9cdd4b04ef77d59d45d2d694d" - sha256 cellar: :any, mojave: "4f3988fb3af0f370bc1648d6eb1d6573fd37381df0f3b9ee0874a49d6a7dec2e" + sha256 cellar: :any, arm64_big_sur: "6adac3ca2899ab923427b9b9322c8a4a412485ac7fe6448e276b4aae598f7a49" + sha256 cellar: :any, big_sur: "71fe247bc197133b02186fac4e8f296d7f457a9507e0c77357b1069e5ee2ca61" + sha256 cellar: :any, catalina: "4634185a35d9fc37c8fc07f884e45e7e2fbaa3fdec615171e647a9e02c395bd4" + sha256 cellar: :any, mojave: "9966890d7d39147e75e92d6a7390ef5fb2f043b08f913e751638bdeef8c1c220" end head do diff --git a/shell/libretro/libretro.cpp b/shell/libretro/libretro.cpp index b658797fb..7f0d27171 100644 --- a/shell/libretro/libretro.cpp +++ b/shell/libretro/libretro.cpp @@ -1394,7 +1394,7 @@ static void retro_vk_context_destroy() static bool set_vulkan_hw_render() { - retro_hw_render_callback hw_render; + retro_hw_render_callback hw_render{}; hw_render.context_type = RETRO_HW_CONTEXT_VULKAN; hw_render.version_major = VK_API_VERSION_1_0; hw_render.version_minor = 0;