Fixes dynamically changing dpi scaling.
Load resources from svg if possible.
Currently svg support is not in Qt build in Externals,
and image files need to be added later.
GraphicsChoice is used by the panes in the Graphics config window to
create combo boxes that change their associated config setting, and
update their own state when something else changes the config setting.
Despite its current name nothing about this class is particular to the
Graphics window, so renaming it to ConfigChoice better reflects its
purpose. This should also make it less confusing when ConfigChoices are
eventually added to the other config windows.
QApplication should parse and remove and args it recognizes
before dolphin starts inspecting the args.
This allows using e.g. -style <style> on the commandline.
PR #11183 regressed the lookup table reconstruction and, for some reason, added an else clause that clobbered the dCache whenever dCache emulation is turned on.
GraphicsBool is used by the panes in the Graphics config window to
create checkboxes that change their associated config setting, and
update their own state when something else changes the config setting.
Despite its current name nothing about this class is particular to the
Graphics window, so renaming it to ConfigBool better reflects its
purpose. This should also make it less confusing when ConfigBools are
eventually added to the other config windows.
In older versions of Dolphin GraphicsBoolEx was used to create a pair of
radio buttons selecting one of Virtual XFB and Real XFB, but this was
removed with the introduction of Hybrid XFB in 65cd085f.
In the meantime GraphicsRadioInt was introduced to allow for Graphics
radio buttons with multiple options, so GraphicsBoolEx is now redundant.
Previously this was using the default deleter (which just calls delete
on the pointer), which is incorrect, since the ENetHost instance is
allocated through ENet's C API, so we need to use its functions to
deallocate the host instead.
Before, any call of Settings::SetDebugModeEnabled(true) would show it. This means that if the debugging UI is enabled, but the user manually closed the code widget, then toggling any option on the interface pane (such as "Pause on Focus Loss") would cause the code widget to reappear. Additionally, closing and reopening dolphin did not call SetDebugModeEnabled, so the code widget did not reappear in that case (it only appeared after touching the interface pane). This is a bit silly, so now only enabling the debugger does it.
This also somewhat resolves an inconsistency introduced by the previous commit: prior to it, --debugger would call SetDebugModeEnabled(true) and thus show the code pane; after these commits, it does not, as it acts like a config change. This is a behavior difference, but not a particularly important one.
Before, Settings::SetDebugModeEnabled was used; this calls SetBaseOrCurrent() which will usually permanently change the base configuration setting for the debugger to true. Thus, the debugger would remain active even if the --debugger command line option was removed. Now, it remains active only for the current run, like other command-line options.
Note that SetBaseOrCurrent is also used by the "Show Debugging UI" option under Options -> Interface; this means that if the debugger is turned off (or off and then back on) by the user while --debugger is specified, this will be reset to whatever the base configuration had when Dolphin is closed and reopened. This behavior is consistent with the rest of the UI.
To my understanding, the --debugger option is something from 5.0 stable/DolphinWx where there was no way to toggle the debug UI in the settings (and the command-line option was the only way of enabling it). It's less useful nowadays.
This isn't used anywhere and not really a generic utility, so we can get
rid of it.
This also lets us remove MathUtil.cpp, since this was the only thing
within that file.
RetroAchievements Rich Presence is a script that is run periodically on a game's memory to provide a detailed text description of what the player is doing. Existing Discord presence on Dolphin would update a player's Discord status to say not just that they are using Dolphin but that they are playing, for example, Sonic Adventure 2 Battle; Rich Presence would detail that the player is in City Escape with 5 lives and 142 rings.
Activating this in the runtime simply entails loading that text script, as returned by the FetchGameData API call, into the runtime, here only determined by whether rich presence is enabled in the achievement settings. Deactivating this is done via the same rcheevos method by setting the rich presence to an empty string.
This activates or deactivates leaderboards in the rcheevos runtime similarly to achievements. The logic is much more straightforward - all leaderboards are active together; there is nothing requiring some leaderboards to be active while others are unactive, and even a leaderboard that has been submitted to in this session is still active to be submitted to again. The only criteria are that leaderboards must be enabled in the settings, and hardcore mode must be on, the latter of which is false until a future PR.
LoadUnlockData and ActivateDeactivateAchievements are the public API components responding to the FetchUnlocks and A/DAchievement (singular) private methods.
LoadUnlockData is asynchronous and performs both a hardcore and a softcore unlock call, updating the unlock map and the active status of any achievements returned from these calls.
ActivateDeactivateAchievements calls ActivateDeactivateAchievement on every achievement ID found in m_game_data, initializing the unlock map for each ID if not already found.
Both of these are currently called in LoadGameByFilenameAsync once the game has been loaded properly. There's a lock around this, to ensure that the unlock map is initialized properly by ActivateDeactivate Achievements before FetchUnlockData makes modifications to it without stalling the async portions of FetchUnlockData.
FetchUnlockData is an API call to RetroAchievements that downloads a list of achievement IDs for a game that the user has already unlocked and published to the site. It accepts a parameter for whether or not hardcore or softcore achievements are being requested, so that must be provided as well. Once it has the requested list on hand, it updates each achievement's status in the unlock map and will activate or deactivate achievements as necessary.
ActivateDeactivateAchievement is passed an Achievement ID as returned from the FetchGameData API call and determines whether to activate it, deactivate it, or leave it where it is based on its current known state and what settings are enabled.
Activating or deactivating an achievement entails calling a method provided by rcheevos that performs this on the rcheevos runtime. Activating an achievement loads its memory signature into the runtime; now the runtime will process the achievement each time the rc_runtime_do_frame function is called (this will be in a future PR) to determine when the achievement's requirements are met. Deactivating an achievement unloads it from the runtime.
The specific logic to determine whether an achievement is active operates over many fields but is documented in detail inside the function. There are multiple settings flags for which achievements are enabled (one flag for all achievements, an "unofficial" flag for enabling achievements marked as unofficial i.e. those that have logic on the site but have not yet been officially approved, and an "encore" flag that enables achievements the player has already unlocked) and this function also evaluates whether the achievement has been unlocked in hardcore mode or softcore mode (though currently every reference to the current hardcore mode state is hardcoded as false).
XInput2 was created to support multiple pointer/keyboard pairs (often
called MPX for multi-pointer X). Dolphin's XInput2 implementation has
always supported MPX by creating a KeyboardMouse object per master
pointer. Since commit bbb12a7, Dolphin's keyboard state is filtered by
the output of XQueryKeymap. As a core X function, XQueryKeymap queries
"the" keyboard, which by default is the first master keyboard. As a
result, Dolphin will ignore keys pressed on other master keyboards
unless the first master is simultaneously pressing the same keys.
XInput2 doesn't provide a function to query the keyboard state. There
is no XIQueryKeymap and the current state is not a member of the
XIKeyClassInfo returned by XIQueryDevice. Instead, XInput2 allows a
master pointer to be nominated as "the" pointer on a per-client basis,
with "the" keyboard automatically becoming the associated master
keyboard. The "documentation" [1] says passing None for the window is
only for debugging purposes, but it is documented in the
XISetClientPointer man page and seems to be the only way to query
keyboards beyond the first.
With this commit, Dolphin correctly reads keys from keyboards other than
the first master keyboard. To test, use the xinput command-line utility
to create a master pointer and reattach a keyboard to the associated
master keyboard.
[1]: https://who-t.blogspot.com/2009/07/xi2-recipes-part-6.html
(the XInput2 developer's blog)
LoadGameByFilenameAsync sets up a volume reader and hashes the volume, then uses that hash to make the three consecutive API requests to resolve hash, start session and load game data.
CloseGame resets the m_is_game_loaded flag, wipes the queue, and destroys all the game data responses.
FetchGameData is the big one - this retrieves the logic for all the achievements, leaderboards, and rich presence, and all the relevant metadata for the game.
Added a call to the RetroAchievements Start Session API to AchievementManager. This is primarily for client-side activation, so it doesn't return much of value, aside from its success/error information, but I'm storing the return structure in case this changes in the future.
Added the ResolveHash method to AchievementManager. This is a blocking function to send a hash string to the RetroAchievements server to verify it and get a game ID back.
This was previously copying each pair out of the vector returned by
GetInterfaceListInternal() when we just need to emplace the first entry
of each pair.
Fixes us forgetting to add its include directories, which could result in linking to a dylib from MacPorts while using the system's header, and failing to link because they use different function names
bSupports2DTextureStorageMultisample is completely unused, while bSupports3DTextureStorageMultisample is practically unused. In the past, these were checked and fell back to sampler2DMS instead of sampler2DMSArray on GLES 3.1, but this path was removed in f039149198 and Dolphin always uses array textures now.
See https://bugs.dolphin-emu.org/issues/13232; this was introduced in 7dde0c3c31. Apparently, providing a parent for a widget that is not visible makes your new widget visible when the parent is later made visible, in addition to managing the deletion of the widget; the documentation does not specify this (only that if the parent is visible you need to explicitly show it).
The inst.SIMM_16 change is for readability (though it also fixes a warning about potentially unintended uses of `||`).
The fallback change is because `b` is only meaningful for indexed instructions; this could theoretically lead to unintended fallbacks (but it seems unlikely).
The m_checkbox_lock_mouse QCheckBox was only conditionally being added
to the layout, leaving it unmanaged and leaking
Setting the parent will allow it to be managed.
The m_verbosity_debug button was only conditionally being added as
widget, this was done in order to hide the object, but this left it
unmanaged.
Unconditionally adding it to the layout and controlling it's visibility
will resolve these issues
Added AchievementManager class. Upon startup (currently only in DolphinQt), logs into RetroAchievements with the login credentials stored in achievements.ini.
Co-authored-by: AdmiralCurtiss <AdmiralCurtiss@users.noreply.github.com>
Added AchievementSettings in Config with RA_INTEGRATION_ENABLED, RA_USERNAME, and RA_API_TOKEN. Includes code to load and store from Achievements.ini file in config folder.
The QByteArray returned by QString::toUtf8() was being freed so the char
pointer was pointing to freed memory.
Found via ASan, didn't notice any issues during normal runtime.
This was triggered after hitting a key combo with alt (ex. toggle
fullscreen) probably happens with others
This fixes a crash when recording fifologs, as the mutex is acquired when BPWritten calls AfterFrameEvent::Trigger, but then acquired again when FifoRecorder::EndFrame calls m_end_of_frame_event.reset(). std::mutex does not allow calling lock() if the thread already owns the mutex, while std::recursive_mutex does allow this.
This is a regression from #11522 (which introduced the HookableEvent system).
Adds the rcheevos library from RetroAchievements to the Dolphin Externals as a submodule. Change was verified to import correctly and build both via Visual Studio and via cmake ninja.
We have these for a reason. I think this also fixes a theoretical
problem when `ABI_PARAM1 == loop_counter` where the first MOV destroys
the second's value; I'm not sure if this can actually happen in practice
though.
Also works around a bug where CMake's ninja generator doesn't properly handle ||'s on POST_BUILD commands, making the || apply to the whole build like `<link> && custom0 || custom1`
Will manually controlling both an accelerometer and a gyroscope at the
same time be reasonable to do? No idea. Was this easy to implement
thanks to the input override system? Yes.
Fixes https://bugs.dolphin-emu.org/issues/12443.
In UpdateInput, lock m_devices_population_mutex before m_devices_mutex
to be consistent with other ControllerInterface functions. Normally the
former lock isn't needed in UpdateInput, but when a Wii Remote
disconnects it calls RemoveDevice which results in the mutexes being
locked in the wrong order.
This gets rid of a blocking operation, improving performance and fixing
https://bugs.dolphin-emu.org/issues/12893.
This also makes us no longer directly access the state of certain UI
elements from the CPU thread, which probably wasn't thread-safe but
doesn't seem to have caused any observable issues so far.
Up until now, there have been two settings on Android that stored the
selected Wii Remote extension: the normal one that's also used on PC,
and a SharedPreferences one that's used by the overlay controls to
determine what controls to show. It is possible for these two to end up
out of sync, and my input changes have made that more likely to happen.
To fix this, let's rework how the overlay controller setting works.
We don't want it to encode the currently selected Wii Remote extension.
However, we can't simply get rid of the setting, because for some Wii
games we need the ability to switch between a GameCube controller and a
Wii Remote. What this commit does is give the user the option to select
any of the 4 GameCube controllers and any of the 4 Wii Remotes. (Before,
controllers 2-4 weren't available in the overlay.) Could be useful for
things like the Psycho Mantis fight in Metal Gear Solid. I'm also
switching from SharedPreferences to Dolphin.ini while I'm at it.
It's missing a lot of features from the PC version for now, like
buttons for inserting functions and the ability to see what the
expression evaluates to. I mostly just wanted to get something in
place so you can set up rumble.
Co-authored-by: Charles Lombardo <clombardo169@gmail.com>
This is a small regression from KillRenderer, which caused duplicated
frames to be counted on the FPS counter when the "Skip Presenting
Duplicated Frames" option was disabled.
This way, Android (which will show groups in the order they're defined)
will show groups in a more logical order similar to DolphinQt.
The main thing that was annoying me was how early Rumble was for
Wii Remotes. Some of the other changes I'm making in this commit,
like the order of Shake/Tilt/Swing, are more arbitrary and were
made for consistency with DolphinQt. But there are also places
where I didn't go all the way with matching DolphinQt. Most notably,
DolphinQt puts sticks before buttons, but I don't see any reason
to do that for Android.
Unlike PCs, Android doesn't really have any input method (not counting
touch) that can reasonably be expected to exist on most devices.
Because of this, I don't think shipping with a default mapping for the
buttons and sticks of GameCube controllers and Wii Remotes makes sense.
I would however like to ship default mappings for a few things:
1. Mapping the Wii Remote's accelerometer and gyroscope to the device's
accelerometer and gyroscope. This functionality is useful mainly
for people who use the touchscreen, but can also be useful when
using a clip-on controller. The disadvantage of having this mapped
by default is that games disable pointer input if the accelerometer
reports that the Wii Remote is pointed at the ceiling.
2. Mapping GC keyboards for use with a physical keyboard, like on PC.
After all, there's no other way of mapping them that makes sense.
3. Mapping rumble to the device's vibrator.
Aside from the GC keyboards, this approach is effectively the same as
what we were doing before the input overhaul.
This is a battery-saving measure. Whether a sensor should be suspended
is determined in the same way as whether key events and motion events
should be handled by the OS rather than consumed by Dolphin.
When Android presents an input event to an app, it wants the app to
return true or false depending on whether the app handled the event or
not. If the event wasn't handled by the app, it will be passed on to
the system, which may decide to take an action depending on what kind
of input event it is. For instance, if a B button press is passed on to
the system, it will be turned into a Back press. But if an R1 press is
passed on to the system, nothing in particular happens.
It's important that we get this return value right in Dolphin. For
instance, the user generally wouldn't want a B button press to open
the EmulationActivity menu, so B button presses usually shouldn't be
passed on to the system - but volume button presses usually should be
passed on to the system, since it would be hard to adjust the volume
otherwise. What ButtonManager did was to pass on input events that are
for a button which the user has not mapped, which I think makes sense.
But exactly how to implement that is more complicated in the new input
backend than in ButtonManager, because now we have a separation between
the input backend and the code that keeps track of the user's mappings.
What I'm going with in this commit is to treat an input as mapped if
it has been polled recently. In part I chose this because it seemed
like a simple way of implementing it that wouldn't cause too many
layering violations, but it also has two useful side effects:
1. If a controller is not being polled (e.g. GameCube controllers in
Wii games that don't use them), its mappings will not be considered.
2. Once sensor input is implemented in the Android input backend,
we will be able to use this "polled recently" tracking to power down
the sensors at times when the game is using a Wii Remote reporting
mode that doesn't include motion data. (Assuming that the sensor
inputs only are mapped to Wii Remote motion controls, that is.)
Android doesn't let us poll inputs whenever we want. Instead, we
listen to input events (activities will have to forward them to the
input backend), and store the received values in atomic variables
in the Input classes. This is similar in concept to how ButtonManager
worked, but without its homegrown second input mapping system.
ButtonManager is very different from how a normal input backend works,
and is making it hard for us to improve controller support on Android.
The following commits will add a new input backend in its place.
When that setting is enabled, m_xfb_entry is initially not present (during the phase where a shader compilation progress bar would be shown). The main path checks for m_xfb_entry, but the software renderer fallback path didn't.
Fixes another aspect of https://bugs.dolphin-emu.org/issues/13172.
Before, it used a fallback where it returned a default object, where the width and height were set to 0. Presenter::Initialize() used GetSurfaceInfo to set the backbuffer size, then used that size when initializing the on-screen UI (even for the software renderer, where the on-screen UI isn't currently present), which meant that ImGui got a window size of 0 and thus resulted in a failed assertion.
Although BindBackbuffer checks for size changes, it doesn't help because ImGui has already been initialized, and the size hasn't actually changed since initialization occured.
Fixes one aspect of https://bugs.dolphin-emu.org/issues/13172.