Compare commits

...
2 Commits
Author SHA1 Message Date
KeatonTheBotandLotP 3f62488b26 SDL: Update game controller database on launch (#177)
Expands upon existing custom SDL mappings functionality: b82e789d4f

Downloads an updated game controller database (gamecontrollerdb.txt) on launch, which only updates when a new file is available. This keeps the database updated between SDL releases.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/177
2026-07-30 21:18:39 +00:00
MabelandLotP e3940abe01 Threaded Renderer Crash, Threaded Renderer Index Desync, Logger Disposal (#174)
These 3 are all fixes made by LotP, who said they just didn't feel like making the PR atm and that someone else could do it if they wanted to (https://discord.com/channels/1294443224030511104/1295891559056674816/1531034369232211968)

Addresses these 3 specific issues:
1. Toggling the hidden console tries to assign a new console logger, which is also done on setting initial state, but at that point a logger already exists so it just returns, except previously it did not dispose of the new logger.
2. The threaded renderer would sometimes just crash when emulation is stopped, the fix being to make sure the backend render thread is joined before touching common objects
3. The disposing workflow of other threads than the main GPU adds commands to the command queue, causing a problem where the index can get desynced because of race conditions

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/174
2026-07-27 20:03:45 +00:00
3 changed files with 50 additions and 4 deletions
+1
View File
@@ -162,6 +162,7 @@ namespace Ryujinx.Common.Logging
{
if (_logTargets.Any(t => t.Name == target.Name))
{
target.Dispose();
return;
}
@@ -195,11 +195,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading
{
// The reference table is sized so that it will never overflow, so long as the references are taken after the command is allocated.
int index = _refProducerPtr;
// make sure increment is thread safe
int index = Interlocked.Increment(ref _refProducerPtr) - 1;
index %= _refQueue.Length;
_refQueue[index] = obj;
_refProducerPtr = (_refProducerPtr + 1) % _refQueue.Length;
_refProducerPtr %= _refQueue.Length;
return index;
}
@@ -531,10 +534,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_running = false;
_galWorkAvailable.Set();
if (_gpuThread != null && _gpuThread.IsAlive)
if (_gpuThread is { IsAlive: true })
{
_gpuThread.Join();
}
if (_backendThread is { IsAlive: true })
{
_backendThread.Join();
}
// Dispose the renderer.
_baseRenderer.Dispose();
+38 -1
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using SDL;
using static SDL.SDL3;
@@ -43,6 +44,9 @@ namespace Ryujinx.SDL3.Common
private SDL3Driver() { }
private static readonly HttpClient _httpClient = new();
private const string GamepadDbUrl = "https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt";
public void Initialize()
{
lock (_lock)
@@ -96,8 +100,10 @@ namespace Ryujinx.SDL3.Common
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_GAMEPAD_SENSOR_UPDATE, false);
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "SDL_GameControllerDB.txt");
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "gamecontrollerdb.txt");
UpdateGamepadDb(gamepadDbPath);
if (File.Exists(gamepadDbPath))
{
SDL_AddGamepadMappingsFromFile(gamepadDbPath);
@@ -110,6 +116,37 @@ namespace Ryujinx.SDL3.Common
}
}
private static void UpdateGamepadDb(string gamepadDbPath)
{
try
{
byte[] remoteBytes = _httpClient.GetByteArrayAsync(GamepadDbUrl).GetAwaiter().GetResult();
bool shouldWrite = true;
if (File.Exists(gamepadDbPath))
{
byte[] localBytes = File.ReadAllBytes(gamepadDbPath);
if (localBytes.AsSpan().SequenceEqual(remoteBytes))
{
shouldWrite = false;
}
}
if (shouldWrite)
{
File.WriteAllBytes(gamepadDbPath ?? "", remoteBytes);
Logger.Info?.Print(LogClass.Application, "Updated gamepad database.");
}
}
catch (Exception ex)
{
Logger.Warning?.Print(LogClass.Application, $"Failed to check/download gamepad database, using existing local copy if present: {ex.Message}");
}
}
public bool RegisterWindow(SDL_WindowID windowId, Action<SDL_Event> windowEventHandler)
{
return _registeredWindowHandlers.TryAdd(windowId, windowEventHandler);