@@ -83,6 +83,9 @@ import androidx.compose.ui.tooling.preview.Preview
8383import app.gamenative.BuildConfig
8484import app.gamenative.R
8585import app.gamenative.ui.util.SnackbarManager
86+ import app.gamenative.ui.util.deviceNativeResolution
87+ import app.gamenative.ui.util.evenRound
88+ import app.gamenative.ui.util.generateAdaptiveScreenSizes
8689import app.gamenative.ui.component.dialog.state.MessageDialogState
8790import app.gamenative.ui.component.settings.SettingsCPUList
8891import app.gamenative.ui.component.settings.SettingsCenteredLabel
@@ -130,7 +133,6 @@ import kotlinx.coroutines.launch
130133import kotlinx.coroutines.withContext
131134import java.io.File
132135import java.util.Locale
133- import kotlin.math.roundToInt
134136
135137/* *
136138 * Gets the component title for Win Components settings group.
@@ -152,42 +154,6 @@ internal fun winComponentsItemTitleRes(string: String): Int {
152154 }
153155}
154156
155- /* *
156- * Rounds a float value to the nearest even integer.
157- * This is required by many mobile GPU drivers to avoid rendering artifacts or crashes
158- * when using resolutions that are not divisible by 2.
159- *
160- * @param value The float value to be rounded.
161- * @return The nearest even integer to the input value.
162- */
163- internal fun evenRound (value : Float ): Int = (value / 2.0f ).roundToInt() * 2
164-
165- /* *
166- * Calculates the greatest common divisor (GCD) of two integers using the Euclidean algorithm.
167- *
168- * @param a The first integer.
169- * @param b The second integer.
170- * @return The greatest common divisor of a and b.
171- */
172- internal fun gcd (a : Int , b : Int ): Int = if (b == 0 ) a else gcd(b, a % b)
173-
174- /* *
175- * Calculates and formats the aspect ratio for a given resolution.
176- * Handles special cases for common mobile aspect ratios like 19.5:9 and 21.5:9.
177- *
178- * @param width The width of the resolution in pixels.
179- * @param height The height of the resolution in pixels.
180- * @return A string representation of the aspect ratio (e.g., "16:9" or "19.5:9").
181- */
182- internal fun calculateAspectRatio (width : Int , height : Int ): String {
183- val common = gcd(width, height)
184- val w = width / common
185- val h = height / common
186- if ((w == 13 ) && (h == 6 )) return " 19.5:9"
187- if ((w == 43 ) && (h == 18 )) return " 21.5:9"
188- return " $w :$h "
189- }
190-
191157private data class ContainerConfigDialogStaticData (
192158 val screenSizes : List <String >,
193159 val baseGraphicsDrivers : List <String >,
@@ -252,38 +218,22 @@ private fun rememberContainerConfigDialogStaticData(): ContainerConfigDialogStat
252218 }
253219 }
254220
255- val displayMetrics = context.resources.displayMetrics
256- val screenWidth = maxOf(displayMetrics.widthPixels, displayMetrics.heightPixels).toFloat()
257- val screenHeight = minOf(displayMetrics.widthPixels, displayMetrics.heightPixels).toFloat()
258-
259- val nativeWidth = evenRound(screenWidth)
260- val nativeHeight = evenRound(screenHeight)
261- val nativeRes = " ${nativeWidth} x$nativeHeight "
262- val nativeRatio = calculateAspectRatio(nativeWidth, nativeHeight)
263-
264- val optimizedWidth = evenRound(screenWidth * 0.75f )
265- val optimizedHeight = evenRound(screenHeight * 0.75f )
266- val optimizedRes = " ${optimizedWidth} x$optimizedHeight "
267- val optimizedRatio = calculateAspectRatio(optimizedWidth, optimizedHeight)
268-
269- val halfWidth = evenRound(screenWidth * 0.5f )
270- val halfHeight = evenRound(screenHeight * 0.5f )
271- val halfRes = " ${halfWidth} x$halfHeight "
272- val halfRatio = calculateAspectRatio(halfWidth, halfHeight)
221+ // Heavy non-composable loads are remembered so a configuration change (which
222+ // re-runs this whole function via LocalConfiguration) does not repeat them.
223+ val gpuCards = remember { ContainerUtils .getGPUCards(context) }
224+ val box64Presets = remember { Box86_64PresetManager .getPresets(" box64" , context) }
225+ val fexcorePresets = remember { FEXCorePresetManager .getPresets(context) }
273226
274227 val baseScreenSizes = stringArrayResource(R .array.screen_size_entries).toList()
275- val adaptiveScreenSizes = mutableListOf<String >()
276-
277- // Add device specific resolutions if they don't exactly match existing presets
278- listOf (
279- Triple (nativeRes, nativeRatio, context.getString(R .string.resolution_native)),
280- Triple (optimizedRes, optimizedRatio, context.getString(R .string.resolution_optimized)),
281- Triple (halfRes, halfRatio, context.getString(R .string.resolution_half)),
282- ).forEach { (res, ratio, label) ->
283- if (baseScreenSizes.none { it.startsWith(res) }) {
284- adaptiveScreenSizes.add(" $res ($ratio , $label )" )
285- }
286- }
228+ val (deviceWidth, deviceHeight) = deviceNativeResolution(context)
229+ val adaptiveScreenSizes = generateAdaptiveScreenSizes(
230+ deviceWidth = deviceWidth,
231+ deviceHeight = deviceHeight,
232+ baseScreenSizes = baseScreenSizes,
233+ nativeLabel = stringResource(R .string.resolution_native),
234+ optimizedLabel = stringResource(R .string.resolution_optimized),
235+ halfLabel = stringResource(R .string.resolution_half),
236+ )
287237
288238 return ContainerConfigDialogStaticData (
289239 screenSizes = baseScreenSizes + adaptiveScreenSizes,
@@ -293,7 +243,7 @@ private fun rememberContainerConfigDialogStaticData(): ContainerConfigDialogStat
293243 dxvkVersionsBase = stringArrayResource(R .array.dxvk_version_entries).toList(),
294244 vkd3dVersionsBase = stringArrayResource(R .array.vkd3d_version_entries).toList(),
295245 audioDrivers = stringArrayResource(R .array.audio_driver_entries).toList(),
296- gpuCards = ContainerUtils .getGPUCards(context) ,
246+ gpuCards = gpuCards ,
297247 presentModes = stringArrayResource(R .array.present_mode_entries).toList(),
298248 rendererPresentModes = listOf (" fifo" , " mailbox" ),
299249 resourceTypes = stringArrayResource(R .array.resource_type_entries).toList(),
@@ -314,9 +264,9 @@ private fun rememberContainerConfigDialogStaticData(): ContainerConfigDialogStat
314264 box64Versions = stringArrayResource(R .array.box64_version_entries).toList(),
315265 wowBox64VersionsBase = stringArrayResource(R .array.wowbox64_version_entries).toList(),
316266 box64BionicVersionsBase = stringArrayResource(R .array.box64_bionic_version_entries).toList(),
317- box64Presets = Box86_64PresetManager .getPresets( " box64 " , context) ,
267+ box64Presets = box64Presets ,
318268 fexcoreVersionsBase = stringArrayResource(R .array.fexcore_version_entries).toList(),
319- fexcorePresets = FEXCorePresetManager .getPresets(context) ,
269+ fexcorePresets = fexcorePresets ,
320270 fexcoreTSOPresets = stringArrayResource(R .array.fexcore_preset_entries).toList(),
321271 fexcoreX87Presets = stringArrayResource(R .array.x87mode_preset_entries).toList(),
322272 fexcoreMultiblockValues = stringArrayResource(R .array.multiblock_values).toList(),
@@ -838,19 +788,19 @@ fun ContainerConfigDialog(
838788 }
839789
840790 val screenSizeIndexRef = rememberSaveable {
841- val searchIndex = screenSizes.indexOfFirst { it.contains( config.screenSize) }
791+ val searchIndex = screenSizes.indexOfFirst { it.substringBefore( ' ' ) == config.screenSize }
842792 mutableIntStateOf(if (searchIndex > 0 ) searchIndex else 0 )
843793 }
844794 var screenSizeIndex by screenSizeIndexRef
845795 val customScreenWidthRef = rememberSaveable {
846- val searchIndex = screenSizes.indexOfFirst { it.contains( config.screenSize) }
796+ val searchIndex = screenSizes.indexOfFirst { it.substringBefore( ' ' ) == config.screenSize }
847797 mutableStateOf(
848798 if (searchIndex <= 0 ) config.screenSize.split(" x" ).getOrElse(0 ) { " 1280" } else " 1280"
849799 )
850800 }
851801 var customScreenWidth by customScreenWidthRef
852802 val customScreenHeightRef = rememberSaveable {
853- val searchIndex = screenSizes.indexOfFirst { it.contains( config.screenSize) }
803+ val searchIndex = screenSizes.indexOfFirst { it.substringBefore( ' ' ) == config.screenSize }
854804 mutableStateOf(
855805 if (searchIndex <= 0 ) config.screenSize.split(" x" ).getOrElse(1 ) { " 720" } else " 720"
856806 )
@@ -1112,15 +1062,15 @@ fun ContainerConfigDialog(
11121062
11131063 val applyScreenSizeToConfig: () -> Unit = {
11141064 val screenSize = if (screenSizeIndex == 0 ) {
1115- val widthInt = customScreenWidth.toIntOrNull() ? : 0
1116- val heightInt = customScreenHeight.toIntOrNull() ? : 0
1117- if (widthInt != 0 && heightInt != 0 ) {
1118- " ${evenRound(widthInt.toFloat()) } x${evenRound(heightInt.toFloat())} "
1065+ val width = evenRound(( customScreenWidth.toIntOrNull() ? : 0 ).toFloat())
1066+ val height = evenRound(( customScreenHeight.toIntOrNull() ? : 0 ).toFloat())
1067+ if (width > 0 && height > 0 ) {
1068+ " ${width } x$height "
11191069 } else {
11201070 config.screenSize
11211071 }
11221072 } else {
1123- screenSizes[screenSizeIndex].split(" " )[0 ]
1073+ screenSizes[screenSizeIndex.coerceIn( 1 , screenSizes.lastIndex) ].split(" " )[0 ]
11241074 }
11251075 config = config.copy(screenSize = screenSize)
11261076 }
0 commit comments