added stretch to fullscreen

This commit is contained in:
BeZide93 2025-09-28 02:43:54 -05:00 committed by KeatonTheBot
parent 327416c967
commit fa5b5b127e
7 changed files with 70 additions and 12 deletions

View file

@ -137,6 +137,10 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
} }
} catch (_: Throwable) {} } catch (_: Throwable) {}
val qs = org.kenjinx.android.viewmodels.QuickSettings(mainViewModel.activity)
try {
KenjinxNative.graphicsSetFullscreenStretch(qs.stretchToFullscreen)
} catch (_: Throwable) {}
_guestThread = thread(start = true, name = "KenjinxGuest") { _guestThread = thread(start = true, name = "KenjinxGuest") {
runGame() runGame()
} }
@ -280,6 +284,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
// If rotation is known: Force plausibility (Landscape ↔ Portrait) // If rotation is known: Force plausibility (Landscape ↔ Portrait)
expectedRotation?.let { rot -> expectedRotation?.let { rot ->
// ROTATION_90 (1) / ROTATION_270 (3) => Landscape
val landscape = (rot == 1 || rot == 3) val landscape = (rot == 1 || rot == 3)
if (landscape && h > w) { if (landscape && h > w) {
val t = w; w = h; h = t val t = w; w = h; h = t

View file

@ -53,6 +53,7 @@ interface KenjinxNativeJna : Library {
fun graphicsRendererSetSize(width: Int, height: Int) fun graphicsRendererSetSize(width: Int, height: Int)
fun graphicsRendererSetVsync(vSyncMode: Int) fun graphicsRendererSetVsync(vSyncMode: Int)
fun graphicsRendererRunLoop() fun graphicsRendererRunLoop()
fun graphicsSetFullscreenStretch(enable: Boolean)
fun deviceReloadFilesystem() fun deviceReloadFilesystem()
fun inputInitialize(width: Int, height: Int) fun inputInitialize(width: Int, height: Int)
fun inputSetClientSize(width: Int, height: Int) fun inputSetClientSize(width: Int, height: Int)
@ -119,10 +120,10 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
@JvmStatic @JvmStatic
fun updateProgress(infoPtr: Long, progress: Float) { fun updateProgress(infoPtr: Long, progress: Float) {
// Get string from native pointer and push into progress overlay
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.
@ -187,6 +188,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
/** /**
* Variant B (strings directly). Used by newer JNI/interop paths. * Variant B (strings directly). Used by newer JNI/interop paths.
* Signature exactly matches the C# call in AndroidUIHandler.cs / Interop.UpdateUiHandler(...).
*/ */
@JvmStatic @JvmStatic
fun uiHandlerUpdate( fun uiHandlerUpdate(

View file

@ -36,6 +36,7 @@ class QuickSettings(val activity: Activity) {
var enableShaderCache: Boolean var enableShaderCache: Boolean
var enableTextureRecompression: Boolean var enableTextureRecompression: Boolean
var enableMacroHLE: Boolean var enableMacroHLE: Boolean
var stretchToFullscreen: Boolean
var resScale: Float var resScale: Float
var maxAnisotropy: Float var maxAnisotropy: Float
var isGrid: Boolean var isGrid: Boolean
@ -74,6 +75,7 @@ class QuickSettings(val activity: Activity) {
enableShaderCache = sharedPref.getBoolean("enableShaderCache", true) enableShaderCache = sharedPref.getBoolean("enableShaderCache", true)
enableTextureRecompression = sharedPref.getBoolean("enableTextureRecompression", false) enableTextureRecompression = sharedPref.getBoolean("enableTextureRecompression", false)
enableMacroHLE = sharedPref.getBoolean("enableMacroHLE", true) enableMacroHLE = sharedPref.getBoolean("enableMacroHLE", true)
stretchToFullscreen = sharedPref.getBoolean("stretchToFullscreen", false)
resScale = sharedPref.getFloat("resScale", 1f) resScale = sharedPref.getFloat("resScale", 1f)
maxAnisotropy = sharedPref.getFloat("maxAnisotropy", 0f) maxAnisotropy = sharedPref.getFloat("maxAnisotropy", 0f)
useVirtualController = sharedPref.getBoolean("useVirtualController", true) useVirtualController = sharedPref.getBoolean("useVirtualController", true)
@ -112,6 +114,7 @@ class QuickSettings(val activity: Activity) {
putBoolean("enableShaderCache", enableShaderCache) putBoolean("enableShaderCache", enableShaderCache)
putBoolean("enableTextureRecompression", enableTextureRecompression) putBoolean("enableTextureRecompression", enableTextureRecompression)
putBoolean("enableMacroHLE", enableMacroHLE) putBoolean("enableMacroHLE", enableMacroHLE)
putBoolean("stretchToFullscreen", stretchToFullscreen)
putFloat("resScale", resScale) putFloat("resScale", resScale)
putFloat("maxAnisotropy", maxAnisotropy) putFloat("maxAnisotropy", maxAnisotropy)
putBoolean("useVirtualController", useVirtualController) putBoolean("useVirtualController", useVirtualController)

View file

@ -57,6 +57,7 @@ class SettingsViewModel(val activity: MainActivity) {
enableShaderCache: MutableState<Boolean>, enableShaderCache: MutableState<Boolean>,
enableTextureRecompression: MutableState<Boolean>, enableTextureRecompression: MutableState<Boolean>,
enableMacroHLE: MutableState<Boolean>, enableMacroHLE: MutableState<Boolean>,
stretchToFullscreen: MutableState<Boolean>,
resScale: MutableState<Float>, resScale: MutableState<Float>,
maxAnisotropy: MutableState<Float>, maxAnisotropy: MutableState<Float>,
useVirtualController: MutableState<Boolean>, useVirtualController: MutableState<Boolean>,
@ -91,6 +92,7 @@ class SettingsViewModel(val activity: MainActivity) {
enableShaderCache.value = sharedPref.getBoolean("enableShaderCache", true) enableShaderCache.value = sharedPref.getBoolean("enableShaderCache", true)
enableTextureRecompression.value = sharedPref.getBoolean("enableTextureRecompression", false) enableTextureRecompression.value = sharedPref.getBoolean("enableTextureRecompression", false)
enableMacroHLE.value = sharedPref.getBoolean("enableMacroHLE", false) enableMacroHLE.value = sharedPref.getBoolean("enableMacroHLE", false)
stretchToFullscreen.value = sharedPref.getBoolean("stretchToFullscreen", false)
resScale.value = sharedPref.getFloat("resScale", 1f) resScale.value = sharedPref.getFloat("resScale", 1f)
maxAnisotropy.value = sharedPref.getFloat("maxAnisotropy", 0f) maxAnisotropy.value = sharedPref.getFloat("maxAnisotropy", 0f)
useVirtualController.value = sharedPref.getBoolean("useVirtualController", true) useVirtualController.value = sharedPref.getBoolean("useVirtualController", true)
@ -131,6 +133,7 @@ class SettingsViewModel(val activity: MainActivity) {
enableShaderCache: MutableState<Boolean>, enableShaderCache: MutableState<Boolean>,
enableTextureRecompression: MutableState<Boolean>, enableTextureRecompression: MutableState<Boolean>,
enableMacroHLE: MutableState<Boolean>, enableMacroHLE: MutableState<Boolean>,
stretchToFullscreen: MutableState<Boolean>,
resScale: MutableState<Float>, resScale: MutableState<Float>,
maxAnisotropy: MutableState<Float>, maxAnisotropy: MutableState<Float>,
useVirtualController: MutableState<Boolean>, useVirtualController: MutableState<Boolean>,
@ -167,6 +170,7 @@ class SettingsViewModel(val activity: MainActivity) {
putBoolean("enableShaderCache", enableShaderCache.value) putBoolean("enableShaderCache", enableShaderCache.value)
putBoolean("enableTextureRecompression", enableTextureRecompression.value) putBoolean("enableTextureRecompression", enableTextureRecompression.value)
putBoolean("enableMacroHLE", enableMacroHLE.value) putBoolean("enableMacroHLE", enableMacroHLE.value)
putBoolean("stretchToFullscreen", stretchToFullscreen.value)
putFloat("resScale", resScale.value) putFloat("resScale", resScale.value)
putFloat("maxAnisotropy", maxAnisotropy.value) putFloat("maxAnisotropy", maxAnisotropy.value)
putBoolean("useVirtualController", useVirtualController.value) putBoolean("useVirtualController", useVirtualController.value)

View file

@ -111,6 +111,7 @@ class SettingViews {
val enableShaderCache = remember { mutableStateOf(false) } val enableShaderCache = remember { mutableStateOf(false) }
val enableTextureRecompression = remember { mutableStateOf(false) } val enableTextureRecompression = remember { mutableStateOf(false) }
val enableMacroHLE = remember { mutableStateOf(false) } val enableMacroHLE = remember { mutableStateOf(false) }
val stretchToFullscreen = remember { mutableStateOf(false) }
val resScale = remember { mutableFloatStateOf(1f) } val resScale = remember { mutableFloatStateOf(1f) }
val maxAnisotropy = remember { mutableFloatStateOf(0f) } val maxAnisotropy = remember { mutableFloatStateOf(0f) }
val useVirtualController = remember { mutableStateOf(true) } val useVirtualController = remember { mutableStateOf(true) }
@ -165,6 +166,7 @@ class SettingViews {
enableShaderCache, enableShaderCache,
enableTextureRecompression, enableTextureRecompression,
enableMacroHLE, enableMacroHLE,
stretchToFullscreen,
resScale, resScale,
maxAnisotropy, maxAnisotropy,
useVirtualController, useVirtualController,
@ -210,6 +212,7 @@ class SettingViews {
enableShaderCache, enableShaderCache,
enableTextureRecompression, enableTextureRecompression,
enableMacroHLE, enableMacroHLE,
stretchToFullscreen,
resScale, resScale,
maxAnisotropy, maxAnisotropy,
useVirtualController, useVirtualController,
@ -259,6 +262,7 @@ class SettingViews {
selectedOrientation = orientationPref.value, selectedOrientation = orientationPref.value,
onOrientationSelected = { sel -> onOrientationSelected = { sel ->
orientationPref.value = sel orientationPref.value = sel
// Save and use immediately
val qs = QuickSettings(mainViewModel.activity) val qs = QuickSettings(mainViewModel.activity)
qs.orientationPreference = sel qs.orientationPreference = sel
qs.save() qs.save()
@ -1245,6 +1249,7 @@ 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")
stretchToFullscreen.SwitchSelector(label = "Stretch to Fullscreen")
ResolutionScaleDropdown( ResolutionScaleDropdown(
selectedScale = resScale.floatValue, selectedScale = resScale.floatValue,
onScaleSelected = { scale -> onScaleSelected = { scale ->

View file

@ -221,19 +221,29 @@ namespace LibKenjinx
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct GraphicsConfiguration public struct GraphicsConfiguration
{ {
public float ResScale = 1f; public float ResScale;
public float MaxAnisotropy = -1; public float MaxAnisotropy;
public bool FastGpuTime = true; public bool FastGpuTime;
public bool Fast2DCopy = true; public bool Fast2DCopy;
public bool EnableMacroJit = false; public bool EnableMacroJit;
public bool EnableMacroHLE = true; public bool EnableMacroHLE;
public bool EnableShaderCache = true; public bool EnableShaderCache;
public bool EnableTextureRecompression = false; public bool EnableTextureRecompression;
public BackendThreading BackendThreading = BackendThreading.Auto; public BackendThreading BackendThreading;
public AspectRatio AspectRatio = AspectRatio.Fixed16x9; public AspectRatio AspectRatio; // <- important
public GraphicsConfiguration() public GraphicsConfiguration()
{ {
ResScale = 1f;
MaxAnisotropy = -1;
FastGpuTime = true;
Fast2DCopy = true;
EnableMacroJit = false;
EnableMacroHLE = true;
EnableShaderCache = true;
EnableTextureRecompression = false;
BackendThreading = BackendThreading.Auto;
AspectRatio = AspectRatio.Fixed16x9;
} }
} }

View file

@ -132,7 +132,6 @@ namespace LibKenjinx
} }
List<string> extensions = []; List<string> extensions = [];
var size = Marshal.SizeOf<IntPtr>();
var extPtr = (IntPtr*)nativeGraphicsInterop.VkRequiredExtensions; var extPtr = (IntPtr*)nativeGraphicsInterop.VkRequiredExtensions;
for (int i = 0; i < nativeGraphicsInterop.VkRequiredExtensionsCount; i++) for (int i = 0; i < nativeGraphicsInterop.VkRequiredExtensionsCount; i++)
{ {
@ -274,6 +273,7 @@ namespace LibKenjinx
return stats; return stats;
} }
[UnmanagedCallersOnly(EntryPoint = "device_launch_mii_editor")] [UnmanagedCallersOnly(EntryPoint = "device_launch_mii_editor")]
public static bool LaunchMiiEditAppletNative() public static bool LaunchMiiEditAppletNative()
{ {
@ -468,5 +468,34 @@ namespace LibKenjinx
CloseUser(userId); CloseUser(userId);
} }
// ----------------------
// Stretch: Helper + Exports
// ----------------------
// central logic (managed)
private static void ApplyFullscreenStretch(bool enable)
{
var ar = enable ? AspectRatio.Stretched : AspectRatio.Fixed16x9;
// Retrieve, modify, write back struct
var cfg = GraphicsConfiguration;
cfg.AspectRatio = ar;
GraphicsConfiguration = cfg;
// Hot-Apply for running emulation
var dev = SwitchDevice?.EmulationContext;
if (dev != null)
{
try { dev.Configuration.AspectRatio = ar; } catch { }
}
}
// CamelCase Export (JNA calls it here)
[UnmanagedCallersOnly(EntryPoint = "graphicsSetFullscreenStretch")]
public static void GraphicsSetFullscreenStretchNativeAlias(bool enable)
{
ApplyFullscreenStretch(enable);
}
} }
} }