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

View file

@ -31,6 +31,7 @@ import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.model.Game
import org.citra.citra_emu.utils.BuildUtil
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.RemovableStorageHelper
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
@ -344,11 +345,12 @@ object NativeLibrary {
return coreErrorAlertResult
}
@get:Keep
@get:JvmStatic
val isPortraitMode: Boolean
get() = CitraApplication.appContext.resources.configuration.orientation ==
@Keep
@JvmStatic
fun isPortraitMode(): Boolean = (
CitraApplication.appContext.resources.configuration.orientation ==
Configuration.ORIENTATION_PORTRAIT
)
@Keep
@JvmStatic
@ -800,6 +802,10 @@ object NativeLibrary {
@JvmStatic
fun getBuildFlavor(): String = BuildConfig.FLAVOR
@Keep
@JvmStatic
fun isUsingAngleForOpenGL(): Boolean = GraphicsUtil.isUsingAngleForOpenGL()
@Keep
@JvmStatic
fun fileExists(path: String): Boolean = if (FileUtil.isNativePath(path)) {

View file

@ -44,7 +44,7 @@ class ScreenAdjustmentUtil(
}
val portraitValues = context.resources.getIntArray(R.array.portraitValues)
if (NativeLibrary.isPortraitMode) {
if (NativeLibrary.isPortraitMode()) {
val currentLayout = IntSetting.PORTRAIT_SCREEN_LAYOUT.int
val pos = portraitValues.indexOf(currentLayout)
val layoutOption = portraitValues[(pos + 1) % portraitValues.size]
@ -61,21 +61,21 @@ class ScreenAdjustmentUtil(
IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
}
fun changeScreenOrientation(layoutOption: Int) {
IntSetting.SCREEN_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
}
fun changeSecondaryOrientation(layoutOption: Int) {
IntSetting.SECONDARY_DISPLAY_LAYOUT.int = layoutOption
settings.saveSetting(IntSetting.SECONDARY_DISPLAY_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
}
fun enableSecondaryDisplay(layoutOption: Int) {
@ -101,6 +101,6 @@ class ScreenAdjustmentUtil(
BooleanSetting.UPRIGHT_SCREEN.boolean = !uprightBoolean
settings.saveSetting(BooleanSetting.UPRIGHT_SCREEN, SettingsFile.FILE_NAME_CONFIG)
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
}
}

View file

@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
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.AbstractStringSetting
@ -13,7 +15,9 @@ class DateTimeSetting(
descriptionId: Int,
val key: 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) {
override val type = TYPE_DATETIME_SETTING

View file

@ -3,6 +3,8 @@
// Refer to the license.txt file included.
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.IntListSetting
class MultiChoiceSetting(
@ -13,7 +15,9 @@ class MultiChoiceSetting(
val valuesId: Int,
val key: String? = 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) {
override val type = TYPE_MULTI_CHOICE

View file

@ -4,6 +4,8 @@
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.features.settings.model.AbstractSetting
@ -29,6 +31,9 @@ abstract class SettingsItem(
open var isEnabled: Boolean = true
@StringRes open var disabledMessage: Int =
R.string.setting_disabled_description_incompatible_setting
val isActive: Boolean
get() {
return this.isEditable && this.isEnabled

View file

@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
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.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractShortSetting
@ -16,7 +18,9 @@ class SingleChoiceSetting(
val valuesId: Int,
val key: String? = 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) {
override val type = TYPE_SINGLE_CHOICE

View file

@ -4,6 +4,8 @@
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.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting
@ -20,7 +22,9 @@ class SliderSetting(
val units: String,
val key: String? = 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) {
override val type = TYPE_SLIDER
val selectedFloat: Float

View file

@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
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.AbstractStringSetting
@ -13,7 +15,9 @@ class StringInputSetting(
descriptionId: Int,
val defaultValue: String,
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) {
override val type = TYPE_STRING_INPUT

View file

@ -1,9 +1,11 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
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.AbstractShortSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@ -16,7 +18,9 @@ class StringSingleChoiceSetting(
val values: Array<String>?,
val key: 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) {
override val type = TYPE_STRING_SINGLE_CHOICE

View file

@ -4,6 +4,8 @@
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
class SwitchSetting(
@ -12,7 +14,9 @@ class SwitchSetting(
descriptionId: Int,
val key: String? = null,
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) {
override val type = TYPE_SWITCH

View file

@ -101,7 +101,7 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
settings.saveSettings(activityView)
// added to ensure that layout changes take effect as soon as settings window closes
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode())
updateAndroidImageVisibility()
TurboHelper.reloadTurbo(false) // TODO: Can this go somewhere else? -OS
}

View file

@ -16,6 +16,7 @@ import android.text.TextWatcher
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doOnTextChanged
@ -641,7 +642,7 @@ class SettingsAdapter(private val fragmentView: SettingsFragmentView, public val
return true
}
fun onClickDisabledSetting(isRuntimeDisabled: Boolean) {
fun onClickDisabledSetting(isRuntimeDisabled: Boolean, @StringRes disabledMessage: Int) {
val titleId = if (isRuntimeDisabled) {
R.string.setting_not_editable
} else {
@ -650,7 +651,7 @@ class SettingsAdapter(private val fragmentView: SettingsFragmentView, public val
val messageId = if (isRuntimeDisabled) {
R.string.setting_not_editable_description
} else {
R.string.setting_disabled_description
disabledMessage
}
MessageDialogFragment.newInstance(

View file

@ -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.fragments.ResetSettingsDialogFragment
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.SystemSaveGame
import org.citra.citra_emu.utils.ThemeUtil
@ -900,7 +901,9 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.array.graphicsApiNames,
R.array.graphicsApiValues,
IntSetting.GRAPHICS_API.key,
IntSetting.GRAPHICS_API.defaultValue
IntSetting.GRAPHICS_API.defaultValue,
isEnabled = !GraphicsUtil.isUsingAngleForOpenGL(),
disabledMessage = R.string.setting_disabled_description_angle
)
)
add(

View file

@ -62,7 +62,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
if (setting.isActive) {
adapter.onDateTimeClick(setting, bindingAdapterPosition)
} 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) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -45,7 +45,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter
if (setting.isEditable) {
adapter.onInputBindingClick(setting, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
}
@ -53,7 +53,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter
if (setting.isEditable) {
adapter.onInputBindingLongClick(setting, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -57,7 +57,7 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return
}
@ -73,7 +73,7 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -59,7 +59,7 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun onClick(clicked: View) {
if (!setting.isRuntimeRunnable && EmulationActivity.isRunning()) {
adapter.onClickDisabledSetting(true)
adapter.onClickDisabledSetting(true, setting.disabledMessage)
} else {
setting.runnable.invoke()
}
@ -67,7 +67,7 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun onLongClick(clicked: View): Boolean {
if (!setting.isEditable) {
adapter.onClickDisabledSetting(true)
adapter.onClickDisabledSetting(true, setting.disabledMessage)
return true
}
return setting.onLongClick?.invoke() ?: true

View file

@ -66,7 +66,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return
}
@ -87,7 +87,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -52,7 +52,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
if (setting.isActive) {
adapter.onSliderClick(setting, bindingAdapterPosition)
} 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) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -39,7 +39,7 @@ class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: Settin
override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
return
}
adapter.onStringInputClick((setting as StringInputSetting), bindingAdapterPosition)
@ -49,7 +49,7 @@ class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: Settin
if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -44,7 +44,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
if (setting.isActive) {
binding.switchWidget.toggle()
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
}
@ -52,7 +52,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
adapter.onClickDisabledSetting(!setting.isEditable, setting.disabledMessage)
}
return false
}

View file

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -88,7 +88,7 @@ object GraphicsUtil {
return UNKNOWN_RENDERER
}
val openGLRendererString = GLES20.glGetString(GLES20.GL_RENDERER) ?: UNKNOWN_RENDERER
val rendererString = GLES20.glGetString(GLES20.GL_RENDERER) ?: UNKNOWN_RENDERER
EGL14.eglMakeCurrent(
glDisplay,
@ -100,6 +100,8 @@ object GraphicsUtil {
EGL14.eglDestroyContext(glDisplay, glContext)
EGL14.eglTerminate(glDisplay)
return openGLRendererString
return rendererString
}
fun isUsingAngleForOpenGL(): Boolean = (openGLRendererString.contains("ANGLE"))
}

View file

@ -28,8 +28,6 @@ add_library(citra-android SHARED
ndk_motion.h
system_save_game.cpp
native_log.cpp
util.cpp
util.h
)
target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network)

View file

@ -7,13 +7,13 @@
#include <cstdlib>
#include <string>
#include <android/native_window_jni.h>
#include "common/android_utils.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "jni/util.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
@ -47,8 +47,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
}
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);
}

View file

@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/android_storage.h"
#include "common/android_utils.h"
#include "common/common_paths.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
@ -84,10 +84,6 @@ jmethodID GetOnCoreError() {
return s_on_core_error;
}
jmethodID GetIsPortraitMode() {
return s_is_portrait_mode;
}
jmethodID GetLandscapeScreenLayout() {
return s_landscape_screen_layout;
}
@ -181,7 +177,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_on_core_error = env->GetStaticMethodID(
s_native_library_class, "onCoreError",
"(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 =
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
s_request_camera_permission =
@ -264,7 +259,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
MiiSelector::InitJNI(env);
SoftwareKeyboard::InitJNI(env);
Camera::StillImage::InitJNI(env);
AndroidStorage::InitJNI(env, s_native_library_class);
AndroidUtils::InitJNI(env, s_native_library_class);
return JNI_VERSION;
}
@ -293,7 +288,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
MiiSelector::CleanupJNI(env);
SoftwareKeyboard::CleanupJNI(env);
Camera::StillImage::CleanupJNI(env);
AndroidStorage::CleanupJNI();
AndroidUtils::CleanupJNI();
}
#ifdef __cplusplus

View file

@ -25,7 +25,6 @@ jmethodID GetOnCoreError();
jmethodID GetDisplayAlertMsg();
jmethodID GetDisplayAlertPrompt();
jmethodID GetAlertPromptButton();
jmethodID GetIsPortraitMode();
jmethodID GetLandscapeScreenLayout();
jmethodID GetPortraitScreenLayout();
jmethodID GetExitEmulationActivity();

View file

@ -63,10 +63,10 @@
#endif
#endif
#include "common/android_utils.h"
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "jni/ndk_motion.h"
#include "jni/util.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
@ -189,7 +189,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
system.InsertCartridge(inserted_cartridge);
}
const auto graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::GetWorkingGraphicsAPI();
EGLContext* shared_context;
switch (graphics_api) {
#ifdef ENABLE_OPENGL
@ -471,7 +471,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_swapScreens([[maybe_unused]] JNIEnv
Settings::values.swap_screen = swap_screens;
auto& system = Core::System::GetInstance();
if (system.IsPoweredOn()) {
system.GPU().Renderer().UpdateCurrentFramebufferLayout(IsPortraitMode());
system.GPU().Renderer().UpdateCurrentFramebufferLayout(AndroidUtils::IsPortraitMode());
}
InputManager::screen_rotation = rotation;
Camera::NDK::g_rotation = rotation;

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());
}

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();

View file

@ -411,7 +411,8 @@
<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_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="auto_select">Auto-Select</string>
<string name="start">Start</string>

View file

@ -650,7 +650,7 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false;
const auto graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::GetWorkingGraphicsAPI();
switch (graphics_api) {
#ifdef ENABLE_SOFTWARE_RENDERER
case Settings::GraphicsAPI::Software:
@ -837,7 +837,7 @@ void GRenderWindow::showEvent(QShowEvent* event) {
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
#ifdef ENABLE_OPENGL
const auto graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::GetWorkingGraphicsAPI();
if (graphics_api == Settings::GraphicsAPI::OpenGL) {
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

View file

@ -18,7 +18,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
SetupPerGameUI();
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;
ui->resolution_factor_combobox->setEnabled(res_scale_enabled);

View file

@ -130,8 +130,8 @@ endif()
# Android storage is only used for non-libretro Android builds
if (ANDROID AND NOT ENABLE_LIBRETRO)
target_sources(citra_common PRIVATE
android_storage.cpp
android_storage.h
android_utils.cpp
android_utils.h
)
endif()

View file

@ -6,11 +6,11 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "common/android_storage.h"
#include "common/android_utils.h"
#include "common/file_util.h"
#include "common/logging/log.h"
namespace AndroidStorage {
namespace AndroidUtils {
JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv {
OwnedEnv() {
@ -36,21 +36,21 @@ AndroidOpenMode ParseOpenmode(const std::string_view openmode) {
int o = 0;
switch (*mode++) {
case 'r':
android_open_mode = AndroidStorage::AndroidOpenMode::READ;
android_open_mode = AndroidUtils::AndroidOpenMode::READ;
break;
case 'w':
android_open_mode = AndroidStorage::AndroidOpenMode::WRITE;
android_open_mode = AndroidUtils::AndroidOpenMode::WRITE;
o = O_TRUNC;
break;
case 'a':
android_open_mode = AndroidStorage::AndroidOpenMode::WRITE;
android_open_mode = AndroidUtils::AndroidOpenMode::WRITE;
o = O_APPEND;
break;
}
// [rwa]\+ or [rwa]b\+ means read and write
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;
@ -67,7 +67,7 @@ void InitJNI(JNIEnv* env, jclass clazz) {
#define F(JMethodID, JMethodName, Signature) \
JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature);
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
ANDROID_JNI_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
@ -78,7 +78,7 @@ void CleanupJNI() {
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
#define F(JMethodID) JMethodID = nullptr;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
ANDROID_JNI_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
@ -199,6 +199,16 @@ std::string GetBuildFlavor() {
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,
const std::string& destination_filename) {
if (copy_file == nullptr) {
@ -268,14 +278,14 @@ bool MoveAndRenameFile(const std::string& src_full_path, const std::string& dest
bool result;
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 (src_filename == dest_filename || src_parent_path == dest_parent_path) {
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) {
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.
const auto uuid = boost::uuids::to_string(boost::uuids::time_generator_v7()());
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.
// 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) {
// 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.
AndroidStorage::DeleteDocument(dest_full_path);
AndroidUtils::DeleteDocument(dest_full_path);
// Step 5: Attempt to move file to desired location.
// 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) {
AndroidStorage::MoveAndRenameFile((allocated_tmp_path + "/" + dest_filename),
src_full_path);
AndroidUtils::MoveAndRenameFile((allocated_tmp_path + "/" + dest_filename),
src_full_path);
}
}
// Step 6: Clean up the allocated temp directory.
AndroidStorage::DeleteDocument(allocated_tmp_path);
AndroidUtils::DeleteDocument(allocated_tmp_path);
return result;
}
@ -326,7 +336,7 @@ std::string TranslateFilePath(const std::string& filepath) {
}
bool CanUseRawFS() {
return AndroidStorage::GetBuildFlavor() != AndroidBuildFlavors::GOOGLEPLAY;
return AndroidUtils::GetBuildFlavor() != AndroidBuildFlavors::GOOGLEPLAY;
}
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
@ -344,5 +354,5 @@ ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F
#undef FR
} // namespace AndroidStorage
} // namespace AndroidUtils
#endif

View file

@ -10,7 +10,7 @@
#include <fcntl.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, \
"createFile", "(Ljava/lang/String;Ljava/lang/String;)Z") \
V(CreateDir, bool, (const std::string& directory, const std::string& filename), create_dir, \
@ -32,6 +32,8 @@
update_document_location, "updateDocumentLocation", \
"(Ljava/lang/String;Ljava/lang/String;)Z") \
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, \
(const std::string& filename, const std::string& source_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(DeleteDocument, bool, delete_document, CallStaticBooleanMethod, "deleteDocument", \
"(Ljava/lang/String;)Z")
namespace AndroidStorage {
namespace AndroidUtils {
static JavaVM* g_jvm = 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 F(JMethodID) static jmethodID JMethodID = nullptr;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
ANDROID_JNI_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
@ -91,7 +93,7 @@ void CleanupJNI();
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
F(FunctionName, Parameters, ReturnValue)
#define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters;
ANDROID_STORAGE_FUNCTIONS(FS)
ANDROID_JNI_FUNCTIONS(FS)
#undef F
#undef FS
@ -102,5 +104,5 @@ ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F
#undef FR
} // namespace AndroidStorage
} // namespace AndroidUtils
#endif

View file

@ -83,7 +83,7 @@ typedef struct stat file_stat_t;
#endif
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
#include "common/android_storage.h"
#include "common/android_utils.h"
#include "common/string_util.h"
#endif
@ -168,11 +168,11 @@ bool Exists(const std::string& filename) {
int result = _wstat64(Common::UTF8ToUTF16W(copy).c_str(), &file_info);
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
int result;
if (AndroidStorage::CanUseRawFS()) {
if (AndroidUtils::CanUseRawFS()) {
struct stat file_info;
result = stat(AndroidStorage::TranslateFilePath(copy).c_str(), &file_info);
result = stat(AndroidUtils::TranslateFilePath(copy).c_str(), &file_info);
} else {
result = AndroidStorage::FileExists(filename) ? 0 : -1;
result = AndroidUtils::FileExists(filename) ? 0 : -1;
}
#else
struct stat file_info;
@ -197,10 +197,10 @@ bool IsDirectory(const std::string& filename) {
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
struct stat file_info;
int result;
if (AndroidStorage::CanUseRawFS()) {
result = stat(AndroidStorage::TranslateFilePath(copy).c_str(), &file_info);
if (AndroidUtils::CanUseRawFS()) {
result = stat(AndroidUtils::TranslateFilePath(copy).c_str(), &file_info);
} else {
return AndroidStorage::IsDirectory(filename);
return AndroidUtils::IsDirectory(filename);
}
#else
struct stat file_info;
@ -260,13 +260,13 @@ bool Delete(const std::string& filepath) {
return false;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
if (unlink(AndroidStorage::TranslateFilePath(filepath).c_str()) == -1) {
if (AndroidUtils::CanUseRawFS()) {
if (unlink(AndroidUtils::TranslateFilePath(filepath).c_str()) == -1) {
LOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filepath, GetLastErrorMsg());
return false;
}
} else {
if (!AndroidStorage::DeleteDocument(filepath)) {
if (!AndroidUtils::DeleteDocument(filepath)) {
LOG_ERROR(Common_Filesystem, "unlink failed on {}", filepath);
return false;
}
@ -294,8 +294,8 @@ bool CreateDir(const std::string& path) {
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
return false;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
if (mkdir(AndroidStorage::TranslateFilePath(path).c_str(), 0755) == 0)
if (AndroidUtils::CanUseRawFS()) {
if (mkdir(AndroidUtils::TranslateFilePath(path).c_str(), 0755) == 0)
return true;
int err = errno;
@ -320,7 +320,7 @@ bool CreateDir(const std::string& path) {
if (directory.empty()) {
directory = "/";
}
if (!AndroidStorage::CreateDir(directory, filename)) {
if (!AndroidUtils::CreateDir(directory, filename)) {
LOG_ERROR(Common_Filesystem, "mkdir failed on {}", path);
return false;
};
@ -397,11 +397,11 @@ bool DeleteDir(const std::string& filename) {
if (::RemoveDirectoryW(Common::UTF8ToUTF16W(filename).c_str()))
return true;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
if (rmdir(AndroidStorage::TranslateFilePath(filename).c_str()) == 0)
if (AndroidUtils::CanUseRawFS()) {
if (rmdir(AndroidUtils::TranslateFilePath(filename).c_str()) == 0)
return true;
} else {
if (AndroidStorage::DeleteDocument(filename))
if (AndroidUtils::DeleteDocument(filename))
return true;
}
#else
@ -421,13 +421,13 @@ bool Rename(const std::string& srcFullPath, const std::string& destFullPath) {
return true;
}
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
if (rename(AndroidStorage::TranslateFilePath(srcFullPath).c_str(),
AndroidStorage::TranslateFilePath(destFullPath).c_str()) == 0) {
if (AndroidUtils::CanUseRawFS()) {
if (rename(AndroidUtils::TranslateFilePath(srcFullPath).c_str(),
AndroidUtils::TranslateFilePath(destFullPath).c_str()) == 0) {
return true;
}
} else {
if (AndroidStorage::MoveAndRenameFile(srcFullPath, destFullPath)) {
if (AndroidUtils::MoveAndRenameFile(srcFullPath, destFullPath)) {
return true;
}
}
@ -496,12 +496,12 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
};
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
return copy_files(AndroidStorage::TranslateFilePath(srcFilename),
AndroidStorage::TranslateFilePath(destFilename));
if (AndroidUtils::CanUseRawFS()) {
return copy_files(AndroidUtils::TranslateFilePath(srcFilename),
AndroidUtils::TranslateFilePath(destFilename));
} else {
return AndroidStorage::CopyFile(srcFilename, std::string(GetParentPath(destFilename)),
std::string(GetFilename(destFilename)));
return AndroidUtils::CopyFile(srcFilename, std::string(GetParentPath(destFilename)),
std::string(GetFilename(destFilename)));
}
#else
return copy_files(srcFilename, destFilename);
@ -526,12 +526,12 @@ u64 GetSize(const std::string& filename) {
struct _stat64 buf;
if (_wstat64(Common::UTF8ToUTF16W(filename).c_str(), &buf) == 0)
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
if (stat(AndroidStorage::TranslateFilePath(filename).c_str(), &buf) == 0) {
if (AndroidUtils::CanUseRawFS()) {
if (stat(AndroidUtils::TranslateFilePath(filename).c_str(), &buf) == 0) {
return buf.st_size;
}
} else {
u64 result = AndroidStorage::GetSize(filename);
u64 result = AndroidUtils::GetSize(filename);
LOG_TRACE(Common_Filesystem, "{}: {}", filename, result);
return result;
}
@ -608,10 +608,10 @@ std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string&
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string& directory) {
if (AndroidStorage::CanUseRawFS()) {
if (AndroidUtils::CanUseRawFS()) {
std::vector<std::string> entries;
DIR* dirp = opendir(AndroidStorage::TranslateFilePath(directory).c_str());
DIR* dirp = opendir(AndroidUtils::TranslateFilePath(directory).c_str());
if (!dirp)
return std::nullopt;
@ -622,7 +622,7 @@ std::optional<std::vector<std::string>> ListDirectoryEntries(const std::string&
closedir(dirp);
return entries;
} else {
return AndroidStorage::GetFilesName(directory);
return AndroidUtils::GetFilesName(directory);
}
}
@ -1354,27 +1354,27 @@ bool IOFile::Open() {
m_good = m_file != nullptr;
#elif defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (AndroidStorage::CanUseRawFS()) {
m_file = FOPEN(AndroidStorage::TranslateFilePath(filename).c_str(), openmode.c_str());
if (AndroidUtils::CanUseRawFS()) {
m_file = FOPEN(AndroidUtils::TranslateFilePath(filename).c_str(), openmode.c_str());
} else {
// Check whether filepath is startsWith content
AndroidStorage::AndroidOpenMode android_open_mode = AndroidStorage::ParseOpenmode(openmode);
if (android_open_mode == AndroidStorage::AndroidOpenMode::WRITE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE ||
android_open_mode == AndroidStorage::AndroidOpenMode::WRITE_APPEND ||
android_open_mode == AndroidStorage::AndroidOpenMode::WRITE_TRUNCATE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE_TRUNCATE ||
android_open_mode == AndroidStorage::AndroidOpenMode::READ_WRITE_APPEND) {
AndroidUtils::AndroidOpenMode android_open_mode = AndroidUtils::ParseOpenmode(openmode);
if (android_open_mode == AndroidUtils::AndroidOpenMode::WRITE ||
android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE ||
android_open_mode == AndroidUtils::AndroidOpenMode::WRITE_APPEND ||
android_open_mode == AndroidUtils::AndroidOpenMode::WRITE_TRUNCATE ||
android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE_TRUNCATE ||
android_open_mode == AndroidUtils::AndroidOpenMode::READ_WRITE_APPEND) {
if (!FileUtil::Exists(filename)) {
std::string directory(GetParentPath(filename));
std::string display_name(GetFilename(filename));
if (!AndroidStorage::CreateFile(directory, display_name)) {
if (!AndroidUtils::CreateFile(directory, display_name)) {
m_good = m_file != nullptr;
return m_good;
}
}
}
m_fd = AndroidStorage::OpenContentUri(filename, android_open_mode);
m_fd = AndroidUtils::OpenContentUri(filename, android_open_mode);
if (m_fd != -1) {
int error_num = 0;
m_file = fdopen(m_fd, openmode.c_str());

View file

@ -35,7 +35,7 @@
#include "common/string_util.h"
#endif
#if defined(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
#include "android_storage.h"
#include "android_utils.h"
#endif
#ifdef HAVE_LIBRETRO_VFS
@ -443,7 +443,7 @@ public:
return fileno(filestream_get_vfs_handle(m_file)->fp);
#else
#ifdef ANDROID
if (!AndroidStorage::CanUseRawFS()) {
if (!AndroidUtils::CanUseRawFS()) {
return m_fd;
}
#endif // ANDROID

View file

@ -5,6 +5,9 @@
#include <string_view>
#include <utility>
#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/settings.h"
@ -243,6 +246,17 @@ void RestoreGlobalState(bool is_powered_on) {
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) {
Settings::values.current_input_profile = Settings::values.input_profiles[index];
Settings::values.current_input_profile_index = index;

View file

@ -685,6 +685,9 @@ void LogSettings();
// Restore the global state of all applicable settings in the Values struct
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
void LoadProfile(int index);
void SaveProfile(int index);

View file

@ -18,7 +18,7 @@ RendererBase::RendererBase(Core::System& system_, Frontend::EmuWindow& window,
RendererBase::~RendererBase() = default;
u32 RendererBase::GetResolutionScaleFactor() {
const auto graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::GetWorkingGraphicsAPI();
if (graphics_api == Settings::GraphicsAPI::Software) {
// Software renderer always render at native resolution
return 1;

View file

@ -25,7 +25,7 @@ namespace VideoCore {
std::unique_ptr<RendererBase> CreateRenderer(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window,
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) {
#ifdef ENABLE_SOFTWARE_RENDERER
case Settings::GraphicsAPI::Software: