android: Force use of Vulkan if OpenGL renderer is ANGLE

This commit also renames the AndroidStorage namespace and related files to AndroidUtils, and merges `jni/utils.cpp`/`.h` into it.
This commit is contained in:
OpenSauce04
2026-06-10 23:05:21 +01:00
committed by OpenSauce
parent bd733284a3
commit 4687226fa5
41 changed files with 204 additions and 156 deletions
@@ -31,6 +31,7 @@ import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.model.Game import org.citra.citra_emu.model.Game
import org.citra.citra_emu.utils.BuildUtil import org.citra.citra_emu.utils.BuildUtil
import org.citra.citra_emu.utils.FileUtil import org.citra.citra_emu.utils.FileUtil
import org.citra.citra_emu.utils.GraphicsUtil
import org.citra.citra_emu.utils.Log import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.RemovableStorageHelper import org.citra.citra_emu.utils.RemovableStorageHelper
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
@@ -344,11 +345,12 @@ object NativeLibrary {
return coreErrorAlertResult return coreErrorAlertResult
} }
@get:Keep @Keep
@get:JvmStatic @JvmStatic
val isPortraitMode: Boolean fun isPortraitMode(): Boolean = (
get() = CitraApplication.appContext.resources.configuration.orientation == CitraApplication.appContext.resources.configuration.orientation ==
Configuration.ORIENTATION_PORTRAIT Configuration.ORIENTATION_PORTRAIT
)
@Keep @Keep
@JvmStatic @JvmStatic
@@ -800,6 +802,10 @@ object NativeLibrary {
@JvmStatic @JvmStatic
fun getBuildFlavor(): String = BuildConfig.FLAVOR fun getBuildFlavor(): String = BuildConfig.FLAVOR
@Keep
@JvmStatic
fun isUsingAngleForOpenGL(): Boolean = GraphicsUtil.isUsingAngleForOpenGL()
@Keep @Keep
@JvmStatic @JvmStatic
fun fileExists(path: String): Boolean = if (FileUtil.isNativePath(path)) { fun fileExists(path: String): Boolean = if (FileUtil.isNativePath(path)) {
@@ -44,7 +44,7 @@ class ScreenAdjustmentUtil(
} }
val portraitValues = context.resources.getIntArray(R.array.portraitValues) val portraitValues = context.resources.getIntArray(R.array.portraitValues)
if (NativeLibrary.isPortraitMode) { if (NativeLibrary.isPortraitMode()) {
val currentLayout = IntSetting.PORTRAIT_SCREEN_LAYOUT.int val currentLayout = IntSetting.PORTRAIT_SCREEN_LAYOUT.int
val pos = portraitValues.indexOf(currentLayout) val pos = portraitValues.indexOf(currentLayout)
val layoutOption = portraitValues[(pos + 1) % portraitValues.size] val layoutOption = portraitValues[(pos + 1) % portraitValues.size]
@@ -61,21 +61,21 @@ class ScreenAdjustmentUtil(
IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings() NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
} }
fun changeScreenOrientation(layoutOption: Int) { fun changeScreenOrientation(layoutOption: Int) {
IntSetting.SCREEN_LAYOUT.int = layoutOption IntSetting.SCREEN_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG) settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings() NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
} }
fun changeSecondaryOrientation(layoutOption: Int) { fun changeSecondaryOrientation(layoutOption: Int) {
IntSetting.SECONDARY_DISPLAY_LAYOUT.int = layoutOption IntSetting.SECONDARY_DISPLAY_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.SECONDARY_DISPLAY_LAYOUT, SettingsFile.FILE_NAME_CONFIG) settings.saveSetting(IntSetting.SECONDARY_DISPLAY_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings() NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
} }
fun enableSecondaryDisplay(layoutOption: Int) { fun enableSecondaryDisplay(layoutOption: Int) {
@@ -101,6 +101,6 @@ class ScreenAdjustmentUtil(
BooleanSetting.UPRIGHT_SCREEN.boolean = !uprightBoolean BooleanSetting.UPRIGHT_SCREEN.boolean = !uprightBoolean
settings.saveSetting(BooleanSetting.UPRIGHT_SCREEN, SettingsFile.FILE_NAME_CONFIG) settings.saveSetting(BooleanSetting.UPRIGHT_SCREEN, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings() NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
} }
} }
@@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@@ -13,7 +15,9 @@ class DateTimeSetting(
descriptionId: Int, descriptionId: Int,
val key: String? = null, val key: String? = null,
private val defaultValue: String? = null, private val defaultValue: String? = null,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_DATETIME_SETTING override val type = TYPE_DATETIME_SETTING
@@ -3,6 +3,8 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.IntListSetting import org.citra.citra_emu.features.settings.model.IntListSetting
class MultiChoiceSetting( class MultiChoiceSetting(
@@ -13,7 +15,9 @@ class MultiChoiceSetting(
val valuesId: Int, val valuesId: Int,
val key: String? = null, val key: String? = null,
val defaultValue: List<Int>? = null, val defaultValue: List<Int>? = null,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_MULTI_CHOICE override val type = TYPE_MULTI_CHOICE
@@ -4,6 +4,8 @@
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.activities.EmulationActivity import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
@@ -29,6 +31,9 @@ abstract class SettingsItem(
open var isEnabled: Boolean = true open var isEnabled: Boolean = true
@StringRes open var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
val isActive: Boolean val isActive: Boolean
get() { get() {
return this.isEditable && this.isEnabled return this.isEditable && this.isEnabled
@@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractIntSetting import org.citra.citra_emu.features.settings.model.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractShortSetting import org.citra.citra_emu.features.settings.model.AbstractShortSetting
@@ -16,7 +18,9 @@ class SingleChoiceSetting(
val valuesId: Int, val valuesId: Int,
val key: String? = null, val key: String? = null,
val defaultValue: Int? = null, val defaultValue: Int? = null,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_SINGLE_CHOICE override val type = TYPE_SINGLE_CHOICE
@@ -4,6 +4,8 @@
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractFloatSetting import org.citra.citra_emu.features.settings.model.AbstractFloatSetting
import org.citra.citra_emu.features.settings.model.AbstractIntSetting import org.citra.citra_emu.features.settings.model.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
@@ -20,7 +22,9 @@ class SliderSetting(
val units: String, val units: String,
val key: String? = null, val key: String? = null,
val defaultValue: Float? = null, val defaultValue: Float? = null,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_SLIDER override val type = TYPE_SLIDER
val selectedFloat: Float val selectedFloat: Float
@@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@@ -13,7 +15,9 @@ class StringInputSetting(
descriptionId: Int, descriptionId: Int,
val defaultValue: String, val defaultValue: String,
val characterLimit: Int = 0, val characterLimit: Int = 0,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_STRING_INPUT override val type = TYPE_STRING_INPUT
@@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractShortSetting import org.citra.citra_emu.features.settings.model.AbstractShortSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@@ -16,7 +18,9 @@ class StringSingleChoiceSetting(
val values: Array<String>?, val values: Array<String>?,
val key: String? = null, val key: String? = null,
private val defaultValue: String? = null, private val defaultValue: String? = null,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_STRING_SINGLE_CHOICE override val type = TYPE_STRING_SINGLE_CHOICE
@@ -4,6 +4,8 @@
package org.citra.citra_emu.features.settings.model.view package org.citra.citra_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.citra.citra_emu.R
import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting
class SwitchSetting( class SwitchSetting(
@@ -12,7 +14,9 @@ class SwitchSetting(
descriptionId: Int, descriptionId: Int,
val key: String? = null, val key: String? = null,
val defaultValue: Boolean = false, val defaultValue: Boolean = false,
override var isEnabled: Boolean = true override var isEnabled: Boolean = true,
@StringRes override var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
) : SettingsItem(setting, titleId, descriptionId) { ) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_SWITCH override val type = TYPE_SWITCH
@@ -101,7 +101,7 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
settings.saveSettings(activityView) settings.saveSettings(activityView)
// added to ensure that layout changes take effect as soon as settings window closes // added to ensure that layout changes take effect as soon as settings window closes
NativeLibrary.reloadSettings() NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
updateAndroidImageVisibility() updateAndroidImageVisibility()
TurboHelper.reloadTurbo(false) // TODO: Can this go somewhere else? -OS TurboHelper.reloadTurbo(false) // TODO: Can this go somewhere else? -OS
} }
@@ -16,6 +16,7 @@ import android.text.TextWatcher
import android.text.format.DateFormat import android.text.format.DateFormat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
@@ -641,7 +642,7 @@ class SettingsAdapter(private val fragmentView: SettingsFragmentView, public val
return true return true
} }
fun onClickDisabledSetting(isRuntimeDisabled: Boolean) { fun onClickDisabledSetting(isRuntimeDisabled: Boolean, @StringRes disabledMessage: Int) {
val titleId = if (isRuntimeDisabled) { val titleId = if (isRuntimeDisabled) {
R.string.setting_not_editable R.string.setting_not_editable
} else { } else {
@@ -650,7 +651,7 @@ class SettingsAdapter(private val fragmentView: SettingsFragmentView, public val
val messageId = if (isRuntimeDisabled) { val messageId = if (isRuntimeDisabled) {
R.string.setting_not_editable_description R.string.setting_not_editable_description
} else { } else {
R.string.setting_disabled_description disabledMessage
} }
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
@@ -46,6 +46,7 @@ import org.citra.citra_emu.features.settings.model.view.SwitchSetting
import org.citra.citra_emu.features.settings.utils.SettingsFile import org.citra.citra_emu.features.settings.utils.SettingsFile
import org.citra.citra_emu.fragments.ResetSettingsDialogFragment import org.citra.citra_emu.fragments.ResetSettingsDialogFragment
import org.citra.citra_emu.utils.BirthdayMonth import org.citra.citra_emu.utils.BirthdayMonth
import org.citra.citra_emu.utils.GraphicsUtil
import org.citra.citra_emu.utils.Log import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.SystemSaveGame import org.citra.citra_emu.utils.SystemSaveGame
import org.citra.citra_emu.utils.ThemeUtil import org.citra.citra_emu.utils.ThemeUtil
@@ -900,7 +901,9 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.array.graphicsApiNames, R.array.graphicsApiNames,
R.array.graphicsApiValues, R.array.graphicsApiValues,
IntSetting.GRAPHICS_API.key, IntSetting.GRAPHICS_API.key,
IntSetting.GRAPHICS_API.defaultValue IntSetting.GRAPHICS_API.defaultValue,
isEnabled = !GraphicsUtil.isUsingAngleForOpenGL(),
disabledMessage = R.string.setting_disabled_description_angle
) )
) )
add( add(
@@ -62,7 +62,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
if (setting.isActive) { if (setting.isActive) {
adapter.onDateTimeClick(setting, bindingAdapterPosition) adapter.onDateTimeClick(setting, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
} }
@@ -70,7 +70,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -45,7 +45,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter
if (setting.isEditable) { if (setting.isEditable) {
adapter.onInputBindingClick(setting, bindingAdapterPosition) adapter.onInputBindingClick(setting, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
} }
@@ -53,7 +53,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter
if (setting.isEditable) { if (setting.isEditable) {
adapter.onInputBindingLongClick(setting, bindingAdapterPosition) adapter.onInputBindingLongClick(setting, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -57,7 +57,7 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) { if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return return
} }
@@ -73,7 +73,7 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -59,7 +59,7 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
if (!setting.isRuntimeRunnable && EmulationActivity.isRunning()) { if (!setting.isRuntimeRunnable && EmulationActivity.isRunning()) {
adapter.onClickDisabledSetting(true) adapter.onClickDisabledSetting(true, setting.disabledMessage)
} else { } else {
setting.runnable.invoke() setting.runnable.invoke()
} }
@@ -67,7 +67,7 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun onLongClick(clicked: View): Boolean { override fun onLongClick(clicked: View): Boolean {
if (!setting.isEditable) { if (!setting.isEditable) {
adapter.onClickDisabledSetting(true) adapter.onClickDisabledSetting(true, setting.disabledMessage)
return true return true
} }
return setting.onLongClick?.invoke() ?: true return setting.onLongClick?.invoke() ?: true
@@ -66,7 +66,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) { if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return return
} }
@@ -87,7 +87,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -52,7 +52,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
if (setting.isActive) { if (setting.isActive) {
adapter.onSliderClick(setting, bindingAdapterPosition) adapter.onSliderClick(setting, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
} }
@@ -60,7 +60,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -39,7 +39,7 @@ class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: Settin
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) { if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return return
} }
adapter.onStringInputClick((setting as StringInputSetting), bindingAdapterPosition) adapter.onStringInputClick((setting as StringInputSetting), bindingAdapterPosition)
@@ -49,7 +49,7 @@ class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: Settin
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -44,7 +44,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
if (setting.isActive) { if (setting.isActive) {
binding.switchWidget.toggle() binding.switchWidget.toggle()
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
} }
@@ -52,7 +52,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
if (setting.isActive) { if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition) return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else { } else {
adapter.onClickDisabledSetting(!setting.isEditable) adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
} }
return false return false
} }
@@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
@@ -88,7 +88,7 @@ object GraphicsUtil {
return UNKNOWN_RENDERER return UNKNOWN_RENDERER
} }
val openGLRendererString = GLES20.glGetString(GLES20.GL_RENDERER) ?: UNKNOWN_RENDERER val rendererString = GLES20.glGetString(GLES20.GL_RENDERER) ?: UNKNOWN_RENDERER
EGL14.eglMakeCurrent( EGL14.eglMakeCurrent(
glDisplay, glDisplay,
@@ -100,6 +100,8 @@ object GraphicsUtil {
EGL14.eglDestroyContext(glDisplay, glContext) EGL14.eglDestroyContext(glDisplay, glContext)
EGL14.eglTerminate(glDisplay) EGL14.eglTerminate(glDisplay)
return openGLRendererString return rendererString
} }
fun isUsingAngleForOpenGL(): Boolean = (openGLRendererString.contains("ANGLE"))
} }
@@ -28,8 +28,6 @@ add_library(citra-android SHARED
ndk_motion.h ndk_motion.h
system_save_game.cpp system_save_game.cpp
native_log.cpp native_log.cpp
util.cpp
util.h
) )
target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network) target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network)
@@ -7,13 +7,13 @@
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android_utils.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "jni/emu_window/emu_window.h" #include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h" #include "jni/id_cache.h"
#include "jni/input_manager.h" #include "jni/input_manager.h"
#include "jni/util.h"
#include "network/network.h" #include "network/network.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
@@ -47,8 +47,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
} }
void EmuWindow_Android::OnFramebufferSizeChanged() { void EmuWindow_Android::OnFramebufferSizeChanged() {
const bool is_portrait_mode = (IsPortraitMode() && !is_secondary); const bool is_portrait_mode = (AndroidUtils::IsPortraitMode() && !is_secondary);
UpdateCurrentFramebufferLayout(window_width, window_height, is_portrait_mode); UpdateCurrentFramebufferLayout(window_width, window_height, is_portrait_mode);
} }
+3 -8
View File
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/android_storage.h" #include "common/android_utils.h"
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/filter.h" #include "common/logging/filter.h"
@@ -84,10 +84,6 @@ jmethodID GetOnCoreError() {
return s_on_core_error; return s_on_core_error;
} }
jmethodID GetIsPortraitMode() {
return s_is_portrait_mode;
}
jmethodID GetLandscapeScreenLayout() { jmethodID GetLandscapeScreenLayout() {
return s_landscape_screen_layout; return s_landscape_screen_layout;
} }
@@ -181,7 +177,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_on_core_error = env->GetStaticMethodID( s_on_core_error = env->GetStaticMethodID(
s_native_library_class, "onCoreError", s_native_library_class, "onCoreError",
"(Lorg/citra/citra_emu/NativeLibrary$CoreError;Ljava/lang/String;)Z"); "(Lorg/citra/citra_emu/NativeLibrary$CoreError;Ljava/lang/String;)Z");
s_is_portrait_mode = env->GetStaticMethodID(s_native_library_class, "isPortraitMode", "()Z");
s_exit_emulation_activity = s_exit_emulation_activity =
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
s_request_camera_permission = s_request_camera_permission =
@@ -264,7 +259,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
MiiSelector::InitJNI(env); MiiSelector::InitJNI(env);
SoftwareKeyboard::InitJNI(env); SoftwareKeyboard::InitJNI(env);
Camera::StillImage::InitJNI(env); Camera::StillImage::InitJNI(env);
AndroidStorage::InitJNI(env, s_native_library_class); AndroidUtils::InitJNI(env, s_native_library_class);
return JNI_VERSION; return JNI_VERSION;
} }
@@ -293,7 +288,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
MiiSelector::CleanupJNI(env); MiiSelector::CleanupJNI(env);
SoftwareKeyboard::CleanupJNI(env); SoftwareKeyboard::CleanupJNI(env);
Camera::StillImage::CleanupJNI(env); Camera::StillImage::CleanupJNI(env);
AndroidStorage::CleanupJNI(); AndroidUtils::CleanupJNI();
} }
#ifdef __cplusplus #ifdef __cplusplus
-1
View File
@@ -25,7 +25,6 @@ jmethodID GetOnCoreError();
jmethodID GetDisplayAlertMsg(); jmethodID GetDisplayAlertMsg();
jmethodID GetDisplayAlertPrompt(); jmethodID GetDisplayAlertPrompt();
jmethodID GetAlertPromptButton(); jmethodID GetAlertPromptButton();
jmethodID GetIsPortraitMode();
jmethodID GetLandscapeScreenLayout(); jmethodID GetLandscapeScreenLayout();
jmethodID GetPortraitScreenLayout(); jmethodID GetPortraitScreenLayout();
jmethodID GetExitEmulationActivity(); jmethodID GetExitEmulationActivity();
+3 -3
View File
@@ -63,10 +63,10 @@
#endif #endif
#endif #endif
#include "common/android_utils.h"
#include "jni/id_cache.h" #include "jni/id_cache.h"
#include "jni/input_manager.h" #include "jni/input_manager.h"
#include "jni/ndk_motion.h" #include "jni/ndk_motion.h"
#include "jni/util.h"
#include "video_core/debug_utils/debug_utils.h" #include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
@@ -189,7 +189,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
system.InsertCartridge(inserted_cartridge); system.InsertCartridge(inserted_cartridge);
} }
const auto graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
EGLContext* shared_context; EGLContext* shared_context;
switch (graphics_api) { switch (graphics_api) {
#ifdef ENABLE_OPENGL #ifdef ENABLE_OPENGL
@@ -471,7 +471,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_swapScreens([[maybe_unused]] JNIEnv
Settings::values.swap_screen = swap_screens; Settings::values.swap_screen = swap_screens;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
if (system.IsPoweredOn()) { if (system.IsPoweredOn()) {
system.GPU().Renderer().UpdateCurrentFramebufferLayout(IsPortraitMode()); system.GPU().Renderer().UpdateCurrentFramebufferLayout(AndroidUtils::IsPortraitMode());
} }
InputManager::screen_rotation = rotation; InputManager::screen_rotation = rotation;
Camera::NDK::g_rotation = rotation; Camera::NDK::g_rotation = rotation;
-10
View File
@@ -1,10 +0,0 @@
// Copyright Citra Emulator Project / Lime3DS Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "jni/id_cache.h"
bool IsPortraitMode() {
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
}
-8
View File
@@ -1,8 +0,0 @@
// Copyright Citra Emulator Project / Lime3DS Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
/// Calls and returns the value of NativeLibrary.isPortraitMode
bool IsPortraitMode();
@@ -411,7 +411,8 @@
<string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string>
<string name="setting_not_editable">You can\'t edit this now</string> <string name="setting_not_editable">You can\'t edit this now</string>
<string name="setting_disabled">Setting disabled</string> <string name="setting_disabled">Setting disabled</string>
<string name="setting_disabled_description">This setting is currently disabled due to another setting not being the appropriate value.</string> <string name="setting_disabled_description_incompatible_setting">This setting is currently disabled due to another setting not being the appropriate value.</string>
<string name="setting_disabled_description_angle">The renderer can\'t be changed because the device is using ANGLE for OpenGL, which is currently incompatible with Azahar. Vulkan will be used.</string>
<string name="setting_not_editable_description">This option can\'t be changed while a game is running.</string> <string name="setting_not_editable_description">This option can\'t be changed while a game is running.</string>
<string name="auto_select">Auto-Select</string> <string name="auto_select">Auto-Select</string>
<string name="start">Start</string> <string name="start">Start</string>
+2 -2
View File
@@ -650,7 +650,7 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false; first_frame = false;
const auto graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
switch (graphics_api) { switch (graphics_api) {
#ifdef ENABLE_SOFTWARE_RENDERER #ifdef ENABLE_SOFTWARE_RENDERER
case Settings::GraphicsAPI::Software: case Settings::GraphicsAPI::Software:
@@ -837,7 +837,7 @@ void GRenderWindow::showEvent(QShowEvent* event) {
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
#ifdef ENABLE_OPENGL #ifdef ENABLE_OPENGL
const auto graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
if (graphics_api == Settings::GraphicsAPI::OpenGL) { if (graphics_api == Settings::GraphicsAPI::OpenGL) {
auto gl_context = static_cast<OpenGLSharedContext*>(main_context.get()); auto gl_context = static_cast<OpenGLSharedContext*>(main_context.get());
// Bind the shared contexts to the main surface in case the backend wants to take over // Bind the shared contexts to the main surface in case the backend wants to take over
@@ -18,7 +18,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
SetupPerGameUI(); SetupPerGameUI();
SetConfiguration(); SetConfiguration();
const auto graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
const bool res_scale_enabled = graphics_api != Settings::GraphicsAPI::Software; const bool res_scale_enabled = graphics_api != Settings::GraphicsAPI::Software;
ui->resolution_factor_combobox->setEnabled(res_scale_enabled); ui->resolution_factor_combobox->setEnabled(res_scale_enabled);
+2 -2
View File
@@ -130,8 +130,8 @@ endif()
# Android storage is only used for non-libretro Android builds # Android storage is only used for non-libretro Android builds
if (ANDROID AND NOT ENABLE_LIBRETRO) if (ANDROID AND NOT ENABLE_LIBRETRO)
target_sources(citra_common PRIVATE target_sources(citra_common PRIVATE
android_storage.cpp android_utils.cpp
android_storage.h android_utils.h
) )
endif() endif()
@@ -6,11 +6,11 @@
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_io.hpp>
#include "common/android_storage.h" #include "common/android_utils.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
namespace AndroidStorage { namespace AndroidUtils {
JNIEnv* GetEnvForThread() { JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
OwnedEnv() { OwnedEnv() {
@@ -36,21 +36,21 @@ AndroidOpenMode ParseOpenmode(const std::string_view openmode) {
int o = 0; int o = 0;
switch (*mode++) { switch (*mode++) {
case 'r': case 'r':
android_open_mode = AndroidStorage::AndroidOpenMode::READ; android_open_mode = AndroidUtils::AndroidOpenMode::READ;
break; break;
case 'w': case 'w':
android_open_mode = AndroidStorage::AndroidOpenMode::WRITE; android_open_mode = AndroidUtils::AndroidOpenMode::WRITE;
o = O_TRUNC; o = O_TRUNC;
break; break;
case 'a': case 'a':
android_open_mode = AndroidStorage::AndroidOpenMode::WRITE; android_open_mode = AndroidUtils::AndroidOpenMode::WRITE;
o = O_APPEND; o = O_APPEND;
break; break;
} }
// [rwa]\+ or [rwa]b\+ means read and write // [rwa]\+ or [rwa]b\+ means read and write
if (*mode == '+' || (*mode == 'b' && mode[1] == '+')) { if (*mode == '+' || (*mode == 'b' && mode[1] == '+')) {
android_open_mode = AndroidStorage::AndroidOpenMode::READ_WRITE; android_open_mode = AndroidUtils::AndroidOpenMode::READ_WRITE;
} }
return android_open_mode | o; return android_open_mode | o;
@@ -67,7 +67,7 @@ void InitJNI(JNIEnv* env, jclass clazz) {
#define F(JMethodID, JMethodName, Signature) \ #define F(JMethodID, JMethodName, Signature) \
JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature); JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature);
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS) ANDROID_JNI_FUNCTIONS(FS)
#undef F #undef F
#undef FS #undef FS
#undef FR #undef FR
@@ -78,7 +78,7 @@ void CleanupJNI() {
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID) #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
#define F(JMethodID) JMethodID = nullptr; #define F(JMethodID) JMethodID = nullptr;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS) ANDROID_JNI_FUNCTIONS(FS)
#undef F #undef F
#undef FS #undef FS
#undef FR #undef FR
@@ -199,6 +199,16 @@ std::string GetBuildFlavor() {
return env->GetStringUTFChars(jflavor, nullptr); return env->GetStringUTFChars(jflavor, nullptr);
} }
bool IsPortraitMode() {
auto env = GetEnvForThread();
return (JNI_FALSE != env->CallStaticBooleanMethod(native_library, is_portrait_mode));
}
bool IsUsingAngleForOpenGL() {
auto env = GetEnvForThread();
return env->CallStaticBooleanMethod(native_library, is_using_angle_for_opengl);
}
bool CopyFile(const std::string& source, const std::string& destination_path, bool CopyFile(const std::string& source, const std::string& destination_path,
const std::string& destination_filename) { const std::string& destination_filename) {
if (copy_file == nullptr) { if (copy_file == nullptr) {
@@ -268,14 +278,14 @@ bool MoveAndRenameFile(const std::string& src_full_path, const std::string& dest
bool result; bool result;
const std::string tmp_path = "/tmp"; const std::string tmp_path = "/tmp";
AndroidStorage::CreateDir("/", "tmp"); AndroidUtils::CreateDir("/", "tmp");
// If a simultaneous move and rename are not necessary, use individual methods // If a simultaneous move and rename are not necessary, use individual methods
if (src_filename == dest_filename || src_parent_path == dest_parent_path) { if (src_filename == dest_filename || src_parent_path == dest_parent_path) {
if (src_filename != dest_filename) { if (src_filename != dest_filename) {
return AndroidStorage::RenameFile(src_full_path, dest_filename); return AndroidUtils::RenameFile(src_full_path, dest_filename);
} else if (src_parent_path != dest_parent_path) { } else if (src_parent_path != dest_parent_path) {
return AndroidStorage::MoveFile(src_filename, src_parent_path, dest_parent_path); return AndroidUtils::MoveFile(src_filename, src_parent_path, dest_parent_path);
} }
} }
@@ -283,28 +293,28 @@ bool MoveAndRenameFile(const std::string& src_full_path, const std::string& dest
// This prevents clashes if files with the same name are moved simultaneously. // This prevents clashes if files with the same name are moved simultaneously.
const auto uuid = boost::uuids::to_string(boost::uuids::time_generator_v7()()); const auto uuid = boost::uuids::to_string(boost::uuids::time_generator_v7()());
const auto allocated_tmp_path = tmp_path + "/" + uuid; const auto allocated_tmp_path = tmp_path + "/" + uuid;
AndroidStorage::CreateDir(tmp_path, uuid); AndroidUtils::CreateDir(tmp_path, uuid);
// Step 2: Attempt to move to allocated temporary directory. // Step 2: Attempt to move to allocated temporary directory.
// If this step fails, skip everything except the cleanup. // If this step fails, skip everything except the cleanup.
result = AndroidStorage::MoveFile(src_filename, src_parent_path, allocated_tmp_path); result = AndroidUtils::MoveFile(src_filename, src_parent_path, allocated_tmp_path);
if (result == true) { if (result == true) {
// Step 3: Rename to desired file name. // Step 3: Rename to desired file name.
AndroidStorage::RenameFile((allocated_tmp_path + "/" + src_filename), dest_filename); AndroidUtils::RenameFile((allocated_tmp_path + "/" + src_filename), dest_filename);
// Step 4: If a file with the desired name in the destination exists, remove it. // Step 4: If a file with the desired name in the destination exists, remove it.
AndroidStorage::DeleteDocument(dest_full_path); AndroidUtils::DeleteDocument(dest_full_path);
// Step 5: Attempt to move file to desired location. // Step 5: Attempt to move file to desired location.
// If this step fails, move the file back to where it came from. // If this step fails, move the file back to where it came from.
result = AndroidStorage::MoveFile(dest_filename, allocated_tmp_path, dest_parent_path); result = AndroidUtils::MoveFile(dest_filename, allocated_tmp_path, dest_parent_path);
if (result == false) { if (result == false) {
AndroidStorage::MoveAndRenameFile((allocated_tmp_path + "/" + dest_filename), AndroidUtils::MoveAndRenameFile((allocated_tmp_path + "/" + dest_filename),
src_full_path); src_full_path);
} }
} }
// Step 6: Clean up the allocated temp directory. // Step 6: Clean up the allocated temp directory.
AndroidStorage::DeleteDocument(allocated_tmp_path); AndroidUtils::DeleteDocument(allocated_tmp_path);
return result; return result;
} }
@@ -326,7 +336,7 @@ std::string TranslateFilePath(const std::string& filepath) {
} }
bool CanUseRawFS() { bool CanUseRawFS() {
return AndroidStorage::GetBuildFlavor() != AndroidBuildFlavors::GOOGLEPLAY; return AndroidUtils::GetBuildFlavor() != AndroidBuildFlavors::GOOGLEPLAY;
} }
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \ #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
@@ -344,5 +354,5 @@ ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F #undef F
#undef FR #undef FR
} // namespace AndroidStorage } // namespace AndroidUtils
#endif #endif
@@ -10,7 +10,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <jni.h> #include <jni.h>
#define ANDROID_STORAGE_FUNCTIONS(V) \ #define ANDROID_JNI_FUNCTIONS(V) \
V(CreateFile, bool, (const std::string& directory, const std::string& filename), create_file, \ V(CreateFile, bool, (const std::string& directory, const std::string& filename), create_file, \
"createFile", "(Ljava/lang/String;Ljava/lang/String;)Z") \ "createFile", "(Ljava/lang/String;Ljava/lang/String;)Z") \
V(CreateDir, bool, (const std::string& directory, const std::string& filename), create_dir, \ V(CreateDir, bool, (const std::string& directory, const std::string& filename), create_dir, \
@@ -32,6 +32,8 @@
update_document_location, "updateDocumentLocation", \ update_document_location, "updateDocumentLocation", \
"(Ljava/lang/String;Ljava/lang/String;)Z") \ "(Ljava/lang/String;Ljava/lang/String;)Z") \
V(GetBuildFlavor, std::string, (), get_build_flavor, "getBuildFlavor", "()Ljava/lang/String;") \ V(GetBuildFlavor, std::string, (), get_build_flavor, "getBuildFlavor", "()Ljava/lang/String;") \
V(IsPortraitMode, bool, (), is_portrait_mode, "isPortraitMode", "()Z") \
V(IsUsingAngleForOpenGL, bool, (), is_using_angle_for_opengl, "isUsingAngleForOpenGL", "()Z") \
V(MoveFile, bool, \ V(MoveFile, bool, \
(const std::string& filename, const std::string& source_dir_path, \ (const std::string& filename, const std::string& source_dir_path, \
const std::string& destination_dir_path), \ const std::string& destination_dir_path), \
@@ -44,7 +46,7 @@
V(GetSize, std::uint64_t, get_size, CallStaticLongMethod, "getSize", "(Ljava/lang/String;)J") \ V(GetSize, std::uint64_t, get_size, CallStaticLongMethod, "getSize", "(Ljava/lang/String;)J") \
V(DeleteDocument, bool, delete_document, CallStaticBooleanMethod, "deleteDocument", \ V(DeleteDocument, bool, delete_document, CallStaticBooleanMethod, "deleteDocument", \
"(Ljava/lang/String;)Z") "(Ljava/lang/String;)Z")
namespace AndroidStorage { namespace AndroidUtils {
static JavaVM* g_jvm = nullptr; static JavaVM* g_jvm = nullptr;
static jclass native_library = nullptr; static jclass native_library = nullptr;
@@ -52,7 +54,7 @@ static jclass native_library = nullptr;
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID) #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
#define F(JMethodID) static jmethodID JMethodID = nullptr; #define F(JMethodID) static jmethodID JMethodID = nullptr;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS) ANDROID_JNI_FUNCTIONS(FS)
#undef F #undef F
#undef FS #undef FS
#undef FR #undef FR
@@ -91,7 +93,7 @@ void CleanupJNI();
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \ #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
F(FunctionName, Parameters, ReturnValue) F(FunctionName, Parameters, ReturnValue)
#define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters; #define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters;
ANDROID_STORAGE_FUNCTIONS(FS) ANDROID_JNI_FUNCTIONS(FS)
#undef F #undef F
#undef FS #undef FS
@@ -102,5 +104,5 @@ ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F #undef F
#undef FR #undef FR
} // namespace AndroidStorage } // namespace AndroidUtils
#endif #endif
+42 -42
View File
@@ -83,7 +83,7 @@ typedef struct stat file_stat_t;
#endif #endif
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
#include "common/android_storage.h" #include "common/android_utils.h"
#include "common/string_util.h" #include "common/string_util.h"
#endif #endif
@@ -168,11 +168,11 @@ bool Exists(const std::string& filename) {
int result = _wstat64(Common::UTF8ToUTF16W(copy).c_str(), &file_info); int result = _wstat64(Common::UTF8ToUTF16W(copy).c_str(), &file_info);
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
int result; int result;
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
struct stat file_info; struct stat file_info;
result = stat(AndroidStorage::TranslateFilePath(copy).c_str(), &file_info); result = stat(AndroidUtils::TranslateFilePath(copy).c_str(), &file_info);
} else { } else {
result = AndroidStorage::FileExists(filename) ? 0 : -1; result = AndroidUtils::FileExists(filename) ? 0 : -1;
} }
#else #else
struct stat file_info; struct stat file_info;
@@ -197,10 +197,10 @@ bool IsDirectory(const std::string& filename) {
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
struct stat file_info; struct stat file_info;
int result; int result;
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
result = stat(AndroidStorage::TranslateFilePath(copy).c_str(), &file_info); result = stat(AndroidUtils::TranslateFilePath(copy).c_str(), &file_info);
} else { } else {
return AndroidStorage::IsDirectory(filename); return AndroidUtils::IsDirectory(filename);
} }
#else #else
struct stat file_info; struct stat file_info;
@@ -260,13 +260,13 @@ bool Delete(const std::string& filepath) {
return false; return false;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
if (unlink(AndroidStorage::TranslateFilePath(filepath).c_str()) == -1) { if (unlink(AndroidUtils::TranslateFilePath(filepath).c_str()) == -1) {
LOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filepath, GetLastErrorMsg()); LOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filepath, GetLastErrorMsg());
return false; return false;
} }
} else { } else {
if (!AndroidStorage::DeleteDocument(filepath)) { if (!AndroidUtils::DeleteDocument(filepath)) {
LOG_ERROR(Common_Filesystem, "unlink failed on {}", filepath); LOG_ERROR(Common_Filesystem, "unlink failed on {}", filepath);
return false; return false;
} }
@@ -294,8 +294,8 @@ bool CreateDir(const std::string& path) {
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error); LOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
return false; return false;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
if (mkdir(AndroidStorage::TranslateFilePath(path).c_str(), 0755) == 0) if (mkdir(AndroidUtils::TranslateFilePath(path).c_str(), 0755) == 0)
return true; return true;
int err = errno; int err = errno;
@@ -320,7 +320,7 @@ bool CreateDir(const std::string& path) {
if (directory.empty()) { if (directory.empty()) {
directory = "/"; directory = "/";
} }
if (!AndroidStorage::CreateDir(directory, filename)) { if (!AndroidUtils::CreateDir(directory, filename)) {
LOG_ERROR(Common_Filesystem, "mkdir failed on {}", path); LOG_ERROR(Common_Filesystem, "mkdir failed on {}", path);
return false; return false;
}; };
@@ -397,11 +397,11 @@ bool DeleteDir(const std::string& filename) {
if (::RemoveDirectoryW(Common::UTF8ToUTF16W(filename).c_str())) if (::RemoveDirectoryW(Common::UTF8ToUTF16W(filename).c_str()))
return true; return true;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
if (rmdir(AndroidStorage::TranslateFilePath(filename).c_str()) == 0) if (rmdir(AndroidUtils::TranslateFilePath(filename).c_str()) == 0)
return true; return true;
} else { } else {
if (AndroidStorage::DeleteDocument(filename)) if (AndroidUtils::DeleteDocument(filename))
return true; return true;
} }
#else #else
@@ -421,13 +421,13 @@ bool Rename(const std::string& srcFullPath, const std::string& destFullPath) {
return true; return true;
} }
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
if (rename(AndroidStorage::TranslateFilePath(srcFullPath).c_str(), if (rename(AndroidUtils::TranslateFilePath(srcFullPath).c_str(),
AndroidStorage::TranslateFilePath(destFullPath).c_str()) == 0) { AndroidUtils::TranslateFilePath(destFullPath).c_str()) == 0) {
return true; return true;
} }
} else { } else {
if (AndroidStorage::MoveAndRenameFile(srcFullPath, destFullPath)) { if (AndroidUtils::MoveAndRenameFile(srcFullPath, destFullPath)) {
return true; return true;
} }
} }
@@ -496,12 +496,12 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
}; };
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
return copy_files(AndroidStorage::TranslateFilePath(srcFilename), return copy_files(AndroidUtils::TranslateFilePath(srcFilename),
AndroidStorage::TranslateFilePath(destFilename)); AndroidUtils::TranslateFilePath(destFilename));
} else { } else {
return AndroidStorage::CopyFile(srcFilename, std::string(GetParentPath(destFilename)), return AndroidUtils::CopyFile(srcFilename, std::string(GetParentPath(destFilename)),
std::string(GetFilename(destFilename))); std::string(GetFilename(destFilename)));
} }
#else #else
return copy_files(srcFilename, destFilename); return copy_files(srcFilename, destFilename);
@@ -526,12 +526,12 @@ u64 GetSize(const std::string& filename) {
struct _stat64 buf; struct _stat64 buf;
if (_wstat64(Common::UTF8ToUTF16W(filename).c_str(), &buf) == 0) if (_wstat64(Common::UTF8ToUTF16W(filename).c_str(), &buf) == 0)
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
if (stat(AndroidStorage::TranslateFilePath(filename).c_str(), &buf) == 0) { if (stat(AndroidUtils::TranslateFilePath(filename).c_str(), &buf) == 0) {
return buf.st_size; return buf.st_size;
} }
} else { } else {
u64 result = AndroidStorage::GetSize(filename); u64 result = AndroidUtils::GetSize(filename);
LOG_TRACE(Common_Filesystem, "{}: {}", filename, result); LOG_TRACE(Common_Filesystem, "{}: {}", filename, result);
return result; return result;
} }
@@ -608,10 +608,10 @@ std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string&
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string& directory) { std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string& directory) {
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
std::vector<std::string> entries; std::vector<std::string> entries;
DIR* dirp = opendir(AndroidStorage::TranslateFilePath(directory).c_str()); DIR* dirp = opendir(AndroidUtils::TranslateFilePath(directory).c_str());
if (!dirp) if (!dirp)
return std::nullopt; return std::nullopt;
@@ -622,7 +622,7 @@ std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string&
closedir(dirp); closedir(dirp);
return entries; return entries;
} else { } else {
return AndroidStorage::GetFilesName(directory); return AndroidUtils::GetFilesName(directory);
} }
} }
@@ -1354,27 +1354,27 @@ bool IOFile::Open() {
m_good = m_file != nullptr; m_good = m_file != nullptr;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) { if (AndroidUtils::CanUseRawFS()) {
m_file = FOPEN(AndroidStorage::TranslateFilePath(filename).c_str(), openmode.c_str()); m_file = FOPEN(AndroidUtils::TranslateFilePath(filename).c_str(), openmode.c_str());
} else { } else {
// Check whether filepath is startsWith content // Check whether filepath is startsWith content
AndroidStorage::AndroidOpenMode android_open_mode = AndroidStorage::ParseOpenmode(openmode); AndroidUtils::AndroidOpenMode android_open_mode = AndroidUtils::ParseOpenmode(openmode);
if (android_open_mode == AndroidStorage::AndroidOpenMode::WRITE || if (android_open_mode == AndroidUtils::AndroidOpenMode::WRITE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE || android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE ||
android_open_mode == AndroidStorage::AndroidOpenMode::WRITE_APPEND || android_open_mode == AndroidUtils::AndroidOpenMode::WRITE_APPEND ||
android_open_mode == AndroidStorage::AndroidOpenMode::WRITE_TRUNCATE || android_open_mode == AndroidUtils::AndroidOpenMode::WRITE_TRUNCATE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE_TRUNCATE || android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE_TRUNCATE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE_APPEND) { android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE_APPEND) {
if (!FileUtil::Exists(filename)) { if (!FileUtil::Exists(filename)) {
std::string directory(GetParentPath(filename)); std::string directory(GetParentPath(filename));
std::string display_name(GetFilename(filename)); std::string display_name(GetFilename(filename));
if (!AndroidStorage::CreateFile(directory, display_name)) { if (!AndroidUtils::CreateFile(directory, display_name)) {
m_good = m_file != nullptr; m_good = m_file != nullptr;
return m_good; return m_good;
} }
} }
} }
m_fd = AndroidStorage::OpenContentUri(filename, android_open_mode); m_fd = AndroidUtils::OpenContentUri(filename, android_open_mode);
if (m_fd != -1) { if (m_fd != -1) {
int error_num = 0; int error_num = 0;
m_file = fdopen(m_fd, openmode.c_str()); m_file = fdopen(m_fd, openmode.c_str());
+2 -2
View File
@@ -35,7 +35,7 @@
#include "common/string_util.h" #include "common/string_util.h"
#endif #endif
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS) #if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
#include "android_storage.h" #include "android_utils.h"
#endif #endif
#ifdef HAVE_LIBRETRO_VFS #ifdef HAVE_LIBRETRO_VFS
@@ -443,7 +443,7 @@ public:
return fileno(filestream_get_vfs_handle(m_file)->fp); return fileno(filestream_get_vfs_handle(m_file)->fp);
#else #else
#ifdef ANDROID #ifdef ANDROID
if (!AndroidStorage::CanUseRawFS()) { if (!AndroidUtils::CanUseRawFS()) {
return m_fd; return m_fd;
} }
#endif // ANDROID #endif // ANDROID
+14
View File
@@ -5,6 +5,9 @@
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include "audio_core/dsp_interface.h" #include "audio_core/dsp_interface.h"
#if defined(ANDROID) && !defined(HAVE_LIBRETRO)
#include "common/android_utils.h"
#endif
#include "common/file_util.h" #include "common/file_util.h"
#include "common/settings.h" #include "common/settings.h"
@@ -243,6 +246,17 @@ void RestoreGlobalState(bool is_powered_on) {
values.disable_right_eye_render.SetGlobal(true); values.disable_right_eye_render.SetGlobal(true);
} }
/// Gets the graphics API that should be used; not necessarily one set in settings
Settings::GraphicsAPI GetWorkingGraphicsAPI() {
auto graphics_api = Settings::values.graphics_api.GetValue();
#if defined(ANDROID) && !defined(HAVE_LIBRETRO)
if (AndroidUtils::IsUsingAngleForOpenGL()) {
graphics_api = Settings::GraphicsAPI::Vulkan;
}
#endif
return graphics_api;
}
void LoadProfile(int index) { void LoadProfile(int index) {
Settings::values.current_input_profile = Settings::values.input_profiles[index]; Settings::values.current_input_profile = Settings::values.input_profiles[index];
Settings::values.current_input_profile_index = index; Settings::values.current_input_profile_index = index;
+3
View File
@@ -685,6 +685,9 @@ void LogSettings();
// Restore the global state of all applicable settings in the Values struct // Restore the global state of all applicable settings in the Values struct
void RestoreGlobalState(bool is_powered_on); void RestoreGlobalState(bool is_powered_on);
/// Gets the graphics API that should be used; not necessarily one set in settings
Settings::GraphicsAPI GetWorkingGraphicsAPI();
// Input profiles // Input profiles
void LoadProfile(int index); void LoadProfile(int index);
void SaveProfile(int index); void SaveProfile(int index);
+1 -1
View File
@@ -18,7 +18,7 @@ RendererBase::RendererBase(Core::System& system_, Frontend::EmuWindow& window,
RendererBase::~RendererBase() = default; RendererBase::~RendererBase() = default;
u32 RendererBase::GetResolutionScaleFactor() { u32 RendererBase::GetResolutionScaleFactor() {
const auto graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
if (graphics_api == Settings::GraphicsAPI::Software) { if (graphics_api == Settings::GraphicsAPI::Software) {
// Software renderer always render at native resolution // Software renderer always render at native resolution
return 1; return 1;
+1 -1
View File
@@ -25,7 +25,7 @@ namespace VideoCore {
std::unique_ptr<RendererBase> CreateRenderer(Frontend::EmuWindow& emu_window, std::unique_ptr<RendererBase> CreateRenderer(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window, Frontend::EmuWindow* secondary_window,
Pica::PicaCore& pica, Core::System& system) { Pica::PicaCore& pica, Core::System& system) {
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue(); const auto graphics_api = Settings::GetWorkingGraphicsAPI();
switch (graphics_api) { switch (graphics_api) {
#ifdef ENABLE_SOFTWARE_RENDERER #ifdef ENABLE_SOFTWARE_RENDERER
case Settings::GraphicsAPI::Software: case Settings::GraphicsAPI::Software: