Welcome back to another Citra Mega Progress Report!
Yes! We aren’t dead! First off, we do apologize for the wait, we are still lacking a full-time writer. In the meantime, Citra community moderator autumnburra and developer FearlessTobi have come together with the assistance of another community moderator, SleepingSnake, to provide you, the Citra community, with this awesome report on all the changes we’ve had in Citra since 2020 Q2!
If you have been keeping up to date with messages posted in the
#development channel in our Discord server, you may already be aware of some of these. But nevertheless, this is a read that you’re not going to want to miss out on!
Implement basic rerecording features (#5448) by zhaowenlan1779
Following on from the built-in video dumper, mentioned in our previous Progress Report, zhaowenlan1779 provides some much needed versatility for your video recordings and TAS recordings!
The changes include features such as adjusting the emulation speed and being able to sync-robust save states when rerecording. Sync-robustness is the concept that if a save state is launched a certain number of times, it should behave the exact same way each time. Being able to use rerecording in an emulator is key when wanting to create TAS videos! Rerecording is used for the validation of TAS scripts, which are used to get the most optimized speedrun of a game.
This PR implements many basic rerecording features, following the TASVideos requirements and desired features for a rerecording emulator, but also adds other needed features for our built-in video dumper such as separate save state slots for each movie, adding a read-only mode, fixing desync and file corruption bugs, and also remaking the UI to be squeaky clean!
To utilize the rerecording features, head to
Tools -> Movie to record your game as a
.CTM (Citra TAS Movie) file. These
.CTM files can then be played back from within Citra to use for TAS runs.
Interlaced 3D is a method of displaying stereoscopic 3D content on passive 3D supported monitors and TV screens. This was first implemented in Citra in 2019 to provide more ways to view 3D on a wider range of devices. However, some monitors, such as LG OLED 3DTV’s, render each eye in a reverse order from typical interlaced monitors. This PR implements a new way to view the 3D capabilities on a new type of screen, keeping the 3D novelty of the 3DS that so many of us love alive.
This setting can be found in
Emulation -> Configure (
Citra -> Preferences on MacOS), inside the
Graphics tab. Make sure to set the Depth to 100% to utilize this feature.
Citra stores the SDMC and NAND folders in a standard user directory location, which is typically located on the same drive as your operating system. The SDMC folder houses your installed games, updates, DLC, and save data, which can quickly accumulate and become large in size depending on your game library. The NAND folder emulates the 3DS’s memory chip and contains the system archives and shared fonts of the 3DS, which can be dumped from your own console. However, Citra has its own open-source implementation of these files that comes with every installation of Citra.
Because the user directory is typically not changeable, users who have limited storage space on their primary drive can encounter issues. This PR solves this problem by allowing users to specify a custom location for the SDMC and NAND folders. Adding this was a big feat, requiring the assistance of multiple developers.
The initial implementation by nieldm saw slew of other issues, such as internal issues with the custom paths and every user being accidentally forced to use custom directories for SDMC and NAND! All of these issues were ironed out by the joint effort of our developers and we’re proud to say that custom directories for SDMC and NAND are here to stay!
As we are entering the mid 2023’s, Citra is long due for a makeover! First on the list of things to make Citra shiny again is to polish up our OpenGL graphics backend.
A fundamental part of Citra’s renderer, regardless of the graphics API used, is a component known as the rasterizer cache, which is responsible for tracking all memory reads and writes to the emulated 3DS VRAM. The rasterizer cache is Citra’s version of the texture cache, a concept well known to avid emulation followers.
But why is this needed? To answer said question, we need to look closer into the architecture of the 3DS. It, alongside other Nintendo consoles of the era such as the Wii, uses a unified memory architecture (UMA), allowing both the CPU and the GPU to access the same memory region. Your computer, on the other hand, works much differently; the system RAM is separate from the video RAM. Access to system RAM from the CPU is relatively fast, something that’s not the case when it comes to video RAM. The latter can also be accessed by the CPU. There’s one problem though; doing that is very slow.
The main function of the rasterizer cache in Citra is to keep textures in the host VRAM, in the computer’s GPU, so that the renderer can access them quickly while also keeping the host VRAM in sync with the emulated 3DS VRAM. This is particularly necessary for resolution upscaling. As an example, if you had to upload a 2560x1400 texture each frame, the performance would be terrible!
In the past, this rasterizer cache was tied with OpenGL and used OpenGL methods directly. This PR introduces a class called
TextureRuntime. This is used to abstract away texture operations from the rasterizer cache. By doing this, it allows for other graphic APIs to be easily ported over to Citra, which we will get into later in this report.
.3gx plugins are executable files that are mapped into memory and executed when the game process runs. When the game runs, the
.3gx plugins also run simultaneously in a new thread, which grants it the same access rights as the game. This allows developers to expand the behavior of games in a way that would normally be impossible, such as with an Action Replay code.
.3gx plugins is another way to add that extra customizability to your 3DS games in a way that the unmodded 3DS can’t do. Many projects use these plugins, such as the Mario Kart 7 modpack CTGP-7.
In the past, due to Citra not supporting
.3gx plugins, a “lite” version of this modpack was offered to Citra players. But this came with nowhere near as many tracks and features as the main modpack! The addition of this plugin loader grants Citra users with more modpacks to alter your game in more ways than before.
Plugins are loaded from the emulated 3DS SD card. Citra follows the same path as the Luma3DS 3GX Plugin Loader to apply
.3gx plugins. Instructions for launching
.3gx plugins can be found on our Game Modding page.
Add Nearest Neighbour Texture Filter (#6189) by venkatrao1
If you hadn’t seen in our previous Progress Report, Texture Filters were added to Citra! With texture upscaling, Citra will use one of several algorithms to automatically upsize the image to a higher resolution.
Nearest Neighbour is a texture filter which is particularly effective at making text stand out and look bolder! With the addition of another highly requested texture filter, you can have more control over how your gameplay looks than ever before!
All of these texture filters, including our shiny new Nearest Neighbour texture filter, can be found in
Emulation -> Configure -> Graphics -> Renderer in Citra! (
Citra -> Preferences on MacOS)
Left: unfiltered, Right: Nearest Neighbour
Better Support for Picture-in-Picture Custom Layouts (#6247) by SomeDudeOnDiscord
Based on an older PR which never saw the light of day, this PR improves our custom layout handling to support a “picture-in-picture” style of displaying the two 3DS screens. This enables you to have two screens overlapping one another to fit within one cohesive view, which is especially useful when in fullscreen.
The screens can be swapped using the
F9 hotkey within Citra, which allows for a choice of which screen is the main screen and which is the secondary smaller screen. The secondary screen is also slightly transparent, ensuring that the main screen isn’t completely covered up!
In the past, to configure your controller you were required to manually map every single button and joystick direction. This proved to be a tedious activity and would eat into time that you’d rather use playing games! vitor-k implemented a way to automatically map your controller to Citra with the press of a button, provided that your controller is listed in the SDL Controller Database.
Disable HIDAPI drivers due to compatibility problems with certain controllers (#5123, #5179) by vitor-k
The change of SDL2 from 2.0.8 to 2.0.10 broke some controllers that reported themselves as a Switch or Xbox One controller, such as DualShock 4 controllers. This PR disables the HIDAPI drivers to allow affected controllers to work again. HIDAPI drivers were enabled again for SDL2.0.12 and up in a later PR.
Ported over from yuzu, with code and feature improvements thanks to german77 and lioncash, this adds a whole new input device to Citra for you to use! With the official GameCube adapter from Nintendo, you can now use the classic GameCube controllers to play your favorite games on Citra!
Instructions on how to set this up can be found on the yuzu FAQ.
Add support for SDL controller accelerometer/gyro events (#5851) by flibitijibibo
Following the release of SDL 2.0.14 came support for motion controls, something which had been anticipated for many years in SDL. In Citra, this can be used as an alternative to mouse controls or CemuhookUDP. This is a big benefit to many users, as setting up Cemuhook can be tedious and outright confusing at times. Setting up SDL motion controls is as easy as pressing a button! (No, seriously. That is all you have to do.)
If you missed the last announcement, this is a follow up to our previous Citra Android Update!
Our Google Play Store release is outdated at the moment due to Google’s new storage permissions system, but we are still updating Citra Android! Builds can be downloaded from our Nightly repository for the time being. We will update Citra Android on the Google Play Store soon.
To use all of these brand new features for Android, make sure you have downloaded and installed the latest
.apk from our Nightly repository. Keep in mind that these manually downloaded builds won’t update automatically!
Arguably one of the most anticipated and requested features for Android is finally here!
A shader is a small program that runs on your GPU. Whenever the game tells Citra to run a new shader, Citra translates this shader, so that your GPU can understand it. Then, it gets uploaded to your GPU. This entire process can take a bit of time, so Citra has to pause emulation until the shader is ready, causing stutter whenever the game is drawing something for the first time.
First implemented on Citra Desktop back in January 2020, the disk shader cache has proved to be very effective in reducing stutters over time for all games.
By using a disk shader cache, Citra can save these shaders when they are first generated, then preload them on any subsequent launch of the game, eliminating stutter. It was only a matter of time before this was implemented on Android for the benefit of all our Android users, and thanks to SachinVin this has been achieved!
Backport commits from citra-emu/citra-android to citra-emu/citra (#5624, #5823, #5906, #5876) by SachinVin and xperia64
Just to keep things tidy for developers on our GitHub page, many commits from the now defunct “citra-android” repository have been backported to our main repository, affectionately just named “Citra”. By doing this, future development of Citra Android has become more centralized and will hopefully steer developers new and old in the right direction.
For a long time, if you wanted to add cheats in-game, you needed to do this manually by editing a text file containing the cheat code(s) in the Citra User Directory. This proved to be a complicated way to do things, especially when taking Android’s file management systems into consideration.
Fans of Citra had been begging for an intuitive way to add cheats to their favorite 3DS games. JosJuice, a developer for the GameCube and Wii emulator Dolphin, stepped up to the task and added a cheat GUI based off of Dolphin’s own implementation!
A hurdle in development was found instantly, though. If you slid a panel away while focused on a text box, such as the cheats text box, the keyboard would stay open without an option to close it! This would be frustrating, and require a restart of Citra to get rid of the keyboard. With a fix ported over from Dolphin, originally written by t895, the keyboard now closes automatically, as intended!
The new cheat menu allows you to input the cheat name, the cheat itself, and any notes about the cheat you would like to add! The cheat menu can be accessed from the in-emulation menu to add, modify, and delete your cheats. However, cheats cannot be disabled while in-game. You must reboot your game for any changes to the cheat code to take effect.
Add support for custom textures and texture dumping (#6144) by LeviathaninWaves
Custom Textures are a powerful tool that allows modders to enhance the texture quality of a game, resulting in even more visually stunning gameplay. Due to the low resolution of the 3DS, games often used low-quality, compressed images for their models, so when Citra renders at upscaled resolutions, they can appear less than perfect. Texture Dumping is a simple process that allows you to collect all the textures from a game while you play through it. No need to do anything fancy, all you need to do is play! These dumped textures can be used for archival purposes or to create your own Custom Texture Packs, which can then be added back into Citra to enhance the gaming experience.
To add Custom Textures to Citra, navigate to
Internal Storage -> citra-emu, create a folder called
load, another folder inside that called
textures, then a folder named the TitleID of your game. These TitleIDs can be found on the 3DS releases database if you do not know it.
Place your custom textures inside this folder with the TitleID of your game. Dumped textures are stored in
Internal Storage -> citra-emu -> dump -> textures.
Both Dump Textures and Custom Textures can be enabled in
Settings -> Graphics -> Utility
This addition is basically what it says on the tin. Some homebrew apps require internet access to download data needed for them to work correctly, such as the Mario Kart 7 modpack CTGP-7. As this is what is known as a “normal permission” granted from Android, any users of Citra do not need to agree to any additional privacy policies that may have been introduced due to this.
NOTE: This PR does not mean that Citra Android has multiplayer access. It is only related to homebrew apps at the moment.
The recent release of Android 13 on some newer devices has caused significant problems with Citra’s user interface. No longer could you swipe down from the top to open the in-game menu. Instead, just the phone notification bar would be brought down.
Due to this, you could no longer access Save States, Amiibo, Screen Layout, Overlay, FPS counter, and more. This has made it difficult to fully utilize Citra’s capabilities on devices running Android 13.
The solution was to use the back button found on all devices to open the in-emulation menu instead! This can be accessed from the bottom of the device, next to the Home and Recents button. The in-emulation menu is accessible on a number of devices now, such as Chromebooks running Citra Android and VR headsets, not just devices running Android 13.
This PR allows for controls introduced by the New Nintendo 3DS to be utilized in Citra while New 3DS mode is enabled. The New Nintendo 3DS came with the addition of the C-Stick, and the ZL and ZR trigger buttons. These can now be used in Citra in games such as Super Smash Bros. for Nintendo 3DS to give you more control over how you play your game!
For a while, the Mii voices in Tomodachi Life would constantly cut off before they would finish speaking, which could make it hard to understand what they are saying to the player. By implementing a partial embedded buffer, this being an area of memory which stores data on a temporary basis, you can hear the sweet voices of your favorite Miis again!
This also fixes an issue where FMVs in Detective Pikachu would run faster than what the frame rate allowed for.
service/apt: Implement Deliver Args (#5611) by zhaowenlan1779
This partially fixes an issue where some games would show black and white screens when launched. By implementing Deliver Args, a way to pass arguments from one 3DS application to the another, as well as
JumpToApplication APT services, this allows the game to crash with a fatal error instead of just hanging on a black screen.
This is a step in the right direction for getting these games, such as Sega 3D Classics Collection, to boot correctly on Citra in the future.
gl_rasterizer_cache: Remove all fully invalid surfaces from the cache (#5710) by BreadFish64
The dead weight of fully invalid surfaces being held in the rasterizer cache impacted many cache management functions and texture lookup times, which in turn lowered performance on some games, such as Pilotwings Resort.
By removing all fully invalidated surfaces and implementing a map of recycled textures from destroyed surfaces to avoid driver overhead from allocations, performance on poorly behaved games has greatly increased.
svcGetSystemInfo is used by 3DS applications to gather the information of a system, such as whether someone is playing on a 3DS or 2DS, and to communicate this information back to the application. Homebrew apps also use this for the same purposes.
As homebrew apps had no way of telling whether they were running on hardware or on Citra, this implements a way for those aforementioned homebrew apps to finally tell if they are being run on Citra or not!
In the past, Citra faced a problem where any copies or operations held at the end of the emulated VRAM were not understood correctly, causing them to be completely ignored. This would cause numerous errors in the emulation of games, including some graphics being cut out entirely on HarmoKnight.
By allowing MemoryRef, a wrapper over a pointer to physical memory used for serialization, to hold a past-the-end offset, these values can now be correctly understood and executed. This means that the errors previously experienced due to ignored values will be resolved, leading to a more accurate and improved emulation of games on Citra.
While most games easily run at full speed nowadays, a long standing issue in Citra has been pre-rendered cutscene videos running way too slowly. This has always been a bit of a mystery, since decoding a video at a resolution of 240p shouldn’t be too taxing on the system of an average user.
By implementing more accurate cycle counting, we are happy to announce we have made the first step towards solving this problem, improving FMV video performance by up to 3x! To understand what this means, we need to take a closer look at how a processor works.
On the lowest level, all that a CPU does is process a list of instructions. Some instructions however take longer to execute than others. The time it takes for an instruction to execute is measured in cycles. Previously, we were using a very naive implementation of assuming every instruction would take one cycle. This leads to games idling longer than they should, therefore unnecessarily slowing down the emulation. Now merryhime, the author of dynarmic, has implemented much more accurate cycle counts, significantly reducing this issue. Performance is still problematic due to currently unknown reasons, so please expect FMV videos to run at half speed on hardware that only meets our minimum recommendations.
This PR implements two key services relating to Download Play Applet functionality on Citra.
GetWirelessRebootInfo are used to transfer information and arguments between reboots of Download Play. These are necessary so that the app is able to start another app, like in the way Download Play works via transferring a game demo from one console to another. Download Play does not work in Citra just yet. This PR is just to lay the groundwork for it to hopefully work in the future!
The implementation of
EjectClient is required to be able to disconnect from a multiplayer session correctly if the host chooses to terminate the room or force-disconnect clients. This allows for multiplayer to work correctly in certain games, such as the Monster Hunter series.
service/nwm_uds: Various improvements/corrections (#5382) by zhaowenlan1779
This PR is just a minor fix to multiplayer in the Monster Hunter games, specifically Monster Hunter Generations, Monster Hunter X, and Monster Hunter XX. These games would suffer from crashes and disconnects when players tried to join a lobby. Now, with this fix, you can go out and hunt your favorite monsters with your friends again!
With some reorganization of the code, we were able to reduce the size of the citra-room executable by 85%, decreasing citra’s compressed size by 6MB and uncompressed size by 43MB! Those who host rooms with citra-room will also no longer need to have OpenGL support on their machines.
GetApplicationData, an issue is resolved in which multiplayer communications would only work one way in Dragon Ball Fusions. This change also fixes multiplayer altogether in Final Fantasy Explorers.
GetApplicationData is used to load appdata from the current beacon, which can then only be used while connected to the network.
When playing multiplayer games, it is helpful to be able to identify your friends. But previously, when using the room feature in some games, everyone was named “Citra”!
This issue caused a lot of confusion and made it very hard to identify individual players. The problem was due to a stubbed function in the friend service that was hardcoded to return “Citra”, regardless of the name the user had configured in the Citra settings. vitor-k corrected this and now the user-configured name is displayed correctly.
An arguably simpler way of taking screenshots in game, without taking you away from the action to name and save them! Use the Capture Screenshot hotkey (default hotkey being CTRL+P) to quickly save them to the screenshots folder in the Citra User Directory.
Are you tired of the same old Light and Dark themes? Good news! Citra now offers two new themes: “Midnight Blue” and “Midnight Blue Colorful,” inspired by the yuzu themes of the same names. These themes provide even more customization options for your Citra experience.
Citra SDL: graceful shutdown on application close (#6102) by ian-h-chamberlain
When closing Citra SDL, the command line counterpart to our normal GUI version that most people will be used to, the window would remain open unintentionally which required a forceful shutdown to close properly. This would result in cleanup tasks, such as video dumping, failing. This isn’t very nice if you’ve just spent a long time working on a video just to lose it!
By implementing a graceful shutdown, the window will close normally and a standard cleanup can be utilized. This results in better closing practices for the SDL version of Citra, and ensures that any data is not lost either!
Another very long awaited feature, Separate Windows, has arrived in Citra!
Since the conception of Citra in 2014 (yes, that long ago!) users had been asking for a way to split the two screens of the 3DS shown in Citra into two separate windows. This would allow you to move the two screens around to wherever you want on your PC, and to be used on two separate monitors too! Unfortunately, no one was able to do this for a very long time, until epicboy came along…
To enable this feature, head to
View -> Screen Layout -> Separate Windows from within Citra. Launch your game, and from there you can edit the size and location of the windows to wherever you want on your PC!
When you run Citra without Single Window Mode enabled, you have the game window and the game list window open at the same time. If you clicked another game in the game list, it’d instantly boot, closing your current game.
After experiencing this themselves when accidentally launching another game while already in a game, foghawk added a confirmation check. No longer will you lose any important save data from this issue, and you can carry on playing after selecting one of the two options!
Based off of the yuzu implementation of the same name, Per-Game Configurations have landed in Citra! This is part of a series of changes coming to Citra to modernize the frontend of the emulator.
With this new change in Citra, you no longer have to manually adjust the settings every time you launch a game. Each game now has its own individual settings profile that you can customize to your liking. You can easily modify the emulation speed, graphical settings, audio settings, and volume of each game, among many other options. This feature saves you time and hassle, allowing you to quickly jump into playing your favorite games without worrying about adjusting settings every time.
With this PR, the option for Alternate Speed, which was available in the general settings of Citra, has been removed in favour of an option called Per-game Emulation Speed. This setting works in the exact same way as the previous Alternate Speed setting, however it is now found inside of the per-game settings instead of the global settings. The hotkey for this has also been renamed appropriately to reflect the name change of the setting.
Individual config files for each per-game setting you may have are stored in
config -> custom -> <titleid>.ini These
.ini files can be edited using a text editor application, and the changes will appear in Citra.
This is another addition which has been highly requested in the Citra community, and we are proud that it is finally here.
Just a small QoL update here! Having a dropdown box to change between two settings is pretty clean, don’t you think?
Stereoscopic is the default in Citra for 3D capabilities, which displays the 3D to both eyes at the same time. Monoscopic rendering emulates the 3D capabilities of the 3DS to one screen for each eye. The Stereoscopic 3D modes will use various methods for displaying each screen to the correct eye, but monoscopic mode just chooses one of them to be displayed. Some games render differently depending on which eye is shown. The major image differences between the eyes happens at 0% depth, as some games do not bother rendering some elements of in game material to both eyes.
jakedowns implemented a left eye option for the Monoscopic Renderer to further Citra’s compatibility with ReShade, a post-processing injector for video games. However, the initial tick box included with the PR to switch from the left eye to right eye was just a little clunky.
By adding a dropdown box to change between the left eye and right eye, this ensures that the games will display correctly on Citra while emulating the 3DS’s 3D capabilities.
Ports from yuzu by FearlessTobi and vitor-k
Prior to this PR, users using fractional scaling would encounter a bug that made the emulated image not render correctly. Fixing the framebuffer size ensures that the image is displayed correctly on your screen when using the GUI for Citra.
This is what it says on the tin! A keyboard hotkey to easily mute your game audio without having to mess about accessing settings. This allows for more seamless gameplay, especially for those who use controllers and just have their keyboard off to the side for hotkey usage.
Even when working on a giant project like Citra with many developers, spelling mistakes still sometimes slip through the cracks. We’re only human! This PR cleans up any spelling mistakes found in Citra to make sure it is clear and understandable to users.
Update submodule discord-rpc to latest (#5810) originally by CaptV0rt3x
As you may be aware, Citra utilizes Discord RPC to display the current game you are playing onto your Discord profile. This PR updates the discord-rpc submodule to the latest version, as well as a few minor bug fixes, to ensure that you are still able to show your favorite game(s) to all of your friends!
Translations for the compatibility ratings and sorting categories for ROMs had been completed for many languages, but never officially implemented in Citra! This PR just fixes this little oversight and now Citra serves these ratings in many languages from across the world.
Last but not least, we are happy to announce that one of our most requested features is now in development!
Developer GPUCode has been hard at work adding a brand-new Vulkan backend to Citra! Vulkan is a graphics API similar to OpenGL which is currently used for Citra’s video backend. Unlike OpenGL, however, Vulkan allows for a much lower-level access to the GPU, allowing us to make use of optimizations that are currently not possible in OpenGL.
Please note that this feature is still very much a Work-In-Progress, but initial tests have been very promising already! With some configurations, performance in games has more than doubled, with Android devices receiving a significant speedup, especially for those using a Mali GPU. Mali GPUs, which are commonly included with Exynos and MediaTek SoCs, are known for having poor OpenGL ES drivers. This causes devices with those GPUs to have low performance on Citra while using our OpenGL ES backend. With the addition of Vulkan, Citra is made more accessible to many more people, not just those who have a Snapdragon SoC.
To achieve this feat, GPUCode has been undertaking a massive rewrite of the OpenGL backend and the video_core as well, to streamline and simplify the code, making it easier to reuse code between both backends.
Another advantage of Vulkan is being able to use MoltenVK on MacOS devices. We have recently changed our OpenGL requirements from 3.3 to 4.3 (more on this is explained in our FAQ) in an effort to modernize Citra’s graphical backends. Since Apple has dropped support for modern OpenGL back in 2018, this has resulted in our users on MacOS being stuck on an older version of Citra, not being able to use all the shiny new features we’ve covered here! Using Vulkan, support of Citra will be brought back to thousands of users on their Mac devices!
We are very excited to share more information about Vulkan at a later point, as it is still being worked on every day. Please be patient while this massive effort comes to life, as a big project like this does take a long time to materialize!
All in all, it has been a tremendous couple of years for Citra development, albeit a bit slow. We hope this Progress Report goes a long way to show that Citra development is very much alive and active, despite the long period of silence on our website. We are proud of our developers, new and old, who have shown us the love they have for this project in many ways. Expect to hear more continued updates from us soon!
If you want to support this project, we have a Patreon! Donations to the Patreon go directly to our team to assist with obtaining hardware for testing and keeping our servers up and running. Donations are not required, but are greatly appreciated!
If you are looking to contribute to Citra or just want to get involved with our community, you can find us on our Discord server or on our IRC channel (#citra @ Libera.Chat). Additionally, we’re still looking for writers! If you are interested in being a writer of these blog posts, please reach out to us on Discord.
Thank you for reading and keep your eyes peeled here, there is more to come in the future!