* [cmake] Fix MoltenVK fetch order/library conflicts
Rather than dealing with `find_library` shenanigans, just set the
library path directly (when using bundled MoltenVK). System MoltenVK
solely uses `find_library`.
Avoids cache nonsense that can cause system/bundled versions to get
mixed up, and overall makes the system/bundled mvk handling a lot more
consistent
```
cmake -S . -B build -DUSE_SYSTEM_MOLTENVK=ON
-- Using MoltenVK at /opt/homebrew/lib/libMoltenVK.dylib.
cmake -S . -B build -DUSE_SYSTEM_MOLTENVK=OFF
-- Using MoltenVK at /Users/crueter/code/azahar/build/externals/MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib.
cmake -S . -B build -DUSE_SYSTEM_MOLTENVK=ON
-- Using MoltenVK at /opt/homebrew/lib/libMoltenVK.dylib.
```
Signed-off-by: crueter <crueter@eden-emu.dev>
* remove old comment
Signed-off-by: crueter <crueter@eden-emu.dev>
* Cleanup
---------
Signed-off-by: crueter <crueter@eden-emu.dev>
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
Disabled texture units on OpenGL always use a null 2D texture, but there are
cases where the null texture should be a null cubemap rather than a 2D
texture to match the active texture binding state.
Fixes some errors that occur in `OpenGLState::Apply()` found
in Brain Age: Concentration Training.
This is mostly just for specificity. In practice this will never do anything in CI because there will never be any cache to use, but if there was, we wouldn't want to use it
I think this was from back when the Dockerfile was first being written, before the 'builder' and 'final' stages were introduced which make this former optimization attempt completely redundant
* ci: Add sbom and attestation
* tools: Add verify-release.sh
* verify-release.sh: Set executable permission
* verify-release.sh: Put downloads into a gitignored directory
* tools: Make verify-release also download sbom
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
citra-build / linux-x86_64 (appimage) (push) Waiting to run
citra-build / linux-x86_64 (appimage-wayland) (push) Waiting to run
citra-build / linux-x86_64 (gcc-nopch) (push) Waiting to run
citra-build / linux-arm64 (clang) (push) Waiting to run
citra-build / linux-arm64 (gcc-nopch) (push) Waiting to run
citra-build / macos (push) Waiting to run
citra-build / windows (msvc) (push) Waiting to run
citra-build / windows (msys2) (push) Waiting to run
citra-build / android (googleplay) (push) Waiting to run
citra-build / android (vanilla) (push) Waiting to run
citra-build / docker (push) Waiting to run
citra-format / clang-format (push) Waiting to run
citra-libretro / android (push) Waiting to run
citra-libretro / linux (push) Waiting to run
citra-libretro / windows (push) Waiting to run
citra-libretro / macos (arm64) (push) Waiting to run
citra-libretro / macos (x86_64) (push) Waiting to run
citra-libretro / ios (push) Waiting to run
citra-libretro / tvos (push) Waiting to run
citra-transifex / transifex (push) Waiting to run
Rather than emitting these subroutine functions for _every_ shader, only emit
the subroutines when the `LG2` and `EX2` instructions are actually used.
This saves a good chunk of memory across all shaders.
Inspired by Tanuki3DS.
citra-build / linux-x86_64 (appimage) (push) Has been cancelled
citra-build / linux-x86_64 (appimage-wayland) (push) Has been cancelled
citra-build / linux-x86_64 (gcc-nopch) (push) Has been cancelled
citra-build / linux-arm64 (clang) (push) Has been cancelled
citra-build / linux-arm64 (gcc-nopch) (push) Has been cancelled
citra-build / macos (push) Has been cancelled
citra-build / windows (msvc) (push) Has been cancelled
citra-build / windows (msys2) (push) Has been cancelled
citra-build / android (googleplay) (push) Has been cancelled
citra-build / android (vanilla) (push) Has been cancelled
citra-build / docker (push) Has been cancelled
citra-format / clang-format (push) Has been cancelled
citra-libretro / android (push) Has been cancelled
citra-libretro / linux (push) Has been cancelled
citra-libretro / windows (push) Has been cancelled
citra-libretro / macos (arm64) (push) Has been cancelled
citra-libretro / macos (x86_64) (push) Has been cancelled
citra-libretro / ios (push) Has been cancelled
citra-libretro / tvos (push) Has been cancelled
citra-transifex / transifex (push) Has been cancelled
* qt: Temporarily fix fullscreen on msys2 builds
* Removed excessive endif comments
We really only need these when nesting ifdefs
* blockRoundedCorners: Invert if condition for readability
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
citra-build / linux-x86_64 (appimage) (push) Has been cancelled
citra-build / linux-x86_64 (appimage-wayland) (push) Has been cancelled
citra-build / linux-x86_64 (gcc-nopch) (push) Has been cancelled
citra-build / linux-arm64 (clang) (push) Has been cancelled
citra-build / linux-arm64 (gcc-nopch) (push) Has been cancelled
citra-build / macos (push) Has been cancelled
citra-build / windows (msvc) (push) Has been cancelled
citra-build / windows (msys2) (push) Has been cancelled
citra-build / android (googleplay) (push) Has been cancelled
citra-build / android (vanilla) (push) Has been cancelled
citra-build / docker (push) Has been cancelled
citra-format / clang-format (push) Has been cancelled
citra-libretro / android (push) Has been cancelled
citra-libretro / linux (push) Has been cancelled
citra-libretro / windows (push) Has been cancelled
citra-libretro / macos (arm64) (push) Has been cancelled
citra-libretro / macos (x86_64) (push) Has been cancelled
citra-libretro / ios (push) Has been cancelled
citra-libretro / tvos (push) Has been cancelled
citra-transifex / transifex (push) Has been cancelled
solves a build issue a ***lot*** of [L4T Megascript](https://github.com/cobalt2727/L4T-Megascript) users were reporting to me on Linux. C++ is definitely not my strong suit, but per https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/pow-powf-powl?view=msvc-170#remarks `pow` has identical behavior in C++ projects. no clue why `powf` worked fine on your environment when developing this but not other people's.
```cmake
[ 98%] Building CXX object src/citra_qt/CMakeFiles/citra_qt.dir/qt_image_interface.cpp.o
/home/runner/azahar/src/citra_qt/notification_led.cpp:56:15: error: no member named 'powf' in namespace 'std'; did you mean simply 'powf'?
56 | float t = std::powf(pwm, 1.f / gamma);
| ^~~~~~~~~
| powf
/usr/include/aarch64-linux-gnu/bits/mathcalls.h:140:1: note: 'powf' declared here
140 | __MATHCALL_VEC (pow,, (_Mdouble_ __x, _Mdouble_ __y));
| ^
/usr/include/math.h:280:3: note: expanded from macro '__MATHCALL_VEC'
280 | __MATHCALL (function, suffix, args)
| ^
/usr/include/math.h:287:3: note: expanded from macro '__MATHCALL'
287 | __MATHDECL (_Mdouble_,function,suffix, args)
| ^
/usr/include/math.h:289:3: note: expanded from macro '__MATHDECL'
289 | __MATHDECL_1(type, function,suffix, args); \
| ^
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
/usr/include/math.h:297:15: note: expanded from macro '__MATHDECL_1_IMPL'
297 | extern type __MATH_PRECNAME(function,suffix) args __THROW
| ^
/usr/include/math.h:326:34: note: expanded from macro '__MATH_PRECNAME'
326 | # define __MATH_PRECNAME(name,r) name##f##r
| ^
<scratch space>:97:1: note: expanded from here
97 | powf
| ^
1 error generated.
make[2]: *** [src/citra_qt/CMakeFiles/citra_qt.dir/build.make:1573: src/citra_qt/CMakeFiles/citra_qt.dir/notification_led.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [CMakeFiles/Makefile2:3481: src/citra_qt/CMakeFiles/citra_qt.dir/all] Error 2
make: *** [Makefile:166: all] Error 2
```
citra-build / linux-x86_64 (appimage) (push) Waiting to run
citra-build / linux-x86_64 (appimage-wayland) (push) Waiting to run
citra-build / linux-x86_64 (gcc-nopch) (push) Waiting to run
citra-build / linux-arm64 (clang) (push) Waiting to run
citra-build / linux-arm64 (gcc-nopch) (push) Waiting to run
citra-build / macos (push) Waiting to run
citra-build / windows (msvc) (push) Waiting to run
citra-build / windows (msys2) (push) Waiting to run
citra-build / android (googleplay) (push) Waiting to run
citra-build / android (vanilla) (push) Waiting to run
citra-build / docker (push) Waiting to run
citra-format / clang-format (push) Waiting to run
citra-libretro / android (push) Waiting to run
citra-libretro / linux (push) Waiting to run
citra-libretro / windows (push) Waiting to run
citra-libretro / macos (arm64) (push) Waiting to run
citra-libretro / macos (x86_64) (push) Waiting to run
citra-libretro / ios (push) Waiting to run
citra-libretro / tvos (push) Waiting to run
citra-transifex / transifex (push) Waiting to run
Ensure the scheduler worker thread has finished processing all dispatched command chunks before the rasterizer cache's garbage collector destroys sentenced surfaces.
The `SETEMIT`/`SETE` instruction only actually encodes 4 bits of possible state,
but this is currently expanded into three separate bytes of
data(four with padding) and requires three separate byte-writes for the x64 and
a64 JITs to write into. These 4 bits from the instruction can instead be
compacted into a singular 1-byte write from the JIT by encoding these 4 bits of
state into a singular byte at JIT-time, and unpacking this data is instead done
by `GeometryEmitter::Emit`. This also allows the serializer to use a singular
byte for all 3 fields now as well.
Allows individual unit-tests to be discovered, tested, and debugged by IDEs without having to run _all_ of the unit-tests just to debug one specific test.
Touch pointer rendering is now always enabled, but unless a controller is being used to move the touchscreen cursor, it will be hidden due to the timeout which is also enabled by default.
* android: Fix launching applications through intent data in vanilla build
* GameHelper.kt: Use Uri.scheme where applicable
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* fix compilation on older QT6
* fix indent
my C++ is very rusty
* fix indents again
* Fixed formatting
* fix capitalization error
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* fix compilation on older QT6
* fix indent
my C++ is very rusty
* fix indents again
* Fixed formatting
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This introduces a very hacky way of telling TranslateFilePath that a path is already native and doesn't need translating. I don't like this very much, but addressing this in any other way is very much outside of the scope of this PR.
* Add DLP:SRVR + add friend code seed hack for LM1 + add multiple filters in IPC debugger + fix cia_container smdh offset not being applied, possible IF statement underflowing + default initialize boss variables + fix IPC header asserts in AM functions + add extra debug info to IPC param assert
* Make server & client more resistant to high ping conditions
* Remove DLP from list of online recommended modules
* Fix license headers + fix clang formatting + fix server create network assert
* Fix recorder.cpp license header
Fixes crash on startup with Vulkan renderer. The extension and its
features must be enabled during device creation for samplers using
custom border colors to work.
Fixes#1824
Adds the large_screen_proportion setting to libretro core options,
allowing users to adjust the ratio between the large and small screens
in the "Large Screen, Small Screen" layout.
This is useful on devices like the Steam Deck where the default 4x ratio
makes the small screen too tiny to be practical.
Values range from 1.00x to 6.00x in 0.25 increments.
Closes#1832
- Allow GIT-COMMIT and GIT-TAG files to override real git info (useful for testing version-related functionality such as update checks)
- Always re-configure scm_rev.cpp when configuring with CMake (fixes an issue where the version number would just not update in incremental builds)
* Convert all setting keys in settings.h into hana strings
* Derive libretro setting keys from common/settings.h hana strings
* settings.h: Reduce code repetition in key definitions via macro
* Implemented mechanism to pass our C++ setting keys to Android/Kotlin
None of the Android keys have been moved over as of this commit, this is just prep work
* jni_settings_keys.cpp.in: Removed redundant code
* Migrate (almost) all Android setting string keys over to SettingKeys
Also some slight cleanup
* Updated license headers
* Fixed top custom width erroneously being used in place of top custom height
* Migrate (probably) all setting string keys to Settings::QKeys
* Migrated several previously missed string keys to generated keys
* SettingKeys.kt: Visually seperate shared and Android-exclusive keys, similar to GenerateSettingKeys.cmake
* android: sdl2_config --> android_config
Not sure why these values are named this way. Hold-over from SDL2 frontend?
* android: Generate and validate default config.ini dynamically
* Settings: Assume C-style string keys by default
Relative to the previous commit, the following names have changed:
- Settings::Keys --> Settings::HKeys
- Settings::CKeys --> Settings::Keys
* default_ini.h: Fixed formatting warning
* Comment cleanup
* android: Fixed compilation failure due to incorrect namespace
* config.cpp: Use ASSERT_MSG instead of LOG_ERROR and ASSERT(false)
it seems like the initial call to `GameList::PopulateAsync` in the window constructor is too early in the app life-cycle and doesn't run asynchronously, or Qt is using macOS API in an esoteric way, or maybe it's something else entirely.
Moving the list population to happen before the window is shown instead appears to fix the issue.
* libretro core
* Bringing citra libretro implementation over
* libretro: hook up vulkan renderer
* libretro: github actions
* libretro: gyro
* libretro: core options v2
* libretro: on ios turn off shader jit if unavailable
* moltenvk 1.3.0 introduces 8-bit indexes but allocates 16-bit for metal; this ends up allocating stream buffer * 2 = 132MiB. Instead, just use 16-bit indexes. (This will be necessary for standalone when bumping moltenvk version.)
* libretro core: address review feedback
* libretro: microphone support
* cmake: Add ENABLE_ROOM_STANDALONE to list of incompatible libretro flags
* libretro: proper initial geometry
* libretro: fix software renderer
* libretro: address review feedback
* .github/libretro.yml: Pin macOS runners at macOS 26
* ci: Remove explicit selection of Xcode 16.0
* .github/libretro.yml: remove unnecessary windows builder apt commands
* .github/libretro.yml: bump min macos version to 11.0
* ci: Re-enable CI jobs for all libretro cores
This is under the condition that we don't introduce build cache for these builds
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
Co-authored-by: PabloMK7 <hackyglitch2@gmail.com>
Otherwise, the configuration on darwin fails for me with the following
error:
```
CMake Error at src/citra_meta/CMakeLists.txt:64 (target_link_libraries):
Target "citra_meta" links to:
Qt6::GuiPrivate
but the target was not found.
```
Signed-off-by: Marcin Serwin <marcin@serwin.dev>
* DirectoryInitialization.kt: Switch to getFilesDir for internalUserPath
Was previously getExternalFilesDir
filesDir is used here, which is just recommended shorthand for getFilesDir
* DirectoryInitialization.kt: Updated license header
This doesn't really address the root cause of the problem because I have absolutely no idea what it is, but this does get around the issue by just forcing the dialog into a pre-determined size rather than letting it automatically set its own size
* Add setup step to grant `MANAGE_EXTERNAL_STORAGE`
* WIP re-implementation of Android `Rename` using native filesystem manipulation
* Applied clang-format and updated license headers
* Support user directories on removable storage devices
* If `MANAGE_EXTERNAL_STORAGE` is lost, re-request it
* Fix missing permission dialog appearing during initial setup
* Added empty code branches to prep for old Android support
* Fixed permission setup completion not accounting for external storage permission
* Implement code for Android <11
* Fixed emulation error if a renamed file is then opened for R/W
* Detect if the current user directory cannot be located, and prompt re-selection
* If an invalid user directory is selected, reject and re-prompt
* [android]: Force app to use the displays max set refresh rate
Since Android 15, google automatically forces "games" to be 60 hrz. This ensures the display's max refresh rate is actually used. Tested on a Google Pixel 7 Pro with Android 16
Emulation Activity was excluded for battery usage concerns
* force60Hrz option
* Code cleanup
* Expanded refresh rate explaination comment
* Moved `enforceRefreshRate` calls to earlier in `onCreate`
This probably doesn't actually do anything, it's a bit of a nitpick
* Moved `enforceRefreshRate` SDK version check to within the function
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Use zstd_seekable header from externals
Specifying the full path relies on the system installed header.
Signed-off-by: Marcin Serwin <marcin@serwin.dev>
* Don't install zstd_seekable
Signed-off-by: Marcin Serwin <marcin@serwin.dev>
---------
Signed-off-by: Marcin Serwin <marcin@serwin.dev>
This can definitely be further improved, as there are Citra components which are also built unnecessarily, but that would require invasive CMake changes which are out of scope for this PR.
* Prevent SecondaryDisplay from stealing focus
The SecondaryDisplay Activity was stealing focus from the main
Activity when it was launched.
Set the `FLAG_NOT_FOCUSABLE` and `FLAG_NOT_TOUCH_MODAL` window flags
to prevent the SecondaryDisplay from gaining focus.
* Implement touch controls for secondary display
This commit introduces touch input handling for the secondary display.
The following changes were made:
- Added `onSecondaryTouchEvent` and `onSecondaryTouchMoved` to `NativeLibrary.kt` and `native.cpp` to process touch events on the secondary display.
- Implemented `onTouchListener` in `SecondaryDisplay.kt` to capture touch events and forward them to the native layer.
- Handles `ACTION_DOWN`, `ACTION_POINTER_DOWN`, `ACTION_MOVE`, `ACTION_UP`, `ACTION_POINTER_UP`, and `ACTION_CANCEL` motion events.
- Tracks the active pointer to ensure correct touch event handling.
* Refactor display logic for multi-display support
This commit introduces a `DisplayHelper` class to centralize display-related logic, particularly for handling scenarios where the application might be launched on an external display.
Key changes:
- Added `DisplayHelper.kt` to manage internal and external display identification based on launch conditions.
- `MainActivity` and `EmulationActivity` now use `DisplayHelper.checkLaunchDisplay()` to determine the initial display.
- `SecondaryDisplay` now uses `DisplayHelper.getExternalDisplay()` to correctly identify the target display for the secondary presentation.
- `InputOverlay` now queries `DisplayHelper.isBottomOnPrimary()` to determine if touch input should be processed for the primary display based on the current screen layout.
- `SecondaryDisplay` now queries `DisplayHelper.isBottomOnSecondary()` to conditionally pass touch events to the native layer based on which screen (primary or secondary) is currently displaying the 3DS bottom screen.
These changes ensure that the application behaves correctly when launched on either the internal or an external display, and that touch input is routed appropriately based on the user's chosen screen layout for the dual screens.
* Removed primary-screen checks so the input overlay always forwards touch events, ensuring all touches reach the native handler even when multiple displays are active
* Remove DisplayHelper class and adjust external display logic
* Formatting adjustments
---------
Co-authored-by: DavidRGriswold <novachild@gmail.com>
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Added NWM spectator mode (DLP now partially working), fixed debug assert, added applet utility cmd fallback
* Reverted AppletUtility command change
* Fixed inconsistent mac address
* Enabled DLP Child authorization
* Added the DLP module to recommended online modules
* Clean up
* Changed the returned number of words on GetProgramInfoFromCia to 7 insteead of 8, futher reverted AppletUtility function to match its original form
* EmulationActivity and EmulationFragment clear only their own hooks
* EmulationLifecycleUtil: Rename `remove()` to `removeHook()`
* EmulationLifecycleUtil: Removed unused function `clear()`
* Corrected somewhat incorrect usage of the word "hook"
* Define `onShutdown` and `onPause` hook functions in constructors
* Formatting nitpicks
* Updated license header
* Re-added log messages for attempting to add duplicate hooks
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Enable the SecondScreenPresentation class
* Update everything to enable second screen on android under GL and Vulkan. Still some issues!
* Some attempts to enable surface changes
* OpenGL is working on surface change, vulkan still no
* release surfaces (also fixed vulkan?)
* added and enabled layout setting
* resolve merge conflict
* rearrange switch cases to satisfy linux compiler
* openGL is working!
* several vk changes to try to fix crashes
* maybe vulkan is working?
* removing unnecessary code attempts
* Simplified secondscreen for better performance
* vk_platform.cpp: Fixed build failure caused by bad rebase
* vk_present_window.h: Removed stray newline
* Applied clang-format
* bug fix for odin 2
* Applied clang-format
* Updated license headers
* Moved SecondScreen class to org.citra.citra_emu.display
* Various formatting and readability improvements
* Added brackets where previously absent for readability
* Additional readability improvement
* RendererVulkan::NotifySurfaceChanged: Simplified condition checking
* change all references to "secondary screen" to "secondary display" to limit confusion with top screen / bottom screen
* rename main_window to main_present_window and second_window to secondary_present_window
* Reverted accidentally downgraded compatibility list submodule
* Removed unnecessary log message
* Applied clang-format
* Added a description to the Secondary Display Screen Layout setting
* Added `_ptr` suffix to `secondary_present_window`
This distinguishes it as a pointer, as `main_present_window` isn't a pointer, so there could be confusion on whether to use `.` or `->`
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Added simple button sliding mode
* Added "keep first" button sliding mode
* directly pressed buttons stay active even when sliding off
* further buttons can be triggered via the simple sliding method
* Added button sliding configuration to overlay settings menu
* Updated licences
* Added button sliding activation to dpads and joysticks
* separated handling of buttons, dpads and joysticks needed since they can be activated by moving now
* Adjusted strings
* Changed ButtonSlidingMode values to mirror prior string name changes
* Reverted incorrectly applied language translation
* Nitpicky formatting adjustments
* Shortened string IDs
* hasActiveJoy --> hasActiveJoystick
* showButtonSlidingModeMenu --> showButtonSlidingMenu
* Updated outdated comment relating to `isMotionFirstButton`
Co-authored-by: toksn <toksn@yahoo.de>
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* renderer_vulkan: remove out of context SDL_Quit call (fixes#1220)
SDL_Quit must not be called unless the application must exit or SDL is no longer needed
* comment: simplify, forgot init had ref-count
* android: Implement play time tacking
Co-Authored-By: Reg Tiangha <rtiangha@users.noreply.github.com>
* Moved playtime manager from `citra_qt` to `common`
* Reimplemented Android play time to use existing logic from desktop
* Updated license headers
* When getting current game ID fails, silently error rather than crashing
* playTimeManagerStart: Check that `play_time_manager` is initialized before using it
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
Co-authored-by: Reg Tiangha <rtiangha@users.noreply.github.com>
* renderer_vulkan: Disable FIFO when refresh rate is lower than ~60hz
Also disables FIFO when Apple low power mode is enabled, as it can limit the application framerate to 30fps
* renderer_vulkan.cpp: Put `IsLowRefreshRate` into anon namespace + make static
* Fix aac_decoder memory leak
Only call NeAACDecInit on the first AAC frame and create new NeAACDecoder on DecoderCommand::Init request
* update license headers
* fix oversight
* reorganized code
-put open new FAAD2 AAC decoder code into a separate function
-removed LOG_INFO for open/close FAAD2 AAC decoder
-added LOG_ERROR when no decoder is created to handle decode request, either decoder creation failed or DecoderCommand::Init command not received
* Update aac_decoder.cpp
fix clang coding style check
* fix load savestate
Loading a savestate creates a situation where decode requests aren't preceded by an init request, so we open a new decoder by default in the constructor. A new AACDecoder instance is always constructed on load savestate.
* cmake: Bump min version to 3.25 and update android to 3.30.3
* app/build.gradle.kts: Set minimum CMake version rather than exact version
---------
Co-authored-by: OpenSauce <opensauce04@gmail.com>
* Replace deprecated and removed in boost 1.88 io_service for io_context
* More thoroughly replaced references to io_service with io_context
* Updated license header
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Fix and restore macOS native menu
* Handle menu more elegantly by making norole default
Handle menu roles more universally by making norole default and manually define previously automatically assigned roles
Uses SIMD operations on the RasterizerAccelerated::AnalyzeVertexArray
function, which is hot code. Slightly reduces GPU processing time
on all games.
This idea was suggested by an anonymous contributor.
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
Enables the use of SSE4.2 instructions on x86_64 CPUs, allowing
compilers to automatically vectorize some loops on citra_common.
A CMake toggle ENABLE_SSE42 (ON by default) has been added
to enable this behaviour.
This change breaks compatibility with CPUs that do not have
SSE4.2 instructions. All modern CPUs (from 2011 onwards) should
always have these instructions. Manual compilation will be
needed for older CPUs.
A message has been added to report if the CPU is incompatible
when starting the emulator.
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* android: Enhance shortcut customization with a custom dialog
Adds ability to customize game shortcuts with:
- Custom name input
- Editable icon via image picker
- Ability to stretch to fit or zoom to fit the shortcut icon
* Code cleanup
* SearchFragment.kt: Updated license header
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
* Add upright boolean for portrait mode
* Add the `upright_screen` boolean to the UI as a switch & in-game
* ScreenAdjustmentUtil.kt: Updated license header
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
* Refactor SetupFragment to support multiple buttons in one page
* Add new `PageButton` data class
* Programmatic button creation && button disabling in setUpAdapter
* Refactor SetupWarningDialogFragment to support multiple titles, descriptions, and help links
* Rework CitraDirectoryHelper to support button step state
* Update warning message for user folder selection step
* Updated license headers
* Code cleanup
* "skip setting the user folder" --> "skip setting up the user folder"
* Fixed typos in string names
* Break `select_emulator_data_folder_description` string over two lines
* `select_emulator_data_folder` --> `select_emulator_data_folders`
* Code cleanup #2
* Removed seemingly accidentally duplicated block of code
* Removed stray newlines
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
It seems that certain environments still don't have access to `std::format` yet, and I missed this because it built fine on my machine and CI passed because the code using `std::format` wasn't included in non-tagged builds.
When the frame limit was set to 0 (unthrottled), the Vulkan present mode would be unintentionally set to FIFO, which caps out at the monitor's refresh rate
* android: Improve performance stats overlay settings and functionality
* Add battery temp functions
* Readd frametime
* Corrected `perf_overlay_position` being placed in the wrong `default_ini.h` file
* Fixed the word "overlay" being repeatedly misspelled in function names
* `updateshowStatsOverlay` --> `updateShowStatsOverlay`
* Increased frequency of performance overlay updates
Changed from every 3 seconds to every 1 second
* Adjusted overlay margins to avoid text being lost behind rounded corner cutouts
* Fix performance overlay updates being stacked when changing orientation
* Changed out host RAM usage statistic for available host RAM
* Removed seemingly unused code
* "FT" --> "Frametime" in overlay
* Use non-breaking spaces to control how the overlay text breaks
Also used a vertical box drawing character instead of a pipe for the divider because it looks slightly nicer
* Renamed/adjusted remnants of the "Show System Memory Usage" setting
* Replaced Performance Stats Overlay icon with a stock clip art image from Android Studio
* Made performance overlay setting value names and strings less generic
* Rebranded Performance Stats Overlay as simply "Performance Overlay"
* Rewrote performance overlay settings description
* Improved naming consistency
* Rebranded "Show Overlay" toggle to "Show Controller Overlay"
This is to avoid confusion with the new performance overlay
* nitpick: Fixed order of imports in EmulationFragment.kt
* More string name consistency improvements
* Fixed compile failure due to a binding name not being updated
* Changed Performance Overlay setting headers
* EmulationFragment.kt: Formatting corrections
* Removed seemingly misplaced call to `updateShowPerformanceOverlay`
* `OVERLAY_POSITION` --> `PERFORMANCE_OVERLAY_POSITION`
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
Co-authored-by: Zephyron <zephyron@citron-emu.orgq>
* change dialog without write permissions
* Added update path from lime to azahar on android
* Shows the correct dialog info now
* remove unnecessary comments
* Adjusted `select_which_user_directory_to_use` string to be more readable
* improve the dialog box itself
* tougher fix than originally expected but all works as planned
* remove unnecessary code
* Updated license headers
* MainActivity.kt: Removed stray newline
* PermissionsHandler.kt: Move repeated "LIME3DS_DIRECTORY" string to `LIME3DS_DIRECTORY` constant
* Nitpicky comment adjustments
* Reverted superficial changes to HomeViewModel.kt
* PermissionsHandler.kt: `updateDirectory` --> `attemptAutomaticUpdateDirectory`
+ nitpicky formatting adjustment
* Moved PR additions to PermissionsHandler.kt to new file CitraDirectoryUtils.kt
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
- Updated to NSIS 3.11
- Updated NSIS installer download URL location
- Use wget to download NSIS setup executable
- Made `Install NSIS` step more verbose via ptime
- Only run `Install NSIS` step for tagged builds
- Reorganized build.yml to have all `if`s at start of scope
* Original Portrait Layout
Original Portrait Layout
* type conversion fix for win
* Updated license headers
* Applied clang-format
* android: Reordered Portrait Screen Layout menu
Custom Layout is now at the bottom of the list
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* framebuffer: Add hybrid layout mode to FrameLayoutFromResolutionScale
* framebuffer_layout.cpp: Moved seemingly misplaced `default` case to proper location
* framebuffer_layout.cpp: Fixed incorrect calculation of framebuffer dimensions for hybrid layout
* framebuffer_layout.cpp: Made implicit cast from float to int explicit
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
* android: Add `isEnabled` setting item conditional check
Co-authored-by: Charles Lombardo <clombardo169@gmail.com>
(Thanks to him for the idea of using DiffUtil)
Now it is possible to have a conditional check for each setting type which once met will disable itself and re-enable once the condition is unmet again in real-time
* Refactor setting checks to deduplicate repeated `isEditable && isEnabled` conditionals
This is done by adding a new value, `setting.isActive` which is equivalent to `setting.isEditable && setting.isEnabled`
* Removed seemingly redundant `isEnabled` overrides
* Updated license headers
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
* Add the turbo slider
* [WIP] Add fast forward toggle hotkey
* Make Increase/Decrease speed hotkeys change turbo key instead of `frame_limit`
* Allow non-runtime editable settings on `general` settings tab`
* `frame_limit` is now non-runtime-editable
* Disable `toggle per game speed limit` if turbo mode is set
* Reset `frame_limit` back to initial value once the emulator closes
* Improve `AdjustSpeedLimit`
- Set frameskip value directly
- Bypass if turbo mode isn't active
* Some code cleanup
* Move `turbo_speed_slider` from UISettings to CommonSettings
Also rename to just `turbo_speed`
* android: Add turbo mode hotkey
* Fixed build failure + Applied clang-format
* configure_general.ui Make padding on right side of sliders consistent
Not sure why there's a difference here, so I just threw in a spacer
* android: Corrected build failures caused by bad merge
* Updated `turbo_speed_description` to be a little more descriptive
* android: Corrected turbo crash caused by bad JNI function names
* Updated license headers
* HotkeyFunctions.kt: Fixed minor fomatting irregularities
* Applied clang-format
---------
Co-authored-by: kleidis <167202775+kleidis@users.noreply.github.com>
If the fragment got paused while emualtionState also was paused manually
via the menu bar, once the fragment got unpasued , the binding would
still remain paused
- All buttons which open a modal interface now disable themselves until their interface is closed
- Renamed button_linked_console to button_unlink_console to better reflect what it actually does
- Changed the warning icon of the Regenerate Console ID button to be the same as the Regenerate MAC Address button
* android: Add uninstall game and open folder options
* Updated license header
* getGameDirectories: Cleanup
* Fixed "Open Updates Folder" button not working correctly
* Made "Open Extra Folder" behaviour consistent with other options when Extra folder not found
* strings.xml: Corrected double newline
* android: Adjusted about game dialog layout
---------
Co-authored-by: Kleidis <167202775+kleidis@users.noreply.github.com>
* Check that the country setting is valid for selected region
* `SystemSaveGame.checkCountryCompatibility` -> `SystemSaveGame.getCountryCompatibility`
* SettingsFragmentPresenter.kt: Moved `checkCountryCompatibility` definition out of `addSystemSettings`
* SettingsFragmentPresenter.kt: Renamed `compat` value to `compatFlags` for better readability
* configure_system.ui: Corrected indentation
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Mark console as "linked" when using the azahar artic setup tool
* Updated strings related to console linking
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* Stereoscopic 3D Enhancements
- Increase maximum 3D depth to 255%
- Fix touch screen to only render 2D when separate window layout is used
- Cleanup some 3D option localizations
* qt: Added warning label below depth slider for values over 100%
* Fixed broken rendering for Interlaced, Reverse Interlaced and Anaglyph options when using 3D with seperate windows
* android: Added warning label below depth slider for values over 100%
* Fixed a bracket and break statement being incorrectly positioned
---------
Co-authored-by: oneup03 <oneup03@gmail.com>
This option was originally disabled due to some devices not supporting OpenGL, however it was implemented by hardcoding the option to be set to OFF via CMAKE_DEPENDENT_OPTION. This change now allows the user to manually set ENABLE_OPENGL to ON in the CMake options, which was previously not possible.
* Fix bug where log file was not generated on first run
This fix resolves issue #727.
On first start, Log::Initialize attempts to create the `azahar-emu/log/`
directory. However, it fails because `azahar-emu/` does not exist. Using
FileUtil::CreateFullPath instead will create both `azahar-emu` and
`log/`.
* Update license header
- [ ] I have read the [Azahar AI Policy document](https://github.com/azahar-emu/azahar/blob/master/AI-POLICY.md) and have disclosed any use of AI if applicable under those terms.
---------
---
<!--
If you are contributing to Azahar for the first time please
keep the block of text between `---` and write your
PR description below it. Do not write anything inside
or change this block of text!
If you are a recurrent contributor, remove this entire
block of text and proceed as normal.
-->

- name:Detect PR if author is first-time contributor
uses:actions/github-script@v9
with:
script:|
const { owner, repo } = context.repo;
const pr = context.payload.pull_request;
// Add needs verification label so that the reopen action runs on comment.
await github.rest.issues.addLabels({
owner,
repo,
issue_number:pr.number,
labels:['needs verification'],
});
// Close the pull request and wait for verification.
await github.rest.pulls.update({
owner,
repo,
pull_number:pr.number,
state:'closed',
});
// Show the new contributor how to verify (they need to write a short poem about the Wii and 3DS being lovers)
await github.rest.issues.createComment({
owner,
repo,
issue_number:pr.number,
body:'Welcome to the Azahar Emulator repository! Due to the surge of AI bots we have decided to add an extra verification step to new contributors. Please follow the exact instructions in your own written Pull Request description to reopen it.',
const body = comment.body.toLowerCase().trim().replace(/[^a-z0-9_\-\s]/g, '').split(/\s+/);
// Check that the user verified themselves by writing a song about the NES and the SNES.
const verified =
(body.includes(username) ||
(displayName && body.includes(displayName))) &&
body.includes('azahar');
// Only reopen the PR and remove the label if verification succeeded
if (verified) {
await github.rest.pulls.update({
owner,
repo,
pull_number:issue.number,
state:'open',
});
await github.rest.issues.createComment({
owner,
repo,
issue_number:issue.number,
body:'Verification successful! Pull request has been reopened. Please also edit your PR description to remove the block of text between `---` to make the description easier to read.',
});
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number:issue.number,
name:'needs verification',
});
}catch {}
}else {
await github.rest.issues.createComment({
owner,
repo,
issue_number:issue.number,
body:'Verification failed! Pull request will remain closed.',
The following document outlines the acceptable and unacceptable uses of AI within the Azahar codebase.
It describes whether or not submissions which were exposed to large language models (LLMs) such as ChatGPT, Claude, DeepSeek, and similar models would be capable of being merged in a pull request or otherwise utilized.
- ✅ Use of AI to help developers discover or understand problems in the codebase is acceptable **under the condition that any discovered issue is independently verified by a human**.
- ✅ Use of AI to write code snippets of a sufficiently small size that they aren't reasonably copyrightable **with disclosure in the PR description** is acceptable.
- This will be handled on a case-by-case basis and is up to the interpretation of the maintainer, but generic algorithm snippets up to a maximum of approximately 5 lines of code are acceptable.
- ❌ Use of AI to write code for submission without disclosure is prohibited.
- ❌ Use of AI to write the entirety/ a significant portion of a contribution is prohibited.
- ❌ Use of AI to write snippets of code which are of a size such that they could reasonably be copyrightable is prohibited.
- ❌ Use of AI to rewrite incompatibly-licensed code for submission to Azahar is prohibited.
- ❌ Use of AI to autonomously submit pull requests or issues is prohibited.
Pull requests which violate these rules will be closed. Previously accepted submissions which are found to violate these rules will be retroactively removed from the codebase.
This document may be updated in the future if further clarification is required.
This policy is effective for code submitted on or after the 20th of March 2026.
<b>Azahar</b> is an open-source 3DS emulator project based on Citra.
@ -10,44 +14,67 @@ It was created from the merging of PabloMK7's Citra fork and the Lime3DS project
The goal of this project is to be the de-facto platform for future development.
> [!NOTE]
> Azahar has not fully released yet. For this reason, there are no compiled binaries available for download.
>
> It is recommended that only developers and early adopters should use the emulator until our first stable release.
>
> Here be dragons.
<!--
# Installation
### Windows& MacOS
### Windows
Download the latest release from [Releases](https://github.com/azahar-emu/azahar/releases).
Azahar is available as both an installer and a zip archive.
Download the latest release in your preferred format from the [Releases](https://github.com/azahar-emu/azahar/releases) page.
If you are unsure of whether you want to use MSVC or MSYS2, use MSYS2.
---
### Android
The recommended method of downloading Azahar on Android is via the [Google Play store](https://play.google.com/store/apps/details?id=io.github.lime3ds.android).
Alternatively, you can install the app using Obtainium:
### MacOS
To download a build that will work on all Macs, you can download the `macos-universal` build on the [Releases](https://github.com/azahar-emu/azahar/releases) page.
Alternatively, if you wish to download a build specifically for your Mac, you can choose either:
- `macos-arm64` for Apple Silicon Macs
- `macos-x86_64` for Intel Macs
---
### Android
There are two variants of Azahar available on Android, those being the Vanilla and Google Play builds.
The Vanilla build is technically superior, as it uses an alternative method of file management which is faster, but isn't permitted on the Google Play store.
For most users, we currently recommended downloading Azahar on Android via the Google Play Store for ease of accessibility:
<ahref='https://play.google.com/store/apps/details?id=io.github.lime3ds.android'><imgwidth='180'alt='Get it on Google Play'src='https://raw.githubusercontent.com/pioug/google-play-badges/06ccd9252af1501613da2ca28eaffe31307a4e6d/svg/English.svg'/></a>
Alternatively, you can install the app using Obtainium, allowing you to use the Vanilla variant:
1. Download and install Obtainium from [here](https://github.com/ImranR98/Obtainium/releases) (use the file named `app-release.apk`)
2. Open Obtainium and click 'Add App'
3. Type `https://github.com/azahar/azahar-emu` into the 'App Source URL' section
3. Type `https://github.com/azahar-emu/azahar` into the 'App Source URL' section
4. Click 'Add'
5. Click 'Install'
5. Click 'Install', and select the preferred variant
If you wish, you can also simply install the latest APK from the [Releases](https://github.com/azahar-emu/azahar/releases) page.
Keep in mind that you will not recieve automatic updates when installing via the APK.
---
### Linux
Azahar is available as an AppImage on the [Releases](https://github.com/azahar-emu/azahar/releases) page.
The recommended format for using Azahar on Linux is the Flatpak available on Flathub:
We are also on Flathub:
<ahref='https://flathub.org/apps/org.azahar_emu.Azahar'><imgwidth='180'alt='Download on Flathub'src='https://dl.flathub.org/assets/badges/flathub-badge-en.png'/></a>
<ahref=https://flathub.org/apps/org.azahar-emu.azahar><imgwidth='180'alt='Download on Flathub'src='https://dl.flathub.org/assets/badges/flathub-badge-en.png'/></a>
-->
Azahar is also available as an AppImage on the [Releases](https://github.com/azahar-emu/azahar/releases) page.
There are two variants of the AppImage available, those being `azahar.AppImage` and `azahar-wayland.AppImage`.
If you are unsure of which variant to use, we recommend using the default `azahar.AppImage`. This is because of upstream issues in the Wayland ecosystem which may cause problems when running the emulator (e.g. [#1162](https://github.com/azahar-emu/azahar/issues/1162)).
Unless you explicitly require native Wayland support (e.g. you are running a system with no Xwayland), the non-Wayland variant is recommended.
The Flatpak build of Azahar also has native Wayland support disabled by default. If you require native Wayland support, it can be enabled using [Flatseal](https://flathub.org/en/apps/com.github.tchx84.Flatseal).
# Build instructions
@ -79,18 +106,23 @@ To do so, simply read https://github.com/azahar-emu/compatibility-list/blob/mast
Contributing compatibility data helps more accurately reflect the current capabilities of the emulator, so it would be highly appreciated if you could go through the reporting process after completing a game.
# Minimum requirements
Below are the minimum requirements to run Azahar:
### Desktop
```
Operating System: Windows 10 (64-bit), MacOS 13 (Ventura), or modern 64-bit Linux
CPU: x86-64 (64-bit) CPU. Single core performance higher than 1,800 on Passmark
Operating System: Windows 10 (64-bit), MacOS 13.4 (Ventura), or modern 64-bit Linux
CPU: x86-64/ARM64 CPU (Windows for ARM not supported).
Single core performance higher than 1,800 on Passmark.
SSE4.2 required on x86_64.
GPU: OpenGL 4.3 or Vulkan 1.1 support
Memory: 2GB of RAM. 4GB is recommended
```
### Android
```
Operating System: Android 9.0+
Operating System: Android 10.0+ (64-bit)
CPU: Snapdragon 835 SoC or better
GPU: OpenGL ES 3.2 or Vulkan 1.1 support
Memory: 2GB of RAM. 4GB is recommended
@ -103,6 +135,7 @@ We share public roadmaps for upcoming releases in the form of GitHub milestones.
You can find these at https://github.com/azahar-emu/azahar/milestones.
# Join the conversation
We have a community Discord server where you can chat about the project, keep up to date with the latest announcements, or coordinate emulator development.