Merge branch 'libryujinx_bionic_threaded-Rendering' into 'libryujinx_bionic'

added an option to disable threaded rendering

See merge request kenji-nx/ryujinx!14
This commit is contained in:
BeZide 2025-12-08 23:44:29 -06:00
commit b3f0e9819e
4 changed files with 164 additions and 3 deletions

View file

@ -6,6 +6,7 @@ import com.sun.jna.Native
import org.kenjinx.android.viewmodels.GameInfo
import java.util.Collections
import android.view.Surface
import android.util.Log
interface KenjinxNativeJna : Library {
fun deviceInitialize(
@ -69,6 +70,14 @@ interface KenjinxNativeJna : Library {
fun deviceCloseEmulation()
fun deviceReinitEmulation()
fun deviceSignalEmulationClose()
// >>> Rendering-bezogene Ergänzungen für den Toggle:
fun deviceWaitForGpuDone(timeoutMs: Int)
fun deviceRecreateSwapchain()
fun graphicsSetBackendThreading(mode: Int)
fun graphicsSetPresentEnabled(enabled: Boolean)
// <<<
fun userGetOpenedUser(): String
fun userGetUserPicture(userId: String): String
fun userSetUserPicture(userId: String, picture: String)
@ -108,6 +117,104 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
loggingSetEnabled(logLevel.ordinal, enabled)
// --- Rendering: Single-Thread-Option & sichere Wrapper --------------------
// 0 = Auto, 1 = SingleThread (Disable Threaded), 2 = Threaded
private const val THREADING_AUTO = 0
private const val THREADING_SINGLE = 1
private const val THREADING_THREADED = 2
override fun graphicsSetBackendThreading(mode: Int) {
try {
jnaInstance.graphicsSetBackendThreading(mode)
} catch (_: Throwable) {
Log.w("KenjinxNative", "graphicsSetBackendThreading not available")
}
}
override fun deviceRecreateSwapchain() {
try { jnaInstance.deviceRecreateSwapchain() } catch (_: Throwable) { /* ignore */ }
}
override fun deviceWaitForGpuDone(timeoutMs: Int) {
try { jnaInstance.deviceWaitForGpuDone(timeoutMs) } catch (_: Throwable) { /* ignore */ }
}
override fun graphicsSetPresentEnabled(enabled: Boolean) {
try { jnaInstance.graphicsSetPresentEnabled(enabled) } catch (_: Throwable) { /* ignore */ }
}
// Sichere deviceResize-Implementierung (reines Rendering)
override fun deviceResize(width: Int, height: Int) {
try {
graphicsRendererSetSize(width, height)
inputSetClientSize(width, height)
} catch (_: Throwable) { /* ignore */ }
}
// Robustes graphicsInitialize mit QCOM-Heuristik + Fallback → SingleThread
override fun graphicsInitialize(
rescale: Float,
maxAnisotropy: Float,
fastGpuTime: Boolean,
fast2DCopy: Boolean,
enableMacroJit: Boolean,
enableMacroHLE: Boolean,
enableShaderCache: Boolean,
enableTextureRecompression: Boolean,
backendThreading: Int
): Boolean {
val requested = backendThreading
val isQcom = "qcom".equals(android.os.Build.HARDWARE, true)
// Heuristik: Auf QCOM bei „Auto“ zunächst SingleThread probieren,
// explizit gesetzte Werte bleiben unberührt.
val firstChoice =
if (isQcom && requested == THREADING_AUTO) THREADING_SINGLE else requested
Log.i(
"KenjinxNative",
"graphicsInitialize: request=$requested firstChoice=$firstChoice hw=${android.os.Build.HARDWARE}"
)
return try {
jnaInstance.graphicsInitialize(
rescale,
maxAnisotropy,
fastGpuTime,
fast2DCopy,
enableMacroJit,
enableMacroHLE,
enableShaderCache,
enableTextureRecompression,
firstChoice
)
} catch (t: Throwable) {
Log.e(
"KenjinxNative",
"graphicsInitialize failed (firstChoice=$firstChoice). Fallback → SingleThread",
t
)
try {
jnaInstance.graphicsInitialize(
rescale,
maxAnisotropy,
fastGpuTime,
fast2DCopy,
enableMacroJit,
enableMacroHLE,
enableShaderCache,
enableTextureRecompression,
THREADING_SINGLE
)
} catch (t2: Throwable) {
Log.e("KenjinxNative", "graphicsInitialize fallback failed", t2)
false
}
}
}
// -------------------------------------------------------------------------
@JvmStatic
fun frameEnded() = MainActivity.frameEnded()
@ -124,6 +231,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
val text = NativeHelpers.instance.getStringJava(infoPtr)
MainActivity.mainViewModel?.gameHost?.setProgress(text, progress)
}
@JvmStatic
fun onSurfaceSizeChanged(width: Int, height: Int) {
// No-Op: Placeholder Hook if needed.

View file

@ -117,13 +117,16 @@ class MainViewModel(val activity: MainActivity) {
settings.overrideSettings(forceNceAndPptc)
}
// 0=Auto, 1=SingleThread, 2=Threaded
val backendMode = if (settings.disableThreadedRendering) 1 else 2
var success = KenjinxNative.graphicsInitialize(
enableMacroHLE = settings.enableMacroHLE,
enableShaderCache = settings.enableShaderCache,
enableTextureRecompression = settings.enableTextureRecompression,
rescale = settings.resScale,
maxAnisotropy = settings.maxAnisotropy,
backendThreading = org.kenjinx.android.BackendThreading.Auto.ordinal
backendThreading = backendMode
)
if (!success)
@ -227,13 +230,16 @@ class MainViewModel(val activity: MainActivity) {
val settings = QuickSettings(activity)
// 0=Auto, 1=SingleThread, 2=Threaded
val backendMode = if (settings.disableThreadedRendering) 1 else 2
var success = KenjinxNative.graphicsInitialize(
enableMacroHLE = settings.enableMacroHLE,
enableShaderCache = settings.enableShaderCache,
enableTextureRecompression = settings.enableTextureRecompression,
rescale = settings.resScale,
maxAnisotropy = settings.maxAnisotropy,
backendThreading = org.kenjinx.android.BackendThreading.Auto.ordinal
backendThreading = backendMode
)
if (!success)

View file

@ -63,6 +63,9 @@ class QuickSettings(val activity: Activity) {
var enableDebugLogs: Boolean
var enableGraphicsLogs: Boolean
// --- NEU: Threaded Rendering Toggle (persistiert)
var disableThreadedRendering: Boolean
private var sharedPref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
init {
@ -108,6 +111,9 @@ class QuickSettings(val activity: Activity) {
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
enableGraphicsLogs = sharedPref.getBoolean("enableGraphicsLogs", false)
// --- NEU laden
disableThreadedRendering = sharedPref.getBoolean("disableThreadedRendering", false)
}
fun save() {
@ -151,6 +157,9 @@ class QuickSettings(val activity: Activity) {
putBoolean("enableTraceLogs", enableTraceLogs)
putBoolean("enableDebugLogs", enableDebugLogs)
putBoolean("enableGraphicsLogs", enableGraphicsLogs)
// --- NEU speichern
putBoolean("disableThreadedRendering", disableThreadedRendering)
}
}

View file

@ -47,6 +47,7 @@ import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
@ -70,8 +71,8 @@ import org.kenjinx.android.viewmodels.DataResetState
import org.kenjinx.android.viewmodels.FirmwareInstallState
import org.kenjinx.android.viewmodels.KeyInstallState
import org.kenjinx.android.viewmodels.MainViewModel
import org.kenjinx.android.viewmodels.MemoryConfiguration
import org.kenjinx.android.viewmodels.SettingsViewModel
import org.kenjinx.android.viewmodels.MemoryConfiguration
import org.kenjinx.android.viewmodels.MemoryManagerMode
import org.kenjinx.android.viewmodels.VSyncMode
import org.kenjinx.android.widgets.ActionButton
@ -89,6 +90,9 @@ import org.kenjinx.android.viewmodels.QuickSettings.OverlayMenuPosition // ← N
import org.kenjinx.android.SystemLanguage
import org.kenjinx.android.RegionCode
// >>> NEU: KenjinxNative für das Live-Umschalten des Threading-Backends
import org.kenjinx.android.KenjinxNative
class SettingViews {
companion object {
const val EXPANSTION_TRANSITION_DURATION = 450
@ -159,6 +163,12 @@ class SettingViews {
mutableFloatStateOf(QuickSettings(mainViewModel.activity).overlayMenuOpacity.coerceIn(0f, 1f))
}
// --- NEU: Disable Threaded Rendering (aus QuickSettings laden)
val disableThreadedRendering = remember {
mutableStateOf(QuickSettings(mainViewModel.activity).disableThreadedRendering)
}
val threadToggleInitialized = remember { mutableStateOf(false) }
if (!loaded.value) {
settingsViewModel.initializeState(
memoryManagerMode,
@ -1321,6 +1331,34 @@ class SettingViews {
enableShaderCache.SwitchSelector(label = "Shader Cache")
enableTextureRecompression.SwitchSelector(label = "Texture Recompression")
enableMacroHLE.SwitchSelector(label = "Macro HLE")
// --- NEU: Toggle für Single-Thread-Renderer
disableThreadedRendering.SwitchSelector(label = "Disable Threaded Rendering")
// Reaktion auf Toggle: persistieren + sanftes Reconfigure
LaunchedEffect(disableThreadedRendering.value) {
if (!threadToggleInitialized.value) {
threadToggleInitialized.value = true
} else {
val qs = QuickSettings(mainViewModel.activity)
qs.disableThreadedRendering = disableThreadedRendering.value
qs.save()
val mode = if (disableThreadedRendering.value) 1 /*Single*/ else 2 /*Threaded*/
thread {
try {
KenjinxNative.graphicsSetPresentEnabled(false)
KenjinxNative.deviceWaitForGpuDone(500)
KenjinxNative.graphicsSetBackendThreading(mode)
KenjinxNative.deviceRecreateSwapchain()
} finally {
KenjinxNative.graphicsSetPresentEnabled(true)
}
}
}
}
stretchToFullscreen.SwitchSelector(label = "Stretch to Fullscreen")
ResolutionScaleDropdown(
selectedScale = resScale.floatValue,