mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-14 16:37:07 +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 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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue