mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-18 01:37:04 +00:00
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:
commit
b3f0e9819e
4 changed files with 164 additions and 3 deletions
|
|
@ -6,6 +6,7 @@ import com.sun.jna.Native
|
||||||
import org.kenjinx.android.viewmodels.GameInfo
|
import org.kenjinx.android.viewmodels.GameInfo
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
interface KenjinxNativeJna : Library {
|
interface KenjinxNativeJna : Library {
|
||||||
fun deviceInitialize(
|
fun deviceInitialize(
|
||||||
|
|
@ -69,6 +70,14 @@ interface KenjinxNativeJna : Library {
|
||||||
fun deviceCloseEmulation()
|
fun deviceCloseEmulation()
|
||||||
fun deviceReinitEmulation()
|
fun deviceReinitEmulation()
|
||||||
fun deviceSignalEmulationClose()
|
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 userGetOpenedUser(): String
|
||||||
fun userGetUserPicture(userId: String): String
|
fun userGetUserPicture(userId: String): String
|
||||||
fun userSetUserPicture(userId: String, picture: String)
|
fun userSetUserPicture(userId: String, picture: String)
|
||||||
|
|
@ -108,6 +117,104 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
|
||||||
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
|
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
|
||||||
loggingSetEnabled(logLevel.ordinal, enabled)
|
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
|
@JvmStatic
|
||||||
fun frameEnded() = MainActivity.frameEnded()
|
fun frameEnded() = MainActivity.frameEnded()
|
||||||
|
|
||||||
|
|
@ -124,6 +231,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
|
||||||
val text = NativeHelpers.instance.getStringJava(infoPtr)
|
val text = NativeHelpers.instance.getStringJava(infoPtr)
|
||||||
MainActivity.mainViewModel?.gameHost?.setProgress(text, progress)
|
MainActivity.mainViewModel?.gameHost?.setProgress(text, progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onSurfaceSizeChanged(width: Int, height: Int) {
|
fun onSurfaceSizeChanged(width: Int, height: Int) {
|
||||||
// No-Op: Placeholder – Hook if needed.
|
// No-Op: Placeholder – Hook if needed.
|
||||||
|
|
|
||||||
|
|
@ -117,13 +117,16 @@ class MainViewModel(val activity: MainActivity) {
|
||||||
settings.overrideSettings(forceNceAndPptc)
|
settings.overrideSettings(forceNceAndPptc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0=Auto, 1=SingleThread, 2=Threaded
|
||||||
|
val backendMode = if (settings.disableThreadedRendering) 1 else 2
|
||||||
|
|
||||||
var success = KenjinxNative.graphicsInitialize(
|
var success = KenjinxNative.graphicsInitialize(
|
||||||
enableMacroHLE = settings.enableMacroHLE,
|
enableMacroHLE = settings.enableMacroHLE,
|
||||||
enableShaderCache = settings.enableShaderCache,
|
enableShaderCache = settings.enableShaderCache,
|
||||||
enableTextureRecompression = settings.enableTextureRecompression,
|
enableTextureRecompression = settings.enableTextureRecompression,
|
||||||
rescale = settings.resScale,
|
rescale = settings.resScale,
|
||||||
maxAnisotropy = settings.maxAnisotropy,
|
maxAnisotropy = settings.maxAnisotropy,
|
||||||
backendThreading = org.kenjinx.android.BackendThreading.Auto.ordinal
|
backendThreading = backendMode
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
|
|
@ -227,13 +230,16 @@ class MainViewModel(val activity: MainActivity) {
|
||||||
|
|
||||||
val settings = QuickSettings(activity)
|
val settings = QuickSettings(activity)
|
||||||
|
|
||||||
|
// 0=Auto, 1=SingleThread, 2=Threaded
|
||||||
|
val backendMode = if (settings.disableThreadedRendering) 1 else 2
|
||||||
|
|
||||||
var success = KenjinxNative.graphicsInitialize(
|
var success = KenjinxNative.graphicsInitialize(
|
||||||
enableMacroHLE = settings.enableMacroHLE,
|
enableMacroHLE = settings.enableMacroHLE,
|
||||||
enableShaderCache = settings.enableShaderCache,
|
enableShaderCache = settings.enableShaderCache,
|
||||||
enableTextureRecompression = settings.enableTextureRecompression,
|
enableTextureRecompression = settings.enableTextureRecompression,
|
||||||
rescale = settings.resScale,
|
rescale = settings.resScale,
|
||||||
maxAnisotropy = settings.maxAnisotropy,
|
maxAnisotropy = settings.maxAnisotropy,
|
||||||
backendThreading = org.kenjinx.android.BackendThreading.Auto.ordinal
|
backendThreading = backendMode
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@ class QuickSettings(val activity: Activity) {
|
||||||
var enableDebugLogs: Boolean
|
var enableDebugLogs: Boolean
|
||||||
var enableGraphicsLogs: Boolean
|
var enableGraphicsLogs: Boolean
|
||||||
|
|
||||||
|
// --- NEU: Threaded Rendering Toggle (persistiert)
|
||||||
|
var disableThreadedRendering: Boolean
|
||||||
|
|
||||||
private var sharedPref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
private var sharedPref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -108,6 +111,9 @@ class QuickSettings(val activity: Activity) {
|
||||||
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
|
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
|
||||||
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
|
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
|
||||||
enableGraphicsLogs = sharedPref.getBoolean("enableGraphicsLogs", false)
|
enableGraphicsLogs = sharedPref.getBoolean("enableGraphicsLogs", false)
|
||||||
|
|
||||||
|
// --- NEU laden
|
||||||
|
disableThreadedRendering = sharedPref.getBoolean("disableThreadedRendering", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
|
|
@ -151,6 +157,9 @@ class QuickSettings(val activity: Activity) {
|
||||||
putBoolean("enableTraceLogs", enableTraceLogs)
|
putBoolean("enableTraceLogs", enableTraceLogs)
|
||||||
putBoolean("enableDebugLogs", enableDebugLogs)
|
putBoolean("enableDebugLogs", enableDebugLogs)
|
||||||
putBoolean("enableGraphicsLogs", enableGraphicsLogs)
|
putBoolean("enableGraphicsLogs", enableGraphicsLogs)
|
||||||
|
|
||||||
|
// --- NEU speichern
|
||||||
|
putBoolean("disableThreadedRendering", disableThreadedRendering)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import androidx.compose.material3.Slider
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
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.FirmwareInstallState
|
||||||
import org.kenjinx.android.viewmodels.KeyInstallState
|
import org.kenjinx.android.viewmodels.KeyInstallState
|
||||||
import org.kenjinx.android.viewmodels.MainViewModel
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
import org.kenjinx.android.viewmodels.MemoryConfiguration
|
|
||||||
import org.kenjinx.android.viewmodels.SettingsViewModel
|
import org.kenjinx.android.viewmodels.SettingsViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.MemoryConfiguration
|
||||||
import org.kenjinx.android.viewmodels.MemoryManagerMode
|
import org.kenjinx.android.viewmodels.MemoryManagerMode
|
||||||
import org.kenjinx.android.viewmodels.VSyncMode
|
import org.kenjinx.android.viewmodels.VSyncMode
|
||||||
import org.kenjinx.android.widgets.ActionButton
|
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.SystemLanguage
|
||||||
import org.kenjinx.android.RegionCode
|
import org.kenjinx.android.RegionCode
|
||||||
|
|
||||||
|
// >>> NEU: KenjinxNative für das Live-Umschalten des Threading-Backends
|
||||||
|
import org.kenjinx.android.KenjinxNative
|
||||||
|
|
||||||
class SettingViews {
|
class SettingViews {
|
||||||
companion object {
|
companion object {
|
||||||
const val EXPANSTION_TRANSITION_DURATION = 450
|
const val EXPANSTION_TRANSITION_DURATION = 450
|
||||||
|
|
@ -159,6 +163,12 @@ class SettingViews {
|
||||||
mutableFloatStateOf(QuickSettings(mainViewModel.activity).overlayMenuOpacity.coerceIn(0f, 1f))
|
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) {
|
if (!loaded.value) {
|
||||||
settingsViewModel.initializeState(
|
settingsViewModel.initializeState(
|
||||||
memoryManagerMode,
|
memoryManagerMode,
|
||||||
|
|
@ -1321,6 +1331,34 @@ class SettingViews {
|
||||||
enableShaderCache.SwitchSelector(label = "Shader Cache")
|
enableShaderCache.SwitchSelector(label = "Shader Cache")
|
||||||
enableTextureRecompression.SwitchSelector(label = "Texture Recompression")
|
enableTextureRecompression.SwitchSelector(label = "Texture Recompression")
|
||||||
enableMacroHLE.SwitchSelector(label = "Macro HLE")
|
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")
|
stretchToFullscreen.SwitchSelector(label = "Stretch to Fullscreen")
|
||||||
ResolutionScaleDropdown(
|
ResolutionScaleDropdown(
|
||||||
selectedScale = resScale.floatValue,
|
selectedScale = resScale.floatValue,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue