diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | 2 | ||||
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt | 8 | ||||
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt | 4 | ||||
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | 11 | ||||
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt | 26 | ||||
-rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt | 4 | ||||
-rw-r--r-- | src/android/app/src/main/jni/native.cpp | 20 | ||||
-rw-r--r-- | src/core/loader/nro.cpp | 13 | ||||
-rw-r--r-- | src/core/loader/nro.h | 2 | ||||
-rw-r--r-- | src/yuzu/configuration/config.cpp | 6 | ||||
-rw-r--r-- | src/yuzu/configuration/config.h | 1 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 8 |
12 files changed, 79 insertions, 26 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index c11b6bc16..22af9e435 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -223,6 +223,8 @@ object NativeLibrary { external fun getCompany(filename: String): String + external fun isHomebrew(filename: String): Boolean + external fun setAppDirectory(directory: String) external fun initializeGpuDriver( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt index ebc0f164a..adbe3696b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt @@ -127,13 +127,7 @@ class SearchFragment : Fragment() { } } - R.id.chip_homebrew -> { - baseList.filter { - Log.error("Guh - ${it.path}") - FileUtil.hasExtension(it.path, "nro") - || FileUtil.hasExtension(it.path, "nso") - } - } + R.id.chip_homebrew -> baseList.filter { it.isHomebrew } R.id.chip_retail -> baseList.filter { FileUtil.hasExtension(it.path, "xci") diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index 2a17653b2..3d6782c49 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt @@ -16,7 +16,8 @@ class Game( val regions: String, val path: String, val gameId: String, - val company: String + val company: String, + val isHomebrew: Boolean ) : Parcelable { val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" val keyLastPlayedTime get() = "${gameId}_LastPlayed" @@ -31,6 +32,7 @@ class Game( && path == other.path && gameId == other.gameId && company == other.company + && isHomebrew == other.isHomebrew } companion object { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index 7059856f1..d9b301210 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt @@ -13,6 +13,8 @@ import androidx.preference.PreferenceManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.MissingFieldException import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import org.yuzu.yuzu_emu.NativeLibrary @@ -20,6 +22,7 @@ import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.utils.GameHelper import java.util.Locale +@OptIn(ExperimentalSerializationApi::class) class GamesViewModel : ViewModel() { private val _games = MutableLiveData<List<Game>>(emptyList()) val games: LiveData<List<Game>> get() = _games @@ -49,7 +52,13 @@ class GamesViewModel : ViewModel() { if (storedGames!!.isNotEmpty()) { val deserializedGames = mutableSetOf<Game>() storedGames.forEach { - val game: Game = Json.decodeFromString(it) + val game: Game + try { + game = Json.decodeFromString(it) + } catch (e: MissingFieldException) { + return@forEach + } + val gameExists = DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path)) ?.exists() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt index c9f5797ac..aa424c768 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt @@ -765,18 +765,20 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context // If we have API access, calculate the safe area to draw the overlay var cutoutLeft = 0 var cutoutBottom = 0 - val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout - if (insets != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2) - insets.boundingRectTop.bottom.toFloat() else maxY - if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2) - insets.boundingRectRight.left.toFloat() else maxX - - minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left - minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom - - cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left - cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout + if (insets != null) { + if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2) + insets.boundingRectTop.bottom.toFloat() else maxY + if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2) + insets.boundingRectRight.left.toFloat() else maxX + + minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left + minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom + + cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left + cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom + } } // This makes sure that if we have an inset on one side of the screen, we mirror it on diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index ba6b5783e..42b207618 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt @@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils import android.content.SharedPreferences import android.net.Uri import androidx.preference.PreferenceManager -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.yuzu.yuzu_emu.NativeLibrary @@ -83,7 +82,8 @@ object GameHelper { NativeLibrary.getRegions(filePath), filePath, gameId, - NativeLibrary.getCompany(filePath) + NativeLibrary.getCompany(filePath), + NativeLibrary.isHomebrew(filePath) ) val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L) diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index b87e04b3d..03cb0b74b 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -13,6 +13,7 @@ #include <android/api-level.h> #include <android/native_window_jni.h> +#include <core/loader/nro.h> #include "common/detached_tasks.h" #include "common/dynamic_library.h" @@ -281,6 +282,10 @@ public: return GetRomMetadata(path).icon; } + bool GetIsHomebrew(const std::string& path) { + return GetRomMetadata(path).isHomebrew; + } + void ResetRomMetadata() { m_rom_metadata_cache.clear(); } @@ -348,6 +353,7 @@ private: struct RomMetadata { std::string title; std::vector<u8> icon; + bool isHomebrew; }; RomMetadata GetRomMetadata(const std::string& path) { @@ -360,11 +366,17 @@ private: RomMetadata CacheRomMetadata(const std::string& path) { const auto file = Core::GetGameFileFromPath(m_vfs, path); - const auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); + auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); RomMetadata entry; loader->ReadTitle(entry.title); loader->ReadIcon(entry.icon); + if (loader->GetFileType() == Loader::FileType::NRO) { + auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); + entry.isHomebrew = loader_nro->IsHomebrew(); + } else { + entry.isHomebrew = false; + } m_rom_metadata_cache[path] = entry; @@ -662,6 +674,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv return env->NewStringUTF(""); } +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jclass clazz, + [[maybe_unused]] jstring j_filename) { + return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); +} + void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { // Create the default config.ini. diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 73d04d7ee..7be6cf5f3 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s struct NroHeader { INSERT_PADDING_BYTES(0x4); u32_le module_header_offset; - INSERT_PADDING_BYTES(0x8); + u32 magic_ext1; + u32 magic_ext2; u32_le magic; INSERT_PADDING_BYTES(0x4); u32_le file_size; @@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) { return FileType::Error; } +bool AppLoader_NRO::IsHomebrew() { + // Read NSO header + NroHeader nro_header{}; + if (sizeof(NroHeader) != file->ReadObject(&nro_header)) { + return false; + } + return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') && + nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W'); +} + static constexpr u32 PageAlignSize(u32 size) { return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); } diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index ccb77b581..8de6eebc6 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -38,6 +38,8 @@ public: */ static FileType IdentifyType(const FileSys::VirtualFile& nro_file); + bool IsHomebrew(); + FileType GetFileType() const override { return IdentifyType(file); } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7168630d8..bac9dff90 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -101,6 +101,12 @@ const std::map<Settings::RendererBackend, QString> Config::renderer_backend_text {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, }; +const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = { + {Settings::ShaderBackend::GLSL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, + {Settings::ShaderBackend::GLASM, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, + {Settings::ShaderBackend::SPIRV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, +}; + // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index ad590ea9e..0fd4baf6b 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -54,6 +54,7 @@ public: static const std::map<bool, QString> use_docked_mode_texts_map; static const std::map<Settings::GPUAccuracy, QString> gpu_accuracy_texts_map; static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map; + static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map; static constexpr UISettings::Theme default_theme{ #ifdef _WIN32 diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 145fea5f1..9d06b21b6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4116,7 +4116,13 @@ void GMainWindow::UpdateDockedButton() { void GMainWindow::UpdateAPIText() { const auto api = Settings::values.renderer_backend.GetValue(); const auto renderer_status_text = Config::renderer_backend_texts_map.find(api)->second; - renderer_status_button->setText(renderer_status_text.toUpper()); + renderer_status_button->setText( + api == Settings::RendererBackend::OpenGL + ? tr("%1 %2").arg( + renderer_status_text.toUpper(), + Config::shader_backend_texts_map.find(Settings::values.shader_backend.GetValue()) + ->second) + : renderer_status_text.toUpper()); } void GMainWindow::UpdateFilterText() { |