This was causing the game to output thousands of FPS during the loading screen when it would run uncapped if Immediately Present XFB was enabled.
Please see Redmine 13447 for reference.
This is another one of those games that has an optional screenshot
feature where the images end up all black if you have Store EFB Copies
to Texture Only turned on. Like for other such games, let's not force
Store EFB Copies to Texture Only off, since it's a large performance
impact for a feature most players won't use.
There's one wrinkle here. As part of teaching the player how to take
screenshots, the game forces the player to take a screenshot before it
lets them progress in the story. However, the game doesn't care what's
in the screenshot, so you can progress just fine even if Store EFB
Copies to Texture Only is turned on. I personally tested it.
Use 1 of the same type as the stored value when shifting left. This
prevents undefined behavior caused by shifting an int more than 31 bits.
Previously iterator incrementation could either hang or prematurely
report it had reached the end of the bitset.
This fixes an issue where the game specific graphics backend would be saved as the global setting after playing a game.
This also now displays the currently running graphics backend when looking in the graphics configuration window.
Keep a shared_ptr to NetKDTimeDevice inside NetKDRequestDevice.
This allows the KDDownload task to finish its work without potentially
trying to dereference nullptr, which can potentially come from either
GetIOS() or GetDeviceByName() if EmulationKernel's destructor has
started running.
Explicitly shut down work queues in NetKDRequestDevice's destructor to
prevent their threads from accessing members after they've been freed.
This crash would occur sporadically if NetKDRequestDevice's periodic
download or mail checks happened to overlap with emulation shutdown in
the wrong way.
An example sequence of events that could cause the crash:
* m_scheduler_timer_thread queues a periodic Download event in
m_scheduler_work_queue, then waits for m_shutdown_event.
* A request to stop emulation results in s_ios being reset by the CPU
thread. This triggers NetKDRequestDevice's destructor which sets
m_shutdown_event and joins m_scheduler_timer_thread.
* m_scheduler_timer_thread wakes from m_shutdown_event and returns from
its thread function, ending the thread.
* The CPU thread resumes execution at the end of NetKDRequestDevice's
destructor and begins destroying NetKDRequestDevice's members in
reverse declaration order.
* m_http is declared after m_scheduler_work_queue and is therefore
destroyed earlier.
* m_scheduler_work_queue's destructor calls its Shutdown function, which
by default finishes the work items in the queue.
* The queued Download event calls KDDownload which calls m_http.Get()
which calls Fetch() which passes garbage data from the freed m_curl
into curl_easy_setopt().
* Curl promptly crashes.
Shutting down the work queues manually in the destructor prevents the
above because m_http and the other members don't get freed until after
the queue threads finish.