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/core/cfg/option.cpp b/core/cfg/option.cpp index 23472a660..8b448f068 100644 --- a/core/cfg/option.cpp +++ b/core/cfg/option.cpp @@ -56,6 +56,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 08db3a23d..4ce5ce847 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 @@ -369,6 +370,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/aica/dsp_arm64.cpp b/core/hw/aica/dsp_arm64.cpp index 68facafa0..9e2150597 100644 --- a/core/hw/aica/dsp_arm64.cpp +++ b/core/hw/aica/dsp_arm64.cpp @@ -67,6 +67,7 @@ public: void Compile(DSPState *DSP) { + JITWriteProtect(false); this->DSP = DSP; DEBUG_LOG(AICA_ARM, "DSPAssembler::DSPCompile recompiling for arm64 at %p", GetBuffer()->GetStartAddress()); @@ -340,6 +341,7 @@ public: vmem_platform_flush_cache( GetBuffer()->GetStartAddress() + rx_offset, GetBuffer()->GetEndAddress() + rx_offset, GetBuffer()->GetStartAddress(), GetBuffer()->GetEndAddress()); + JITWriteProtect(true); } private: diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index 22e077cbd..88b1be8a2 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -442,10 +442,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) + std::lock_guard lock(swap_mutex); + 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/rend/gui.cpp b/core/rend/gui.cpp index 4dbafa71c..30513367e 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -1454,9 +1454,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__ 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"); OptionCheckbox("Show VMU In-game", config::FloatVMUs, "Show the VMU LCD screens while in-game"); OptionCheckbox("Rotate Screen 90°", config::Rotate90, "Rotate the screen 90° counterclockwise"); @@ -1582,6 +1580,10 @@ static void gui_display_settings() OptionCheckbox("Disable Sound", config::DisableSound, "Disable the emulator sound output"); 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-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