Compare commits
108 Commits
android-20
...
android-21
Author | SHA1 | Date | |
---|---|---|---|
82359e986c | |||
5862b1df55 | |||
0da5c3912d | |||
fcae200396 | |||
ad63c5dc0e | |||
386bbc6495 | |||
d5e8c9d04f | |||
3f1290cee3 | |||
ce2eb6e8ee | |||
8b47465586 | |||
3065ab0fd8 | |||
a2407a2964 | |||
16b79df836 | |||
6a4b25699d | |||
bd8635e26a | |||
4349cdba07 | |||
f2fb761bac | |||
59aee2b461 | |||
4d206d849e | |||
744c0173d1 | |||
55482ab5dc | |||
e56b44dee6 | |||
f2012e5aff | |||
4526fdaf64 | |||
bc22b4e782 | |||
f70821ce0d | |||
a774ff935c | |||
431df5ae93 | |||
677c2c2cd2 | |||
ee540c712c | |||
d23c4393fd | |||
b24a111136 | |||
91636deaaf | |||
68cbf67f4c | |||
645961613f | |||
53b321c945 | |||
975deb7528 | |||
2c049ae06d | |||
54372fdff5 | |||
c60ab6bbf6 | |||
cc09c265e1 | |||
0f9288e38d | |||
06fb7f90da | |||
e04368ad7c | |||
3e2d3548f2 | |||
eb9036d75b | |||
01a2d978eb | |||
6e67b25af9 | |||
e91667ba75 | |||
d45561ace0 | |||
0fdd6e8934 | |||
35794f4f18 | |||
b8be8dff69 | |||
bc317a9807 | |||
97ca160b08 | |||
1a3fc3724a | |||
7b01454d5f | |||
f3749394ac | |||
807f421752 | |||
e4915fb7d2 | |||
a76f6a2775 | |||
ba518f6899 | |||
ad4622da2c | |||
3b1c2896d9 | |||
fc5d76e6e2 | |||
5f9a45ada9 | |||
a120f8ff4d | |||
96833cd809 | |||
8649a80071 | |||
550cadbee4 | |||
8bd10473d6 | |||
8d708b0c79 | |||
beaab10c8f | |||
889c5d2705 | |||
17b0aac809 | |||
399220ddbc | |||
59080a3d1d | |||
3a25a217e6 | |||
961b5586a5 | |||
57ff934f0d | |||
92ce9273ee | |||
dd36d43ea1 | |||
a7a7720752 | |||
c725f3c86c | |||
1b984738ab | |||
748465f5a5 | |||
04867e2456 | |||
32f623e029 | |||
b6c6534c30 | |||
beb438bb0b | |||
4b963ca8a5 | |||
648ed55fe6 | |||
23430e6772 | |||
0672847330 | |||
a874ab0133 | |||
590d9b7e1d | |||
b0bca0f8b0 | |||
d8f1ce2f76 | |||
9b11b9dce5 | |||
303cd31162 | |||
0adc09e0af | |||
96fd1348ae | |||
bad705f245 | |||
34a8d0cc8e | |||
0a2536a0df | |||
c85d7ccd79 | |||
7a9d1ad2f8 | |||
2f0418c101 |
@ -155,3 +155,7 @@ License: MIT
|
||||
Files: externals/gamemode/*
|
||||
Copyright: Copyright 2017-2019 Feral Interactive
|
||||
License: BSD-3-Clause
|
||||
|
||||
Files: src/android/app/debug.keystore
|
||||
Copyright: 2023 yuzu Emulator Project
|
||||
License: GPL-3.0-or-later
|
||||
|
@ -2,18 +2,20 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_path(SimpleIni_INCLUDE_DIR SimpleIni.h)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SimpleIni
|
||||
REQUIRED_VARS SimpleIni_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni)
|
||||
add_library(SimpleIni::SimpleIni INTERFACE IMPORTED)
|
||||
set_target_properties(SimpleIni::SimpleIni PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${SimpleIni_INCLUDE_DIR}"
|
||||
find_package(SimpleIni QUIET CONFIG)
|
||||
if (SimpleIni_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(SimpleIni CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(SIMPLEINI QUIET IMPORTED_TARGET simpleini)
|
||||
find_package_handle_standard_args(SimpleIni
|
||||
REQUIRED_VARS SIMPLEINI_INCLUDEDIR
|
||||
VERSION_VAR SIMPLEINI_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(SimpleIni_INCLUDE_DIR)
|
||||
if (SimpleIni_FOUND AND NOT TARGET SimpleIni::SimpleIni)
|
||||
add_library(SimpleIni::SimpleIni ALIAS PkgConfig::SIMPLEINI)
|
||||
endif()
|
||||
|
13
README.md
13
README.md
@ -1,3 +1,16 @@
|
||||
| Pull Request | Commit | Title | Author | Merged? |
|
||||
|----|----|----|----|----|
|
||||
| [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`e3171486d`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12760](https://github.com/yuzu-emu/yuzu-android//pull/12760) | [`53f17ede1`](https://github.com/yuzu-emu/yuzu-android//pull/12760/files) | am: rewrite for multiprocess support | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12802](https://github.com/yuzu-emu/yuzu-android//pull/12802) | [`c5e88c654`](https://github.com/yuzu-emu/yuzu-android//pull/12802/files) | service: mii: Migrate service to new interface | [german77](https://github.com/german77/) | Yes |
|
||||
| [12826](https://github.com/yuzu-emu/yuzu-android//pull/12826) | [`2d8f80b65`](https://github.com/yuzu-emu/yuzu-android//pull/12826/files) | android: Show system driver information | [t895](https://github.com/t895/) | Yes |
|
||||
| [12827](https://github.com/yuzu-emu/yuzu-android//pull/12827) | [`c770af9b1`](https://github.com/yuzu-emu/yuzu-android//pull/12827/files) | android: Disable focus on loading card | [t895](https://github.com/t895/) | Yes |
|
||||
|
||||
|
||||
End of merge log. You can find the original README.md below the break.
|
||||
|
||||
-----
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
3
externals/CMakeLists.txt
vendored
3
externals/CMakeLists.txt
vendored
@ -178,6 +178,9 @@ if (NOT TARGET stb::headers)
|
||||
add_library(stb::headers ALIAS stb)
|
||||
endif()
|
||||
|
||||
add_library(tz tz/tz/tz.cpp)
|
||||
target_include_directories(tz PUBLIC ./tz)
|
||||
|
||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
||||
|
||||
|
2
externals/nx_tzdb/CMakeLists.txt
vendored
2
externals/nx_tzdb/CMakeLists.txt
vendored
@ -32,7 +32,7 @@ set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
|
||||
|
||||
if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ARCHIVE})
|
||||
if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR})
|
||||
set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...")
|
||||
|
4
externals/nx_tzdb/NxTzdbCreateHeader.cmake
vendored
4
externals/nx_tzdb/NxTzdbCreateHeader.cmake
vendored
@ -11,6 +11,10 @@ execute_process(
|
||||
WORKING_DIRECTORY ${ZONE_PATH}
|
||||
OUTPUT_VARIABLE FILE_LIST)
|
||||
|
||||
if (NOT FILE_LIST)
|
||||
message(FATAL_ERROR "No timezone files found in directory ${ZONE_PATH}, did the download fail?")
|
||||
endif()
|
||||
|
||||
set(DIRECTORY_NAME ${HEADER_NAME})
|
||||
|
||||
set(FILE_DATA "")
|
||||
|
1636
externals/tz/tz/tz.cpp
vendored
Normal file
1636
externals/tz/tz/tz.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
externals/tz/tz/tz.h
vendored
Normal file
81
externals/tz/tz/tz.h
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: 1996 Arthur David Olson
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <array>
|
||||
#include <time.h>
|
||||
|
||||
namespace Tz {
|
||||
using u8 = uint8_t;
|
||||
using s8 = int8_t;
|
||||
using u16 = uint16_t;
|
||||
using s16 = int16_t;
|
||||
using u32 = uint32_t;
|
||||
using s32 = int32_t;
|
||||
using u64 = uint64_t;
|
||||
using s64 = int64_t;
|
||||
|
||||
constexpr size_t TZ_MAX_TIMES = 1000;
|
||||
constexpr size_t TZ_MAX_TYPES = 128;
|
||||
constexpr size_t TZ_MAX_CHARS = 50;
|
||||
constexpr size_t MY_TZNAME_MAX = 255;
|
||||
constexpr size_t TZNAME_MAXIMUM = 255;
|
||||
constexpr size_t TZ_MAX_LEAPS = 50;
|
||||
constexpr s64 TIME_T_MAX = std::numeric_limits<s64>::max();
|
||||
constexpr s64 TIME_T_MIN = std::numeric_limits<s64>::min();
|
||||
constexpr size_t CHARS_EXTRA = 3;
|
||||
constexpr size_t MAX_ZONE_CHARS = std::max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof("UTC"));
|
||||
constexpr size_t MAX_TZNAME_CHARS = 2 * (MY_TZNAME_MAX + 1);
|
||||
|
||||
struct ttinfo {
|
||||
s32 tt_utoff;
|
||||
bool tt_isdst;
|
||||
s32 tt_desigidx;
|
||||
bool tt_ttisstd;
|
||||
bool tt_ttisut;
|
||||
};
|
||||
static_assert(sizeof(ttinfo) == 0x10, "ttinfo has the wrong size!");
|
||||
|
||||
struct Rule {
|
||||
s32 timecnt;
|
||||
s32 typecnt;
|
||||
s32 charcnt;
|
||||
bool goback;
|
||||
bool goahead;
|
||||
std::array <u8, 0x2> padding0;
|
||||
std::array<s64, TZ_MAX_TIMES> ats;
|
||||
std::array<u8, TZ_MAX_TIMES> types;
|
||||
std::array<ttinfo, TZ_MAX_TYPES> ttis;
|
||||
std::array<char, std::max(MAX_ZONE_CHARS, MAX_TZNAME_CHARS)> chars;
|
||||
s32 defaulttype;
|
||||
std::array <u8, 0x12C4> padding1;
|
||||
};
|
||||
static_assert(sizeof(Rule) == 0x4000, "Rule has the wrong size!");
|
||||
|
||||
struct CalendarTimeInternal {
|
||||
s32 tm_sec;
|
||||
s32 tm_min;
|
||||
s32 tm_hour;
|
||||
s32 tm_mday;
|
||||
s32 tm_mon;
|
||||
s32 tm_year;
|
||||
s32 tm_wday;
|
||||
s32 tm_yday;
|
||||
s32 tm_isdst;
|
||||
std::array<char, 16> tm_zone;
|
||||
s32 tm_utoff;
|
||||
s32 time_index;
|
||||
};
|
||||
static_assert(sizeof(CalendarTimeInternal) == 0x3C, "CalendarTimeInternal has the wrong size!");
|
||||
|
||||
s32 ParseTimeZoneBinary(Rule& out_rule, std::span<const u8> binary);
|
||||
|
||||
bool localtime_rz(CalendarTimeInternal* tmp, Rule* sp, time_t* timep);
|
||||
u32 mktime_tzname(time_t* out_time, Rule* sp, CalendarTimeInternal* tmp);
|
||||
|
||||
} // namespace Tz
|
@ -82,8 +82,8 @@ android {
|
||||
}
|
||||
|
||||
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
|
||||
if (keystoreFile != null) {
|
||||
signingConfigs {
|
||||
signingConfigs {
|
||||
if (keystoreFile != null) {
|
||||
create("release") {
|
||||
storeFile = file(keystoreFile)
|
||||
storePassword = System.getenv("ANDROID_KEYSTORE_PASS")
|
||||
@ -91,6 +91,12 @@ android {
|
||||
keyPassword = System.getenv("ANDROID_KEYSTORE_PASS")
|
||||
}
|
||||
}
|
||||
create("default") {
|
||||
storeFile = file("$projectDir/debug.keystore")
|
||||
storePassword = "android"
|
||||
keyAlias = "androiddebugkey"
|
||||
keyPassword = "android"
|
||||
}
|
||||
}
|
||||
|
||||
// Define build types, which are orthogonal to product flavors.
|
||||
@ -101,7 +107,7 @@ android {
|
||||
signingConfig = if (keystoreFile != null) {
|
||||
signingConfigs.getByName("release")
|
||||
} else {
|
||||
signingConfigs.getByName("debug")
|
||||
signingConfigs.getByName("default")
|
||||
}
|
||||
|
||||
resValue("string", "app_name_suffixed", "yuzu")
|
||||
@ -118,7 +124,7 @@ android {
|
||||
register("relWithDebInfo") {
|
||||
isDefault = true
|
||||
resValue("string", "app_name_suffixed", "yuzu Debug Release")
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
signingConfig = signingConfigs.getByName("default")
|
||||
isMinifyEnabled = true
|
||||
isDebuggable = true
|
||||
proguardFiles(
|
||||
@ -133,6 +139,7 @@ android {
|
||||
// Signed by debug key disallowing distribution on Play Store.
|
||||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||
debug {
|
||||
signingConfig = signingConfigs.getByName("default")
|
||||
resValue("string", "app_name_suffixed", "yuzu Debug")
|
||||
isDebuggable = true
|
||||
isJniDebuggable = true
|
||||
|
BIN
src/android/app/debug.keystore
Normal file
BIN
src/android/app/debug.keystore
Normal file
Binary file not shown.
@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
|
||||
import org.yuzu.yuzu_emu.model.InstallResult
|
||||
import org.yuzu.yuzu_emu.model.Patch
|
||||
import org.yuzu.yuzu_emu.model.GameVerificationResult
|
||||
|
||||
/**
|
||||
* Class which contains methods that interact
|
||||
@ -260,7 +261,7 @@ object NativeLibrary {
|
||||
/**
|
||||
* Begins emulation.
|
||||
*/
|
||||
external fun run(path: String?)
|
||||
external fun run(path: String?, programIndex: Int = 0)
|
||||
|
||||
// Surface Handling
|
||||
external fun surfaceChanged(surf: Surface?)
|
||||
@ -302,6 +303,11 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun getCpuBackend(): String
|
||||
|
||||
/**
|
||||
* Returns the current GPU Driver.
|
||||
*/
|
||||
external fun getGpuDriver(): String
|
||||
|
||||
external fun applySettings()
|
||||
|
||||
external fun logSettings()
|
||||
@ -483,6 +489,12 @@ object NativeLibrary {
|
||||
sEmulationActivity.get()!!.onEmulationStopped(status)
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun onProgramChanged(programIndex: Int) {
|
||||
sEmulationActivity.get()!!.onProgramChanged(programIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the Yuzu version, Android version and, CPU.
|
||||
*/
|
||||
@ -564,6 +576,26 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun removeMod(programId: String, name: String)
|
||||
|
||||
/**
|
||||
* Verifies all installed content
|
||||
* @param callback UI callback for verification progress. Return true in the callback to cancel.
|
||||
* @return Array of content that failed verification. Successful if empty.
|
||||
*/
|
||||
external fun verifyInstalledContents(
|
||||
callback: (max: Long, progress: Long) -> Boolean
|
||||
): Array<String>
|
||||
|
||||
/**
|
||||
* Verifies the contents of a game
|
||||
* @param path String path to a game
|
||||
* @param callback UI callback for verification progress. Return true in the callback to cancel.
|
||||
* @return Int that is meant to be converted to a [GameVerificationResult]
|
||||
*/
|
||||
external fun verifyGameContents(
|
||||
path: String,
|
||||
callback: (max: Long, progress: Long) -> Boolean
|
||||
): Int
|
||||
|
||||
/**
|
||||
* Gets the save location for a specific game
|
||||
*
|
||||
@ -593,6 +625,11 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun clearFilesystemProvider()
|
||||
|
||||
/**
|
||||
* Checks if all necessary keys are present for decryption
|
||||
*/
|
||||
external fun areKeysPresent(): Boolean
|
||||
|
||||
/**
|
||||
* Button type for use in onTouchEvent
|
||||
*/
|
||||
|
@ -76,7 +76,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
|
||||
override fun onDestroy() {
|
||||
stopForegroundService(this)
|
||||
emulationViewModel.clear()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@ -193,6 +192,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
if (emulationViewModel.drawerOpen.value) {
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
return InputHandler.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
@ -203,6 +206,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
return super.dispatchGenericMotionEvent(event)
|
||||
}
|
||||
|
||||
if (emulationViewModel.drawerOpen.value) {
|
||||
return super.dispatchGenericMotionEvent(event)
|
||||
}
|
||||
|
||||
// Don't attempt to do anything if we are disconnecting a device.
|
||||
if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
||||
return true
|
||||
@ -438,9 +445,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
}
|
||||
|
||||
fun onEmulationStopped(status: Int) {
|
||||
if (status == 0) {
|
||||
if (status == 0 && emulationViewModel.programChanged.value == -1) {
|
||||
finish()
|
||||
}
|
||||
emulationViewModel.setEmulationStopped(true)
|
||||
}
|
||||
|
||||
fun onProgramChanged(programIndex: Int) {
|
||||
emulationViewModel.setProgramChanged(programIndex)
|
||||
}
|
||||
|
||||
private fun startMotionSensorListener() {
|
||||
|
@ -14,15 +14,20 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
* Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate
|
||||
* code used in every [RecyclerView].
|
||||
* Type assigned to [Model] must inherit from [Object] in order to be compared properly.
|
||||
* @param exact Decides whether each item will be compared by reference or by their contents
|
||||
*/
|
||||
abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> :
|
||||
ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) {
|
||||
abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>>(
|
||||
exact: Boolean = true
|
||||
) : ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>(exact)).build()) {
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) =
|
||||
holder.bind(currentList[position])
|
||||
|
||||
private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() {
|
||||
private class DiffCallback<Model>(val exact: Boolean) : DiffUtil.ItemCallback<Model>() {
|
||||
override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
|
||||
return oldItem === newItem
|
||||
if (exact) {
|
||||
return oldItem === newItem
|
||||
}
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
@SuppressLint("DiffUtilEquals")
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
@ -15,10 +12,6 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -30,7 +23,6 @@ import kotlinx.coroutines.withContext
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.databinding.CardGameBinding
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||
@ -38,7 +30,7 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils
|
||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
||||
|
||||
class GameAdapter(private val activity: AppCompatActivity) :
|
||||
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() {
|
||||
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
|
||||
CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
.also { return GameViewHolder(it) }
|
||||
@ -89,36 +81,13 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||
)
|
||||
.apply()
|
||||
|
||||
val openIntent =
|
||||
Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(game.path)
|
||||
}
|
||||
|
||||
activity.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val layerDrawable = ResourcesCompat.getDrawable(
|
||||
YuzuApplication.appContext.resources,
|
||||
R.drawable.shortcut,
|
||||
null
|
||||
) as LayerDrawable
|
||||
layerDrawable.setDrawableByLayerId(
|
||||
R.id.shortcut_foreground,
|
||||
GameIconUtils.getGameIcon(activity, game)
|
||||
.toDrawable(YuzuApplication.appContext.resources)
|
||||
)
|
||||
val inset = YuzuApplication.appContext.resources
|
||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||
val shortcut =
|
||||
ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
|
||||
.setShortLabel(game.title)
|
||||
.setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
)
|
||||
)
|
||||
.setIntent(openIntent)
|
||||
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
||||
.setIntent(game.launchIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
THEME("theme"),
|
||||
THEME_MODE("theme_mode"),
|
||||
OVERLAY_SCALE("control_scale"),
|
||||
OVERLAY_OPACITY("control_opacity");
|
||||
OVERLAY_OPACITY("control_opacity"),
|
||||
LOCK_DRAWER("lock_drawer");
|
||||
|
||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||
|
||||
|
@ -77,7 +77,7 @@ class AboutFragment : Fragment() {
|
||||
}
|
||||
|
||||
binding.textVersionName.text = BuildConfig.VERSION_NAME
|
||||
binding.textVersionName.setOnClickListener {
|
||||
binding.buttonVersionName.setOnClickListener {
|
||||
val clipBoard =
|
||||
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)
|
||||
|
@ -141,7 +141,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||
retainInstance = true
|
||||
emulationState = EmulationState(game.path)
|
||||
emulationState = EmulationState(game.path) {
|
||||
return@EmulationState driverViewModel.isInteractionAllowed.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,11 +184,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
// No op
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
binding.inGameMenu.requestFocus()
|
||||
emulationViewModel.setDrawerOpen(true)
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
// No op
|
||||
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
|
||||
emulationViewModel.setDrawerOpen(false)
|
||||
}
|
||||
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
@ -196,6 +201,28 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
|
||||
game.title
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
||||
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
||||
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
||||
R.string.unlock_drawer
|
||||
} else {
|
||||
R.string.lock_drawer
|
||||
}
|
||||
val iconId = if (lockMode == DrawerLayout.LOCK_MODE_UNLOCKED) {
|
||||
R.drawable.ic_unlock
|
||||
} else {
|
||||
R.drawable.ic_lock
|
||||
}
|
||||
|
||||
title = getString(titleId)
|
||||
icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
iconId,
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
|
||||
binding.inGameMenu.setNavigationItemSelectedListener {
|
||||
when (it.itemId) {
|
||||
R.id.menu_pause_emulation -> {
|
||||
@ -216,6 +243,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
binding.inGameMenu.requestFocus()
|
||||
true
|
||||
}
|
||||
|
||||
@ -224,6 +252,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
null,
|
||||
Settings.MenuTag.SECTION_ROOT
|
||||
)
|
||||
binding.inGameMenu.requestFocus()
|
||||
binding.root.findNavController().navigate(action)
|
||||
true
|
||||
}
|
||||
@ -233,6 +262,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
args.game,
|
||||
Settings.MenuTag.SECTION_ROOT
|
||||
)
|
||||
binding.inGameMenu.requestFocus()
|
||||
binding.root.findNavController().navigate(action)
|
||||
true
|
||||
}
|
||||
@ -242,11 +272,39 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_lock_drawer -> {
|
||||
when (IntSetting.LOCK_DRAWER.getInt()) {
|
||||
DrawerLayout.LOCK_MODE_UNLOCKED -> {
|
||||
IntSetting.LOCK_DRAWER.setInt(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
it.title = resources.getString(R.string.unlock_drawer)
|
||||
it.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_lock,
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
|
||||
DrawerLayout.LOCK_MODE_LOCKED_CLOSED -> {
|
||||
IntSetting.LOCK_DRAWER.setInt(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
it.title = resources.getString(R.string.lock_drawer)
|
||||
it.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_unlock,
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.inGameMenu.requestFocus()
|
||||
NativeConfig.saveGlobalConfig()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_exit -> {
|
||||
emulationState.stop()
|
||||
NativeConfig.reloadGlobalConfig()
|
||||
emulationViewModel.setIsEmulationStopping(true)
|
||||
binding.drawerLayout.close()
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
binding.inGameMenu.requestFocus()
|
||||
true
|
||||
}
|
||||
|
||||
@ -263,12 +321,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
if (!NativeLibrary.isRunning()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (binding.drawerLayout.isOpen) {
|
||||
binding.drawerLayout.close()
|
||||
} else {
|
||||
binding.drawerLayout.open()
|
||||
}
|
||||
emulationViewModel.setDrawerOpen(!binding.drawerLayout.isOpen)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -322,11 +375,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.isInteractionAllowed.collect {
|
||||
if (it) {
|
||||
startEmulation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
emulationViewModel.emulationStarted.collectLatest {
|
||||
if (it) {
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
|
||||
ViewUtils.showView(binding.surfaceInputOverlay)
|
||||
ViewUtils.hideView(binding.loadingIndicator)
|
||||
|
||||
@ -351,10 +413,41 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.isInteractionAllowed.collect {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
emulationViewModel.drawerOpen.collect {
|
||||
if (it) {
|
||||
onEmulationStart()
|
||||
binding.drawerLayout.open()
|
||||
binding.inGameMenu.requestFocus()
|
||||
} else {
|
||||
binding.drawerLayout.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
emulationViewModel.programChanged.collect {
|
||||
if (it != 0) {
|
||||
emulationViewModel.setEmulationStarted(false)
|
||||
binding.drawerLayout.close()
|
||||
binding.drawerLayout
|
||||
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
ViewUtils.hideView(binding.surfaceInputOverlay)
|
||||
ViewUtils.showView(binding.loadingIndicator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
emulationViewModel.emulationStopped.collect {
|
||||
if (it && emulationViewModel.programChanged.value != -1) {
|
||||
if (perfStatsUpdater != null) {
|
||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
||||
}
|
||||
emulationState.changeProgram(emulationViewModel.programChanged.value)
|
||||
emulationViewModel.setProgramChanged(-1)
|
||||
emulationViewModel.setEmulationStopped(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -362,7 +455,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEmulationStart() {
|
||||
private fun startEmulation(programIndex: Int = 0) {
|
||||
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
DirectoryInitialization.start()
|
||||
@ -370,7 +463,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
updateScreenLayout()
|
||||
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated)
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated, programIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,12 +530,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
val FRAMETIME = 2
|
||||
val SPEED = 3
|
||||
perfStatsUpdater = {
|
||||
if (emulationViewModel.emulationStarted.value) {
|
||||
if (emulationViewModel.emulationStarted.value &&
|
||||
!emulationViewModel.isEmulationStopping.value
|
||||
) {
|
||||
val perfStats = NativeLibrary.getPerfStats()
|
||||
val cpuBackend = NativeLibrary.getCpuBackend()
|
||||
val gpuDriver = NativeLibrary.getGpuDriver()
|
||||
if (_binding != null) {
|
||||
binding.showFpsText.text =
|
||||
String.format("FPS: %.1f\n%s", perfStats[FPS], cpuBackend)
|
||||
String.format("FPS: %.1f\n%s/%s", perfStats[FPS], cpuBackend, gpuDriver)
|
||||
}
|
||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
||||
}
|
||||
@ -759,9 +855,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
private class EmulationState(private val gamePath: String) {
|
||||
private class EmulationState(
|
||||
private val gamePath: String,
|
||||
private val emulationCanStart: () -> Boolean
|
||||
) {
|
||||
private var state: State
|
||||
private var surface: Surface? = null
|
||||
lateinit var emulationThread: Thread
|
||||
|
||||
init {
|
||||
// Starting state is stopped.
|
||||
@ -807,7 +907,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun run(isActivityRecreated: Boolean) {
|
||||
fun run(isActivityRecreated: Boolean, programIndex: Int = 0) {
|
||||
if (isActivityRecreated) {
|
||||
if (NativeLibrary.isRunning()) {
|
||||
state = State.PAUSED
|
||||
@ -818,10 +918,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||
if (surface != null) {
|
||||
runWithValidSurface()
|
||||
runWithValidSurface(programIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun changeProgram(programIndex: Int) {
|
||||
emulationThread.join()
|
||||
emulationThread = Thread({
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||
NativeLibrary.run(gamePath, programIndex)
|
||||
}, "NativeEmulation")
|
||||
emulationThread.start()
|
||||
}
|
||||
|
||||
// Surface callbacks
|
||||
@Synchronized
|
||||
fun newSurface(surface: Surface?) {
|
||||
@ -853,6 +963,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
State.PAUSED -> Log.warning(
|
||||
"[EmulationFragment] Surface cleared while emulation paused."
|
||||
)
|
||||
|
||||
else -> Log.warning(
|
||||
"[EmulationFragment] Surface cleared while emulation stopped."
|
||||
)
|
||||
@ -860,13 +971,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
private fun runWithValidSurface() {
|
||||
private fun runWithValidSurface(programIndex: Int = 0) {
|
||||
NativeLibrary.surfaceChanged(surface)
|
||||
if (!emulationCanStart.invoke()) {
|
||||
return
|
||||
}
|
||||
|
||||
when (state) {
|
||||
State.STOPPED -> {
|
||||
val emulationThread = Thread({
|
||||
emulationThread = Thread({
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||
NativeLibrary.run(gamePath)
|
||||
NativeLibrary.run(gamePath, programIndex)
|
||||
}, "NativeEmulation")
|
||||
emulationThread.start()
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
|
||||
import org.yuzu.yuzu_emu.model.GameVerificationResult
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.utils.GameMetadata
|
||||
|
||||
@ -101,6 +103,38 @@ class GameInfoFragment : Fragment() {
|
||||
""".trimIndent()
|
||||
copyToClipboard(args.game.title, details)
|
||||
}
|
||||
|
||||
buttonVerifyIntegrity.setOnClickListener {
|
||||
ProgressDialogFragment.newInstance(
|
||||
requireActivity(),
|
||||
R.string.verifying,
|
||||
true
|
||||
) { progressCallback, _ ->
|
||||
val result = GameVerificationResult.from(
|
||||
NativeLibrary.verifyGameContents(
|
||||
args.game.path,
|
||||
progressCallback
|
||||
)
|
||||
)
|
||||
return@newInstance when (result) {
|
||||
GameVerificationResult.Success ->
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_success,
|
||||
descriptionId = R.string.operation_completed_successfully
|
||||
)
|
||||
GameVerificationResult.Failed ->
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_failure,
|
||||
descriptionId = R.string.verify_failure_description
|
||||
)
|
||||
GameVerificationResult.NotImplemented ->
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_no_result,
|
||||
descriptionId = R.string.verify_no_result_description
|
||||
)
|
||||
}
|
||||
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
setInsets()
|
||||
|
@ -4,6 +4,8 @@
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
@ -84,6 +86,24 @@ class GamePropertiesFragment : Fragment() {
|
||||
view.findNavController().popBackStack()
|
||||
}
|
||||
|
||||
val shortcutManager = requireActivity().getSystemService(ShortcutManager::class.java)
|
||||
binding.buttonShortcut.isEnabled = shortcutManager.isRequestPinShortcutSupported
|
||||
binding.buttonShortcut.setOnClickListener {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val shortcut = ShortcutInfo.Builder(requireContext(), args.game.title)
|
||||
.setShortLabel(args.game.title)
|
||||
.setIcon(
|
||||
GameIconUtils.getShortcutIcon(requireActivity(), args.game)
|
||||
.toIcon(requireContext())
|
||||
)
|
||||
.setIntent(args.game.launchIntent)
|
||||
.build()
|
||||
shortcutManager.requestPinShortcut(shortcut, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
|
||||
binding.title.text = args.game.title
|
||||
binding.title.postDelayed(
|
||||
|
@ -32,6 +32,7 @@ import org.yuzu.yuzu_emu.BuildConfig
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
|
||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||
@ -140,6 +141,44 @@ class HomeSettingsFragment : Fragment() {
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.verify_installed_content,
|
||||
R.string.verify_installed_content_description,
|
||||
R.drawable.ic_check_circle,
|
||||
{
|
||||
ProgressDialogFragment.newInstance(
|
||||
requireActivity(),
|
||||
titleId = R.string.verifying,
|
||||
cancellable = true
|
||||
) { progressCallback, _ ->
|
||||
val result = NativeLibrary.verifyInstalledContents(progressCallback)
|
||||
return@newInstance if (progressCallback.invoke(100, 100)) {
|
||||
// Invoke the progress callback to check if the process was cancelled
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_no_result,
|
||||
descriptionId = R.string.verify_no_result_description
|
||||
)
|
||||
} else if (result.isEmpty()) {
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_success,
|
||||
descriptionId = R.string.operation_completed_successfully
|
||||
)
|
||||
} else {
|
||||
val failedNames = result.joinToString("\n")
|
||||
val errorMessage = YuzuApplication.appContext.getString(
|
||||
R.string.verification_failed_for,
|
||||
failedNames
|
||||
)
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.verify_failure,
|
||||
descriptionString = errorMessage
|
||||
)
|
||||
}
|
||||
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.share_log,
|
||||
|
@ -26,9 +26,15 @@ class MessageDialogFragment : DialogFragment() {
|
||||
val descriptionId = requireArguments().getInt(DESCRIPTION_ID)
|
||||
val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!!
|
||||
val helpLinkId = requireArguments().getInt(HELP_LINK)
|
||||
val dismissible = requireArguments().getBoolean(DISMISSIBLE)
|
||||
val clearPositiveAction = requireArguments().getBoolean(CLEAR_POSITIVE_ACTION)
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
|
||||
if (clearPositiveAction) {
|
||||
messageDialogViewModel.positiveAction = null
|
||||
}
|
||||
|
||||
if (messageDialogViewModel.positiveAction == null) {
|
||||
builder.setPositiveButton(R.string.close, null)
|
||||
} else {
|
||||
@ -51,6 +57,8 @@ class MessageDialogFragment : DialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
isCancelable = dismissible
|
||||
|
||||
return builder.show()
|
||||
}
|
||||
|
||||
@ -67,28 +75,38 @@ class MessageDialogFragment : DialogFragment() {
|
||||
private const val DESCRIPTION_ID = "DescriptionId"
|
||||
private const val DESCRIPTION_STRING = "DescriptionString"
|
||||
private const val HELP_LINK = "Link"
|
||||
private const val DISMISSIBLE = "Dismissible"
|
||||
private const val CLEAR_POSITIVE_ACTION = "ClearPositiveAction"
|
||||
|
||||
fun newInstance(
|
||||
activity: FragmentActivity,
|
||||
activity: FragmentActivity? = null,
|
||||
titleId: Int = 0,
|
||||
titleString: String = "",
|
||||
descriptionId: Int = 0,
|
||||
descriptionString: String = "",
|
||||
helpLinkId: Int = 0,
|
||||
dismissible: Boolean = true,
|
||||
positiveAction: (() -> Unit)? = null
|
||||
): MessageDialogFragment {
|
||||
var clearPositiveAction = false
|
||||
if (activity != null) {
|
||||
ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
|
||||
clear()
|
||||
this.positiveAction = positiveAction
|
||||
}
|
||||
} else {
|
||||
clearPositiveAction = true
|
||||
}
|
||||
|
||||
val dialog = MessageDialogFragment()
|
||||
val bundle = Bundle()
|
||||
bundle.apply {
|
||||
val bundle = Bundle().apply {
|
||||
putInt(TITLE_ID, titleId)
|
||||
putString(TITLE_STRING, titleString)
|
||||
putInt(DESCRIPTION_ID, descriptionId)
|
||||
putString(DESCRIPTION_STRING, descriptionString)
|
||||
putInt(HELP_LINK, helpLinkId)
|
||||
}
|
||||
ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
|
||||
clear()
|
||||
this.positiveAction = positiveAction
|
||||
putBoolean(DISMISSIBLE, dismissible)
|
||||
putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction)
|
||||
}
|
||||
dialog.arguments = bundle
|
||||
return dialog
|
||||
|
@ -31,6 +31,7 @@ import androidx.preference.PreferenceManager
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import java.io.File
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
@ -162,7 +163,7 @@ class SetupFragment : Fragment() {
|
||||
R.string.install_prod_keys_warning_help,
|
||||
{
|
||||
val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
|
||||
if (file.exists()) {
|
||||
if (file.exists() && NativeLibrary.areKeysPresent()) {
|
||||
StepState.COMPLETE
|
||||
} else {
|
||||
StepState.INCOMPLETE
|
||||
@ -347,7 +348,8 @@ class SetupFragment : Fragment() {
|
||||
val getProdKey =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||
if (result != null) {
|
||||
if (mainActivity.processKey(result)) {
|
||||
mainActivity.processKey(result)
|
||||
if (NativeLibrary.areKeysPresent()) {
|
||||
keyCallback.onStepCompleted()
|
||||
}
|
||||
}
|
||||
|
@ -66,10 +66,13 @@ class DriverViewModel : ViewModel() {
|
||||
|
||||
fun updateDriverList() {
|
||||
val selectedDriver = GpuDriverHelper.customDriverSettingData
|
||||
val systemDriverData = GpuDriverHelper.getSystemDriverInfo()
|
||||
val newDriverList = mutableListOf(
|
||||
Driver(
|
||||
selectedDriver == GpuDriverMetadata(),
|
||||
YuzuApplication.appContext.getString(R.string.system_gpu_driver)
|
||||
YuzuApplication.appContext.getString(R.string.system_gpu_driver),
|
||||
systemDriverData?.get(0) ?: "",
|
||||
systemDriverData?.get(1) ?: ""
|
||||
)
|
||||
)
|
||||
driverData.forEach {
|
||||
@ -144,6 +147,7 @@ class DriverViewModel : ViewModel() {
|
||||
val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString())
|
||||
val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData
|
||||
if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) {
|
||||
setDriverReady()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package org.yuzu.yuzu_emu.model
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class EmulationViewModel : ViewModel() {
|
||||
val emulationStarted: StateFlow<Boolean> get() = _emulationStarted
|
||||
@ -14,6 +15,12 @@ class EmulationViewModel : ViewModel() {
|
||||
val isEmulationStopping: StateFlow<Boolean> get() = _isEmulationStopping
|
||||
private val _isEmulationStopping = MutableStateFlow(false)
|
||||
|
||||
private val _emulationStopped = MutableStateFlow(false)
|
||||
val emulationStopped = _emulationStopped.asStateFlow()
|
||||
|
||||
private val _programChanged = MutableStateFlow(-1)
|
||||
val programChanged = _programChanged.asStateFlow()
|
||||
|
||||
val shaderProgress: StateFlow<Int> get() = _shaderProgress
|
||||
private val _shaderProgress = MutableStateFlow(0)
|
||||
|
||||
@ -23,6 +30,9 @@ class EmulationViewModel : ViewModel() {
|
||||
val shaderMessage: StateFlow<String> get() = _shaderMessage
|
||||
private val _shaderMessage = MutableStateFlow("")
|
||||
|
||||
private val _drawerOpen = MutableStateFlow(false)
|
||||
val drawerOpen = _drawerOpen.asStateFlow()
|
||||
|
||||
fun setEmulationStarted(started: Boolean) {
|
||||
_emulationStarted.value = started
|
||||
}
|
||||
@ -31,6 +41,17 @@ class EmulationViewModel : ViewModel() {
|
||||
_isEmulationStopping.value = value
|
||||
}
|
||||
|
||||
fun setEmulationStopped(value: Boolean) {
|
||||
if (value) {
|
||||
_emulationStarted.value = false
|
||||
}
|
||||
_emulationStopped.value = value
|
||||
}
|
||||
|
||||
fun setProgramChanged(programIndex: Int) {
|
||||
_programChanged.value = programIndex
|
||||
}
|
||||
|
||||
fun setShaderProgress(progress: Int) {
|
||||
_shaderProgress.value = progress
|
||||
}
|
||||
@ -49,19 +70,7 @@ class EmulationViewModel : ViewModel() {
|
||||
setTotalShaders(max)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
setEmulationStarted(false)
|
||||
setIsEmulationStopping(false)
|
||||
setShaderProgress(0)
|
||||
setTotalShaders(0)
|
||||
setShaderMessage("")
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_EMULATION_STARTED = "EmulationStarted"
|
||||
const val KEY_IS_EMULATION_STOPPING = "IsEmulationStarting"
|
||||
const val KEY_SHADER_PROGRESS = "ShaderProgress"
|
||||
const val KEY_TOTAL_SHADERS = "TotalShaders"
|
||||
const val KEY_SHADER_MESSAGE = "ShaderMessage"
|
||||
fun setDrawerOpen(value: Boolean) {
|
||||
_drawerOpen.value = value
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.model
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import java.util.HashSet
|
||||
@ -11,6 +12,7 @@ import kotlinx.serialization.Serializable
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import java.time.LocalDateTime
|
||||
@ -61,12 +63,26 @@ class Game(
|
||||
val addonDir: String
|
||||
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Game) {
|
||||
return false
|
||||
val launchIntent: Intent
|
||||
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(path)
|
||||
}
|
||||
|
||||
return hashCode() == other.hashCode()
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Game
|
||||
|
||||
if (title != other.title) return false
|
||||
if (path != other.path) return false
|
||||
if (programId != other.programId) return false
|
||||
if (developer != other.developer) return false
|
||||
if (version != other.version) return false
|
||||
if (isHomebrew != other.isHomebrew) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
|
@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.model
|
||||
|
||||
enum class GameVerificationResult(val int: Int) {
|
||||
Success(0),
|
||||
Failed(1),
|
||||
NotImplemented(2);
|
||||
|
||||
companion object {
|
||||
fun from(int: Int): GameVerificationResult =
|
||||
entries.firstOrNull { it.int == int } ?: Success
|
||||
}
|
||||
}
|
@ -31,6 +31,9 @@ class HomeViewModel : ViewModel() {
|
||||
private val _reloadPropertiesList = MutableStateFlow(false)
|
||||
val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow()
|
||||
|
||||
private val _checkKeys = MutableStateFlow(false)
|
||||
val checkKeys = _checkKeys.asStateFlow()
|
||||
|
||||
var navigatedToSetup = false
|
||||
|
||||
fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
|
||||
@ -66,4 +69,8 @@ class HomeViewModel : ViewModel() {
|
||||
fun reloadPropertiesList(reload: Boolean) {
|
||||
_reloadPropertiesList.value = reload
|
||||
}
|
||||
|
||||
fun setCheckKeys(value: Boolean) {
|
||||
_checkKeys.value = value
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
|
||||
override var themeId: Int = 0
|
||||
|
||||
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
||||
private var checkedDecryption = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||
@ -75,6 +78,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION)
|
||||
}
|
||||
if (!checkedDecryption) {
|
||||
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
|
||||
if (!firstTimeSetup) {
|
||||
checkKeys()
|
||||
}
|
||||
checkedDecryption = true
|
||||
}
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
|
||||
|
||||
@ -150,6 +165,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
homeViewModel.checkKeys.collect {
|
||||
if (it) {
|
||||
checkKeys()
|
||||
homeViewModel.setCheckKeys(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dismiss previous notifications (should not happen unless a crash occurred)
|
||||
@ -158,6 +183,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
setInsets()
|
||||
}
|
||||
|
||||
private fun checkKeys() {
|
||||
if (!NativeLibrary.areKeysPresent()) {
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.keys_missing,
|
||||
descriptionId = R.string.keys_missing_description,
|
||||
helpLinkId = R.string.keys_missing_help
|
||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
|
||||
}
|
||||
|
||||
fun finishSetup(navController: NavController) {
|
||||
navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment)
|
||||
(binding.navigationView as NavigationBarView).setupWithNavController(navController)
|
||||
@ -349,6 +389,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
R.string.install_keys_success,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
homeViewModel.setCheckKeys(true)
|
||||
gamesViewModel.reloadGames(true)
|
||||
return true
|
||||
} else {
|
||||
@ -399,6 +440,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
firmwarePath.deleteRecursively()
|
||||
cacheFirmwareDir.copyRecursively(firmwarePath, true)
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
getString(R.string.save_file_imported_success)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -5,7 +5,10 @@ package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@ -85,4 +88,22 @@ object GameIconUtils {
|
||||
return imageLoader.execute(request)
|
||||
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
}
|
||||
|
||||
suspend fun getShortcutIcon(lifecycleOwner: LifecycleOwner, game: Game): IconCompat {
|
||||
val layerDrawable = ResourcesCompat.getDrawable(
|
||||
YuzuApplication.appContext.resources,
|
||||
R.drawable.shortcut,
|
||||
null
|
||||
) as LayerDrawable
|
||||
layerDrawable.setDrawableByLayerId(
|
||||
R.id.shortcut_foreground,
|
||||
getGameIcon(lifecycleOwner, game).toDrawable(YuzuApplication.appContext.resources)
|
||||
)
|
||||
val inset = YuzuApplication.appContext.resources
|
||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||
return IconCompat.createWithAdaptiveBitmap(
|
||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.view.Surface
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
@ -195,6 +197,11 @@ object GpuDriverHelper {
|
||||
|
||||
external fun supportsCustomDriverLoading(): Boolean
|
||||
|
||||
external fun getSystemDriverInfo(
|
||||
surface: Surface = Surface(SurfaceTexture(true)),
|
||||
hookLibPath: String = GpuDriverHelper.hookLibPath!!
|
||||
): Array<String>?
|
||||
|
||||
// Parse the custom driver metadata to retrieve the name.
|
||||
val installedCustomDriverData: GpuDriverMetadata
|
||||
get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME))
|
||||
|
@ -22,7 +22,7 @@ add_library(yuzu-android SHARED
|
||||
|
||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||
|
||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common)
|
||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common Vulkan::Headers)
|
||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
|
||||
if (ARCHITECTURE_arm64)
|
||||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||
|
@ -63,6 +63,7 @@ struct Values {
|
||||
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
||||
Settings::Category::Overlay};
|
||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
||||
Settings::Setting<s32> lock_drawer{linkage, false, "lock_drawer", Settings::Category::Overlay};
|
||||
};
|
||||
|
||||
extern Values values;
|
||||
|
@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj
|
||||
const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
|
||||
object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
|
||||
return ResultData{GetJString(env, string),
|
||||
static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField(
|
||||
static_cast<Service::AM::Frontend::SwkbdResult>(env->GetIntField(
|
||||
object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
|
||||
}
|
||||
|
||||
void AndroidKeyboard::ShowTextCheckDialog(
|
||||
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const {
|
||||
LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
|
||||
}
|
||||
@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged(
|
||||
"\ncursor_position={}",
|
||||
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
|
||||
text_parameters.input_text, text_parameters.cursor_position);
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
|
||||
|
||||
m_current_text += submitted_text;
|
||||
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
|
||||
m_current_text.size());
|
||||
}
|
||||
|
||||
@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
|
||||
case KEYCODE_BACK:
|
||||
case KEYCODE_ENTER:
|
||||
m_is_inline_active = false;
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text,
|
||||
static_cast<s32>(m_current_text.size()));
|
||||
break;
|
||||
case KEYCODE_DEL:
|
||||
m_current_text.pop_back();
|
||||
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
|
||||
m_current_text.size());
|
||||
break;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
|
||||
void ShowNormalKeyboard() const override;
|
||||
|
||||
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const override;
|
||||
|
||||
void ShowInlineKeyboard(
|
||||
@ -45,7 +45,7 @@ private:
|
||||
static ResultData CreateFromFrontend(jobject object);
|
||||
|
||||
std::string text;
|
||||
Service::AM::Applets::SwkbdResult result{};
|
||||
Service::AM::Frontend::SwkbdResult result{};
|
||||
};
|
||||
|
||||
void SubmitNormalText(const ResultData& result) const;
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <core/core.h>
|
||||
#include <core/file_sys/mode.h>
|
||||
#include <core/file_sys/patch_manager.h>
|
||||
#include <core/loader/nro.h>
|
||||
#include <jni.h>
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/loader/nro.h"
|
||||
#include "jni.h"
|
||||
#include "jni/android_common/android_common.h"
|
||||
#include "native.h"
|
||||
|
||||
@ -79,7 +79,7 @@ extern "C" {
|
||||
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj,
|
||||
jstring jpath) {
|
||||
const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
||||
GetJString(env, jpath), FileSys::Mode::Read);
|
||||
GetJString(env, jpath), FileSys::OpenMode::Read);
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ static jmethodID s_exit_emulation_activity;
|
||||
static jmethodID s_disk_cache_load_progress;
|
||||
static jmethodID s_on_emulation_started;
|
||||
static jmethodID s_on_emulation_stopped;
|
||||
static jmethodID s_on_program_changed;
|
||||
|
||||
static jclass s_game_class;
|
||||
static jmethodID s_game_constructor;
|
||||
@ -123,6 +124,10 @@ jmethodID GetOnEmulationStopped() {
|
||||
return s_on_emulation_stopped;
|
||||
}
|
||||
|
||||
jmethodID GetOnProgramChanged() {
|
||||
return s_on_program_changed;
|
||||
}
|
||||
|
||||
jclass GetGameClass() {
|
||||
return s_game_class;
|
||||
}
|
||||
@ -306,6 +311,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
||||
s_on_emulation_stopped =
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
||||
s_on_program_changed =
|
||||
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
||||
|
||||
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
||||
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
||||
|
@ -19,6 +19,7 @@ jmethodID GetExitEmulationActivity();
|
||||
jmethodID GetDiskCacheLoadProgress();
|
||||
jmethodID GetOnEmulationStarted();
|
||||
jmethodID GetOnEmulationStopped();
|
||||
jmethodID GetOnProgramChanged();
|
||||
|
||||
jclass GetGameClass();
|
||||
jmethodID GetGameConstructor();
|
||||
|
@ -35,20 +35,22 @@
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "frontend_common/config.h"
|
||||
@ -59,6 +61,9 @@
|
||||
#include "jni/id_cache.h"
|
||||
#include "jni/native.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||
#include "video_core/vulkan_common/vulkan_surface.h"
|
||||
|
||||
#define jconst [[maybe_unused]] const auto
|
||||
#define jauto [[maybe_unused]] auto
|
||||
@ -154,7 +159,7 @@ void EmulationSession::SurfaceChanged() {
|
||||
}
|
||||
|
||||
void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) {
|
||||
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
|
||||
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::OpenMode::Read);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
@ -207,7 +212,14 @@ void EmulationSession::InitializeSystem(bool reload) {
|
||||
m_system.GetFileSystemController().CreateFactories(*m_vfs);
|
||||
}
|
||||
|
||||
Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath) {
|
||||
void EmulationSession::SetAppletId(int applet_id) {
|
||||
m_applet_id = applet_id;
|
||||
m_system.GetFrontendAppletHolder().SetCurrentAppletId(
|
||||
static_cast<Service::AM::AppletId>(m_applet_id));
|
||||
}
|
||||
|
||||
Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
|
||||
const std::size_t program_index) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// Create the render window.
|
||||
@ -221,7 +233,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
||||
m_system.ApplySettings();
|
||||
Settings::LogSettings();
|
||||
m_system.HIDCore().ReloadInputDevices();
|
||||
m_system.SetAppletFrontendSet({
|
||||
m_system.SetFrontendAppletSet({
|
||||
nullptr, // Amiibo Settings
|
||||
nullptr, // Controller Selector
|
||||
nullptr, // Error Display
|
||||
@ -237,7 +249,11 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
||||
ConfigureFilesystemProvider(filepath);
|
||||
|
||||
// Load the ROM.
|
||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
|
||||
Service::AM::FrontendAppletParameters params{
|
||||
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
|
||||
.program_index = static_cast<s32>(program_index),
|
||||
};
|
||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
|
||||
if (m_load_result != Core::SystemResultStatus::Success) {
|
||||
return m_load_result;
|
||||
}
|
||||
@ -247,12 +263,24 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
||||
m_system.GetCpuManager().OnGpuReady();
|
||||
m_system.RegisterExitCallback([&] { HaltEmulation(); });
|
||||
|
||||
// Register an ExecuteProgram callback such that Core can execute a sub-program
|
||||
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
|
||||
m_next_program_index = program_index_;
|
||||
EmulationSession::GetInstance().HaltEmulation();
|
||||
});
|
||||
|
||||
OnEmulationStarted();
|
||||
return Core::SystemResultStatus::Success;
|
||||
}
|
||||
|
||||
void EmulationSession::ShutdownEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
if (m_next_program_index != -1) {
|
||||
ChangeProgram(m_next_program_index);
|
||||
m_next_program_index = -1;
|
||||
}
|
||||
|
||||
m_is_running = false;
|
||||
|
||||
// Unload user input.
|
||||
@ -321,6 +349,9 @@ void EmulationSession::RunEmulation() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset current applet ID.
|
||||
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
|
||||
}
|
||||
|
||||
bool EmulationSession::IsHandheldOnly() {
|
||||
@ -400,6 +431,12 @@ void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
|
||||
static_cast<jint>(result));
|
||||
}
|
||||
|
||||
void EmulationSession::ChangeProgram(std::size_t program_index) {
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnProgramChanged(),
|
||||
static_cast<jint>(program_index));
|
||||
}
|
||||
|
||||
u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
|
||||
auto program_id_string = GetJString(env, jprogramId);
|
||||
try {
|
||||
@ -409,7 +446,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
|
||||
}
|
||||
}
|
||||
|
||||
static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
|
||||
static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
||||
const size_t program_index = 0) {
|
||||
MicroProfileOnThreadCreate("EmuThread");
|
||||
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||
|
||||
@ -422,7 +460,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
|
||||
|
||||
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
|
||||
|
||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath);
|
||||
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index);
|
||||
if (result != Core::SystemResultStatus::Success) {
|
||||
return result;
|
||||
}
|
||||
@ -463,8 +501,8 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
|
||||
};
|
||||
|
||||
return static_cast<int>(
|
||||
ContentManager::InstallNSP(&EmulationSession::GetInstance().System(),
|
||||
EmulationSession::GetInstance().System().GetFilesystem().get(),
|
||||
ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
|
||||
*EmulationSession::GetInstance().System().GetFilesystem(),
|
||||
GetJString(env, j_file), callback));
|
||||
}
|
||||
|
||||
@ -474,8 +512,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
std::string updatePath = GetJString(env, jupdatePath);
|
||||
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
||||
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(updatePath,
|
||||
FileSys::Mode::Read));
|
||||
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
||||
updatePath, FileSys::OpenMode::Read));
|
||||
for (const auto& item : nsp->GetNCAs()) {
|
||||
for (const auto& nca_details : item.second) {
|
||||
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
||||
@ -519,6 +557,37 @@ jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDri
|
||||
#endif
|
||||
}
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
|
||||
JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
|
||||
const char* file_redirect_dir_{};
|
||||
int featureFlags{};
|
||||
std::string hook_lib_dir = GetJString(env, j_hook_lib_dir);
|
||||
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||
InputCommon::InputSubsystem input_subsystem;
|
||||
auto m_window = std::make_unique<EmuWindow_Android>(
|
||||
&input_subsystem, ANativeWindow_fromSurface(env, j_surf), driver_library);
|
||||
|
||||
Vulkan::vk::InstanceDispatch dld;
|
||||
Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance(
|
||||
*driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android);
|
||||
|
||||
auto surface = Vulkan::CreateSurface(vk_instance, m_window->GetWindowInfo());
|
||||
|
||||
auto device = Vulkan::CreateDevice(vk_instance, dld, *surface);
|
||||
|
||||
auto driver_version = device.GetDriverVersion();
|
||||
auto version_string =
|
||||
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
|
||||
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
|
||||
|
||||
jobjectArray j_driver_info =
|
||||
env->NewObjectArray(2, IDCache::GetStringClass(), ToJString(env, version_string));
|
||||
env->SetObjectArrayElement(j_driver_info, 1, ToJString(env, device.GetDriverName()));
|
||||
return j_driver_info;
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) {
|
||||
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
||||
return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
|
||||
@ -674,6 +743,11 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass
|
||||
return ToJString(env, "JIT");
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) {
|
||||
return ToJString(env,
|
||||
EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor());
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) {
|
||||
EmulationSession::GetInstance().System().ApplySettings();
|
||||
}
|
||||
@ -682,11 +756,11 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
|
||||
Settings::LogSettings();
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz,
|
||||
jstring j_path) {
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
|
||||
jint j_program_index) {
|
||||
const std::string path = GetJString(env, j_path);
|
||||
|
||||
const Core::SystemResultStatus result{RunEmulation(path)};
|
||||
const Core::SystemResultStatus result{RunEmulation(path, j_program_index)};
|
||||
if (result != Core::SystemResultStatus::Success) {
|
||||
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
|
||||
IDCache::GetExitEmulationActivity(), static_cast<int>(result));
|
||||
@ -713,7 +787,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
|
||||
jobject instance) {
|
||||
const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
|
||||
auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
|
||||
Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read);
|
||||
Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
|
||||
|
||||
const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser(
|
||||
static_cast<std::size_t>(0));
|
||||
@ -748,13 +822,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
|
||||
jint jappletId) {
|
||||
EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId(
|
||||
static_cast<Service::AM::Applets::AppletId>(jappletId));
|
||||
EmulationSession::GetInstance().SetAppletId(jappletId);
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
|
||||
jint jcabinetMode) {
|
||||
EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode(
|
||||
EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode(
|
||||
static_cast<Service::NFP::CabinetMode>(jcabinetMode));
|
||||
}
|
||||
|
||||
@ -819,7 +892,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject job
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
|
||||
jstring jprogramId) {
|
||||
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id);
|
||||
ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
|
||||
@ -829,6 +902,44 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
|
||||
program_id, GetJString(env, jname));
|
||||
}
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
|
||||
jobject jobj,
|
||||
jobject jcallback) {
|
||||
auto jlambdaClass = env->GetObjectClass(jcallback);
|
||||
auto jlambdaInvokeMethod = env->GetMethodID(
|
||||
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
|
||||
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
|
||||
ToJDouble(env, max), ToJDouble(env, progress));
|
||||
return GetJBoolean(env, jwasCancelled);
|
||||
};
|
||||
|
||||
auto& session = EmulationSession::GetInstance();
|
||||
std::vector<std::string> result = ContentManager::VerifyInstalledContents(
|
||||
session.System(), *session.GetContentProvider(), callback);
|
||||
jobjectArray jresult =
|
||||
env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
env->SetObjectArrayElement(jresult, i, ToJString(env, result[i]));
|
||||
}
|
||||
return jresult;
|
||||
}
|
||||
|
||||
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobject jobj,
|
||||
jstring jpath, jobject jcallback) {
|
||||
auto jlambdaClass = env->GetObjectClass(jcallback);
|
||||
auto jlambdaInvokeMethod = env->GetMethodID(
|
||||
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
|
||||
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
|
||||
ToJDouble(env, max), ToJDouble(env, progress));
|
||||
return GetJBoolean(env, jwasCancelled);
|
||||
};
|
||||
auto& session = EmulationSession::GetInstance();
|
||||
return static_cast<jint>(
|
||||
ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback));
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
|
||||
jstring jprogramId) {
|
||||
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
@ -845,7 +956,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
|
||||
|
||||
const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
|
||||
auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir),
|
||||
FileSys::Mode::Read);
|
||||
FileSys::OpenMode::Read);
|
||||
|
||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
|
||||
@ -875,4 +986,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env,
|
||||
EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) {
|
||||
auto& system = EmulationSession::GetInstance().System();
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
|
||||
return ContentManager::AreKeysPresent();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
@ -45,7 +45,9 @@ public:
|
||||
const Core::PerfStatsResults& PerfStats();
|
||||
void ConfigureFilesystemProvider(const std::string& filepath);
|
||||
void InitializeSystem(bool reload);
|
||||
Core::SystemResultStatus InitializeEmulation(const std::string& filepath);
|
||||
void SetAppletId(int applet_id);
|
||||
Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
|
||||
const std::size_t program_index = 0);
|
||||
|
||||
bool IsHandheldOnly();
|
||||
void SetDeviceType([[maybe_unused]] int index, int type);
|
||||
@ -60,6 +62,7 @@ public:
|
||||
private:
|
||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
|
||||
static void OnEmulationStopped(Core::SystemResultStatus result);
|
||||
static void ChangeProgram(std::size_t program_index);
|
||||
|
||||
private:
|
||||
// Window management
|
||||
@ -77,6 +80,7 @@ private:
|
||||
std::atomic<bool> m_is_paused = false;
|
||||
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
||||
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
|
||||
int m_applet_id{1};
|
||||
|
||||
// GPU driver parameters
|
||||
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||
@ -84,4 +88,7 @@ private:
|
||||
// Synchronization
|
||||
std::condition_variable_any m_cv;
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
// Program index for next boot
|
||||
std::atomic<s32> m_next_program_index = -1;
|
||||
};
|
||||
|
9
src/android/app/src/main/res/drawable/ic_lock.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_lock.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
|
||||
</vector>
|
9
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M280,920q-33,0 -56.5,-23.5T200,840v-720q0,-33 23.5,-56.5T280,40h400q33,0 56.5,23.5T760,120v160h-80v-40L280,240v480h400v-40h80v160q0,33 -23.5,56.5T680,920L280,920ZM686,520L480,520v120h-80v-120q0,-33 23.5,-56.5T480,440h206l-62,-64 56,-56 160,160 -160,160 -56,-56 62,-64Z" />
|
||||
</vector>
|
@ -11,12 +11,14 @@
|
||||
android:id="@+id/appbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/about" />
|
||||
|
||||
@ -28,6 +30,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:fadeScrollbars="false"
|
||||
android:scrollbars="vertical"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/coordinator_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/content_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="3"
|
||||
android:gravity="top|center_horizontal"
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_copy"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/copy_details" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_verify_integrity"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/verify_integrity" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/path"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/path_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="none"
|
||||
android:minHeight="48dp"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="1.0.0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/program_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/program_id_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="none"
|
||||
android:minHeight="48dp"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="1.0.0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/developer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/developer_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="none"
|
||||
android:minHeight="48dp"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="1.0.0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/version_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="none"
|
||||
android:minHeight="48dp"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="1.0.0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -14,6 +14,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:fadeScrollbars="false"
|
||||
android:scrollbars="vertical"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/icon_layout"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
@ -43,16 +44,35 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_margin="8dp"
|
||||
app:icon="@drawable/ic_back"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_back"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_shortcut"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_shortcut"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
|
@ -23,6 +23,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:checked="false" />
|
||||
|
||||
|
@ -6,16 +6,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:focusable="true">
|
||||
android:layout_marginVertical="12dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:animateLayoutChanges="true">
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/path"
|
||||
|
@ -11,12 +11,14 @@
|
||||
android:id="@+id/appbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:title="@string/about"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
@ -28,6 +30,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:fadeScrollbars="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -11,6 +11,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
@ -19,6 +20,7 @@
|
||||
android:id="@+id/toolbar_addons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
@ -28,6 +30,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:nextFocusDown="@id/button_install"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -10,12 +10,14 @@
|
||||
android:id="@+id/appbar_applets"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_applets"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/applets" />
|
||||
|
||||
|
@ -15,12 +15,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:liftOnScrollTargetViewId="@id/list_drivers">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_drivers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/gpu_driver_manager" />
|
||||
|
||||
|
@ -11,12 +11,14 @@
|
||||
android:id="@+id/appbar_ea"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/early_access" />
|
||||
|
||||
@ -30,6 +32,7 @@
|
||||
android:paddingBottom="20dp"
|
||||
android:scrollbars="vertical"
|
||||
android:fadeScrollbars="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -5,6 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:keepScreenOn="true"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment"
|
||||
tools:openDrawer="start">
|
||||
|
||||
@ -24,7 +25,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false" />
|
||||
android:focusableInTouchMode="false"
|
||||
android:defaultFocusHighlightEnabled="false" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/loading_indicator"
|
||||
@ -33,7 +35,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:clickable="false">
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:clickable="false"
|
||||
app:rippleColor="@android:color/transparent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/loading_layout"
|
||||
@ -118,6 +122,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<Button
|
||||
@ -160,6 +165,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:focusedByDefault="true"
|
||||
app:headerLayout="@layout/header_in_game"
|
||||
app:menu="@menu/menu_in_game"
|
||||
tools:visibility="gone" />
|
||||
|
@ -15,12 +15,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:liftOnScrollTargetViewId="@id/list_folders">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_folders"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/game_folders" />
|
||||
|
||||
@ -31,6 +33,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -11,12 +11,14 @@
|
||||
android:id="@+id/appbar_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
@ -25,6 +27,7 @@
|
||||
android:id="@+id/scroll_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
@ -118,6 +121,14 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/copy_details" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_verify_integrity"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/verify_integrity" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
@ -13,7 +12,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:fadeScrollbars="false"
|
||||
android:clipToPadding="false">
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_all"
|
||||
@ -22,16 +22,35 @@
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_gravity="start"
|
||||
app:icon="@drawable/ic_back"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_back"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_shortcut"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_shortcut"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
@ -45,7 +64,7 @@
|
||||
android:id="@+id/image_game_screen"
|
||||
android:layout_width="175dp"
|
||||
android:layout_height="175dp"
|
||||
tools:src="@drawable/default_icon"/>
|
||||
tools:src="@drawable/default_icon" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@ -68,7 +87,7 @@
|
||||
android:id="@+id/list_properties"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/card_simple_outlined" />
|
||||
android:defaultFocusHighlightEnabled="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
tools:listitem="@layout/card_game" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -7,7 +7,8 @@
|
||||
android:background="?attr/colorSurface"
|
||||
android:scrollbars="vertical"
|
||||
android:fadeScrollbars="false"
|
||||
android:clipToPadding="false">
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/linear_layout_settings"
|
||||
|
@ -10,12 +10,14 @@
|
||||
android:id="@+id/appbar_installables"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_installables"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:title="@string/manage_yuzu_data"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
|
@ -10,12 +10,14 @@
|
||||
android:id="@+id/appbar_licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:title="@string/licenses"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:elevation="0dp">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
@ -24,6 +25,7 @@
|
||||
android:id="@+id/toolbar_settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:focusable="true"
|
||||
android:focusable="false"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
|
@ -12,4 +12,5 @@
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textStyle="bold"
|
||||
android:focusable="false"
|
||||
tools:text="CPU Settings" />
|
||||
|
@ -21,6 +21,11 @@
|
||||
android:icon="@drawable/ic_controller"
|
||||
android:title="@string/emulation_input_overlay" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_lock_drawer"
|
||||
android:icon="@drawable/ic_unlock"
|
||||
android:title="@string/emulation_input_overlay" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_exit"
|
||||
android:icon="@drawable/ic_exit"
|
||||
|
@ -142,6 +142,11 @@
|
||||
<item quantity="other">Successfully imported %d saves</item>
|
||||
</plurals>
|
||||
<string name="no_save_data_found">No save data found</string>
|
||||
<string name="verify_installed_content">Verify installed content</string>
|
||||
<string name="verify_installed_content_description">Checks all installed content for corruption</string>
|
||||
<string name="keys_missing">Encryption keys are missing</string>
|
||||
<string name="keys_missing_description">Firmware and retail games cannot be decrypted</string>
|
||||
<string name="keys_missing_help">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
|
||||
|
||||
<!-- Applet launcher strings -->
|
||||
<string name="applets">Applet launcher</string>
|
||||
@ -288,6 +293,7 @@
|
||||
<string name="import_complete">Import complete</string>
|
||||
<string name="more_options">More options</string>
|
||||
<string name="use_global_setting">Use global setting</string>
|
||||
<string name="operation_completed_successfully">The operation completed successfully</string>
|
||||
|
||||
<!-- GPU driver installation -->
|
||||
<string name="select_gpu_driver">Select GPU driver</string>
|
||||
@ -352,6 +358,14 @@
|
||||
<string name="content_install_notice_description">The content that you selected does not match this game.\nInstall anyway?</string>
|
||||
<string name="confirm_uninstall">Confirm uninstall</string>
|
||||
<string name="confirm_uninstall_description">Are you sure you want to uninstall this addon?</string>
|
||||
<string name="verify_integrity">Verify integrity</string>
|
||||
<string name="verifying">Verifying…</string>
|
||||
<string name="verify_success">Integrity verification succeeded!</string>
|
||||
<string name="verify_failure">Integrity verification failed!</string>
|
||||
<string name="verify_failure_description">File contents may be corrupt</string>
|
||||
<string name="verify_no_result">Integrity verification couldn\'t be performed</string>
|
||||
<string name="verify_no_result_description">File contents were not checked for validity</string>
|
||||
<string name="verification_failed_for">Verification failed for the following files:\n%1$s</string>
|
||||
|
||||
<!-- ROM loading errors -->
|
||||
<string name="loader_error_encrypted">Your ROM is encrypted</string>
|
||||
@ -381,6 +395,8 @@
|
||||
<string name="emulation_unpause">Unpause emulation</string>
|
||||
<string name="emulation_input_overlay">Overlay options</string>
|
||||
<string name="touchscreen">Touchscreen</string>
|
||||
<string name="lock_drawer">Lock drawer</string>
|
||||
<string name="unlock_drawer">Unlock drawer</string>
|
||||
|
||||
<string name="load_settings">Loading settings…</string>
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/guest_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "common/fixed_point.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/guest_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::Renderer {
|
||||
|
@ -106,6 +106,7 @@ add_library(common STATIC
|
||||
precompiled_headers.h
|
||||
quaternion.h
|
||||
range_map.h
|
||||
range_mutex.h
|
||||
reader_writer_queue.h
|
||||
ring_buffer.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
|
||||
|
@ -30,27 +30,27 @@ NativeClock::NativeClock() {
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)};
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)};
|
||||
}
|
||||
|
||||
std::chrono::microseconds NativeClock::GetTimeUS() const {
|
||||
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)};
|
||||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)};
|
||||
}
|
||||
|
||||
std::chrono::milliseconds NativeClock::GetTimeMS() const {
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)};
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)};
|
||||
}
|
||||
|
||||
u64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor);
|
||||
s64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetUptime(), guest_cntfrq_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor);
|
||||
s64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetUptime(), gputick_cntfrq_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksNow() const {
|
||||
u64 cntvct_el0 = 0;
|
||||
s64 NativeClock::GetUptime() const {
|
||||
s64 cntvct_el0 = 0;
|
||||
asm volatile("dsb ish\n\t"
|
||||
"mrs %[cntvct_el0], cntvct_el0\n\t"
|
||||
"dsb ish\n\t"
|
||||
@ -58,15 +58,11 @@ u64 NativeClock::GetHostTicksNow() const {
|
||||
return cntvct_el0;
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksElapsed() const {
|
||||
return GetHostTicksNow();
|
||||
}
|
||||
|
||||
bool NativeClock::IsNative() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostCNTFRQ() {
|
||||
s64 NativeClock::GetHostCNTFRQ() {
|
||||
u64 cntfrq_el0 = 0;
|
||||
std::string_view board{""};
|
||||
#ifdef ANDROID
|
||||
|
@ -17,17 +17,15 @@ public:
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() const override;
|
||||
|
||||
u64 GetCNTPCT() const override;
|
||||
s64 GetCNTPCT() const override;
|
||||
|
||||
u64 GetGPUTick() const override;
|
||||
s64 GetGPUTick() const override;
|
||||
|
||||
u64 GetHostTicksNow() const override;
|
||||
|
||||
u64 GetHostTicksElapsed() const override;
|
||||
s64 GetUptime() const override;
|
||||
|
||||
bool IsNative() const override;
|
||||
|
||||
static u64 GetHostCNTFRQ();
|
||||
static s64 GetHostCNTFRQ();
|
||||
|
||||
public:
|
||||
using FactorType = unsigned __int128;
|
||||
|
@ -45,6 +45,7 @@ using f32 = float; ///< 32-bit floating point
|
||||
using f64 = double; ///< 64-bit floating point
|
||||
|
||||
using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
|
||||
using DAddr = u64; ///< Represents a pointer in the device specific virtual address space.
|
||||
using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
|
||||
using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space.
|
||||
|
||||
|
@ -18,4 +18,4 @@ struct MemoryInfo {
|
||||
*/
|
||||
[[nodiscard]] const MemoryInfo& GetMemInfo();
|
||||
|
||||
} // namespace Common
|
||||
} // namespace Common
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include "bit_cast.h"
|
||||
|
||||
@ -19,4 +20,21 @@ inline T WrappingAdd(T lhs, T rhs) {
|
||||
return BitCast<T>(lhs_u + rhs_u);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_integral_v<T> && std::is_signed_v<T>)
|
||||
inline bool CanAddWithoutOverflow(T lhs, T rhs) {
|
||||
#ifdef _MSC_VER
|
||||
if (lhs >= 0 && rhs >= 0) {
|
||||
return WrappingAdd(lhs, rhs) >= std::max(lhs, rhs);
|
||||
} else if (lhs < 0 && rhs < 0) {
|
||||
return WrappingAdd(lhs, rhs) <= std::min(lhs, rhs);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
T res;
|
||||
return !__builtin_add_overflow(lhs, rhs, &res);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
93
src/common/range_mutex.h
Normal file
93
src/common/range_mutex.h
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class ScopedRangeLock;
|
||||
|
||||
class RangeMutex {
|
||||
public:
|
||||
explicit RangeMutex() = default;
|
||||
~RangeMutex() = default;
|
||||
|
||||
private:
|
||||
friend class ScopedRangeLock;
|
||||
|
||||
void Lock(ScopedRangeLock& l);
|
||||
void Unlock(ScopedRangeLock& l);
|
||||
bool HasIntersectionLocked(ScopedRangeLock& l);
|
||||
|
||||
private:
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
|
||||
using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
|
||||
LockList m_list;
|
||||
};
|
||||
|
||||
class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
|
||||
public:
|
||||
explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
|
||||
: m_mutex(mutex), m_address(address), m_size(size) {
|
||||
if (m_size > 0) {
|
||||
m_mutex.Lock(*this);
|
||||
}
|
||||
}
|
||||
~ScopedRangeLock() {
|
||||
if (m_size > 0) {
|
||||
m_mutex.Unlock(*this);
|
||||
}
|
||||
}
|
||||
|
||||
u64 GetAddress() const {
|
||||
return m_address;
|
||||
}
|
||||
|
||||
u64 GetSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
RangeMutex& m_mutex;
|
||||
const u64 m_address{};
|
||||
const u64 m_size{};
|
||||
};
|
||||
|
||||
inline void RangeMutex::Lock(ScopedRangeLock& l) {
|
||||
std::unique_lock lk{m_mutex};
|
||||
m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
|
||||
m_list.push_back(l);
|
||||
}
|
||||
|
||||
inline void RangeMutex::Unlock(ScopedRangeLock& l) {
|
||||
{
|
||||
std::scoped_lock lk{m_mutex};
|
||||
m_list.erase(m_list.iterator_to(l));
|
||||
}
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
|
||||
const auto cur_begin = l.GetAddress();
|
||||
const auto cur_last = l.GetAddress() + l.GetSize() - 1;
|
||||
|
||||
for (const auto& other : m_list) {
|
||||
const auto other_begin = other.GetAddress();
|
||||
const auto other_last = other.GetAddress() + other.GetSize() - 1;
|
||||
|
||||
if (cur_begin <= other_last && other_begin <= cur_last) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Common
|
@ -419,9 +419,16 @@ struct Values {
|
||||
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<s64> custom_rtc{
|
||||
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
|
||||
true, true, &custom_rtc_enabled};
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
s64 custom_rtc_differential;
|
||||
false, true, &custom_rtc_enabled};
|
||||
SwitchableSetting<s64, true> custom_rtc_offset{linkage,
|
||||
0,
|
||||
std::numeric_limits<int>::min(),
|
||||
std::numeric_limits<int>::max(),
|
||||
"custom_rtc_offset",
|
||||
Category::System,
|
||||
Specialization::Countable,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<bool> rng_seed_enabled{
|
||||
linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<u32> rng_seed{
|
||||
|
@ -88,7 +88,17 @@ std::string FindSystemTimeZone() {
|
||||
LOG_ERROR(Common, "Time zone {} not handled, defaulting to hour offset.", tz_index);
|
||||
}
|
||||
}
|
||||
return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
|
||||
|
||||
// For some reason the Etc/GMT times are reversed. GMT+6 contains -21600 as its offset,
|
||||
// -6 hours instead of +6 hours, so these signs are purposefully reversed to fix it.
|
||||
std::string postfix{""};
|
||||
if (hours > 0) {
|
||||
postfix = fmt::format("-{:d}", std::abs(hours));
|
||||
} else if (hours < 0) {
|
||||
postfix = fmt::format("+{:d}", std::abs(hours));
|
||||
}
|
||||
|
||||
return fmt::format("Etc/GMT{:s}", postfix);
|
||||
}
|
||||
|
||||
} // namespace Common::TimeZone
|
||||
|
@ -12,9 +12,8 @@
|
||||
namespace Common {
|
||||
|
||||
struct UUID {
|
||||
std::array<u8, 0x10> uuid{};
|
||||
std::array<u8, 0x10> uuid;
|
||||
|
||||
/// Constructs an invalid UUID.
|
||||
constexpr UUID() = default;
|
||||
|
||||
/// Constructs a UUID from a reference to a 128 bit array.
|
||||
@ -34,14 +33,6 @@ struct UUID {
|
||||
*/
|
||||
explicit UUID(std::string_view uuid_string);
|
||||
|
||||
~UUID() = default;
|
||||
|
||||
constexpr UUID(const UUID&) noexcept = default;
|
||||
constexpr UUID(UUID&&) noexcept = default;
|
||||
|
||||
constexpr UUID& operator=(const UUID&) noexcept = default;
|
||||
constexpr UUID& operator=(UUID&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* Returns whether the stored UUID is valid or not.
|
||||
*
|
||||
@ -121,6 +112,7 @@ struct UUID {
|
||||
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
|
||||
};
|
||||
static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size.");
|
||||
static_assert(std::is_trivial_v<UUID>);
|
||||
|
||||
/// An invalid UUID. This UUID has all its bytes set to 0.
|
||||
constexpr UUID InvalidUUID = {};
|
||||
|
@ -18,42 +18,40 @@ namespace Common {
|
||||
|
||||
class StandardWallClock final : public WallClock {
|
||||
public:
|
||||
explicit StandardWallClock() : start_time{SteadyClock::Now()} {}
|
||||
explicit StandardWallClock() {}
|
||||
|
||||
std::chrono::nanoseconds GetTimeNS() const override {
|
||||
return SteadyClock::Now() - start_time;
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
std::chrono::microseconds GetTimeUS() const override {
|
||||
return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den);
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() const override {
|
||||
return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den);
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
u64 GetCNTPCT() const override {
|
||||
return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
||||
s64 GetCNTPCT() const override {
|
||||
return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
||||
}
|
||||
|
||||
u64 GetGPUTick() const override {
|
||||
return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
||||
s64 GetGPUTick() const override {
|
||||
return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
||||
}
|
||||
|
||||
u64 GetHostTicksNow() const override {
|
||||
return static_cast<u64>(SteadyClock::Now().time_since_epoch().count());
|
||||
}
|
||||
|
||||
u64 GetHostTicksElapsed() const override {
|
||||
return static_cast<u64>(GetTimeNS().count());
|
||||
s64 GetUptime() const override {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
bool IsNative() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SteadyClock::time_point start_time;
|
||||
};
|
||||
|
||||
std::unique_ptr<WallClock> CreateOptimalClock() {
|
||||
|
@ -29,16 +29,13 @@ public:
|
||||
virtual std::chrono::milliseconds GetTimeMS() const = 0;
|
||||
|
||||
/// @returns The guest CNTPCT ticks since the construction of this clock.
|
||||
virtual u64 GetCNTPCT() const = 0;
|
||||
virtual s64 GetCNTPCT() const = 0;
|
||||
|
||||
/// @returns The guest GPU ticks since the construction of this clock.
|
||||
virtual u64 GetGPUTick() const = 0;
|
||||
virtual s64 GetGPUTick() const = 0;
|
||||
|
||||
/// @returns The raw host timer ticks since an indeterminate epoch.
|
||||
virtual u64 GetHostTicksNow() const = 0;
|
||||
|
||||
/// @returns The raw host timer ticks since the construction of this clock.
|
||||
virtual u64 GetHostTicksElapsed() const = 0;
|
||||
virtual s64 GetUptime() const = 0;
|
||||
|
||||
/// @returns Whether the clock directly uses the host's hardware clock.
|
||||
virtual bool IsNative() const = 0;
|
||||
|
@ -8,39 +8,35 @@
|
||||
namespace Common::X64 {
|
||||
|
||||
NativeClock::NativeClock(u64 rdtsc_frequency_)
|
||||
: start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_},
|
||||
ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)},
|
||||
: rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den,
|
||||
rdtsc_frequency)},
|
||||
us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)},
|
||||
ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)},
|
||||
cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)},
|
||||
gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {}
|
||||
|
||||
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)};
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)};
|
||||
}
|
||||
|
||||
std::chrono::microseconds NativeClock::GetTimeUS() const {
|
||||
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)};
|
||||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)};
|
||||
}
|
||||
|
||||
std::chrono::milliseconds NativeClock::GetTimeMS() const {
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)};
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)};
|
||||
}
|
||||
|
||||
u64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor);
|
||||
s64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor);
|
||||
s64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetUptime(), gputick_rdtsc_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksNow() const {
|
||||
return FencedRDTSC();
|
||||
}
|
||||
|
||||
u64 NativeClock::GetHostTicksElapsed() const {
|
||||
return FencedRDTSC() - start_ticks;
|
||||
s64 NativeClock::GetUptime() const {
|
||||
return static_cast<s64>(FencedRDTSC());
|
||||
}
|
||||
|
||||
bool NativeClock::IsNative() const {
|
||||
|
@ -17,18 +17,15 @@ public:
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() const override;
|
||||
|
||||
u64 GetCNTPCT() const override;
|
||||
s64 GetCNTPCT() const override;
|
||||
|
||||
u64 GetGPUTick() const override;
|
||||
s64 GetGPUTick() const override;
|
||||
|
||||
u64 GetHostTicksNow() const override;
|
||||
|
||||
u64 GetHostTicksElapsed() const override;
|
||||
s64 GetUptime() const override;
|
||||
|
||||
bool IsNative() const override;
|
||||
|
||||
private:
|
||||
u64 start_ticks;
|
||||
u64 rdtsc_frequency;
|
||||
|
||||
u64 ns_rdtsc_factor;
|
||||
|
@ -20,26 +20,49 @@ add_library(core STATIC
|
||||
cpu_manager.h
|
||||
crypto/aes_util.cpp
|
||||
crypto/aes_util.h
|
||||
crypto/ctr_encryption_layer.cpp
|
||||
crypto/ctr_encryption_layer.h
|
||||
crypto/encryption_layer.cpp
|
||||
crypto/encryption_layer.h
|
||||
crypto/key_manager.cpp
|
||||
crypto/key_manager.h
|
||||
crypto/partition_data_manager.cpp
|
||||
crypto/partition_data_manager.h
|
||||
crypto/ctr_encryption_layer.cpp
|
||||
crypto/ctr_encryption_layer.h
|
||||
crypto/xts_encryption_layer.cpp
|
||||
crypto/xts_encryption_layer.h
|
||||
debugger/debugger_interface.h
|
||||
debugger/debugger.cpp
|
||||
debugger/debugger.h
|
||||
debugger/gdbstub_arch.cpp
|
||||
debugger/gdbstub_arch.h
|
||||
debugger/debugger_interface.h
|
||||
debugger/gdbstub.cpp
|
||||
debugger/gdbstub.h
|
||||
debugger/gdbstub_arch.cpp
|
||||
debugger/gdbstub_arch.h
|
||||
device_memory_manager.h
|
||||
device_memory_manager.inc
|
||||
device_memory.cpp
|
||||
device_memory.h
|
||||
file_sys/bis_factory.cpp
|
||||
file_sys/bis_factory.h
|
||||
file_sys/card_image.cpp
|
||||
file_sys/card_image.h
|
||||
file_sys/common_funcs.h
|
||||
file_sys/content_archive.cpp
|
||||
file_sys/content_archive.h
|
||||
file_sys/control_metadata.cpp
|
||||
file_sys/control_metadata.h
|
||||
file_sys/errors.h
|
||||
file_sys/fs_directory.h
|
||||
file_sys/fs_file.h
|
||||
file_sys/fs_filesystem.h
|
||||
file_sys/fs_memory_management.h
|
||||
file_sys/fs_operate_range.h
|
||||
file_sys/fs_path.h
|
||||
file_sys/fs_path_utility.h
|
||||
file_sys/fs_string_util.h
|
||||
file_sys/fsmitm_romfsbuild.cpp
|
||||
file_sys/fsmitm_romfsbuild.h
|
||||
file_sys/fssystem/fs_i_storage.h
|
||||
file_sys/fssystem/fs_types.h
|
||||
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
|
||||
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h
|
||||
file_sys/fssystem/fssystem_aes_ctr_storage.cpp
|
||||
@ -81,25 +104,10 @@ add_library(core STATIC
|
||||
file_sys/fssystem/fssystem_switch_storage.h
|
||||
file_sys/fssystem/fssystem_utility.cpp
|
||||
file_sys/fssystem/fssystem_utility.h
|
||||
file_sys/fssystem/fs_types.h
|
||||
file_sys/bis_factory.cpp
|
||||
file_sys/bis_factory.h
|
||||
file_sys/card_image.cpp
|
||||
file_sys/card_image.h
|
||||
file_sys/common_funcs.h
|
||||
file_sys/content_archive.cpp
|
||||
file_sys/content_archive.h
|
||||
file_sys/control_metadata.cpp
|
||||
file_sys/control_metadata.h
|
||||
file_sys/directory.h
|
||||
file_sys/errors.h
|
||||
file_sys/fsmitm_romfsbuild.cpp
|
||||
file_sys/fsmitm_romfsbuild.h
|
||||
file_sys/ips_layer.cpp
|
||||
file_sys/ips_layer.h
|
||||
file_sys/kernel_executable.cpp
|
||||
file_sys/kernel_executable.h
|
||||
file_sys/mode.h
|
||||
file_sys/nca_metadata.cpp
|
||||
file_sys/nca_metadata.h
|
||||
file_sys/partition_filesystem.cpp
|
||||
@ -144,22 +152,22 @@ add_library(core STATIC
|
||||
file_sys/system_archive/system_version.h
|
||||
file_sys/system_archive/time_zone_binary.cpp
|
||||
file_sys/system_archive/time_zone_binary.h
|
||||
file_sys/vfs.cpp
|
||||
file_sys/vfs.h
|
||||
file_sys/vfs_cached.cpp
|
||||
file_sys/vfs_cached.h
|
||||
file_sys/vfs_concat.cpp
|
||||
file_sys/vfs_concat.h
|
||||
file_sys/vfs_layered.cpp
|
||||
file_sys/vfs_layered.h
|
||||
file_sys/vfs_offset.cpp
|
||||
file_sys/vfs_offset.h
|
||||
file_sys/vfs_real.cpp
|
||||
file_sys/vfs_real.h
|
||||
file_sys/vfs_static.h
|
||||
file_sys/vfs_types.h
|
||||
file_sys/vfs_vector.cpp
|
||||
file_sys/vfs_vector.h
|
||||
file_sys/vfs/vfs.cpp
|
||||
file_sys/vfs/vfs.h
|
||||
file_sys/vfs/vfs_cached.cpp
|
||||
file_sys/vfs/vfs_cached.h
|
||||
file_sys/vfs/vfs_concat.cpp
|
||||
file_sys/vfs/vfs_concat.h
|
||||
file_sys/vfs/vfs_layered.cpp
|
||||
file_sys/vfs/vfs_layered.h
|
||||
file_sys/vfs/vfs_offset.cpp
|
||||
file_sys/vfs/vfs_offset.h
|
||||
file_sys/vfs/vfs_real.cpp
|
||||
file_sys/vfs/vfs_real.h
|
||||
file_sys/vfs/vfs_static.h
|
||||
file_sys/vfs/vfs_types.h
|
||||
file_sys/vfs/vfs_vector.cpp
|
||||
file_sys/vfs/vfs_vector.h
|
||||
file_sys/xts_archive.cpp
|
||||
file_sys/xts_archive.h
|
||||
frontend/applets/cabinet.cpp
|
||||
@ -168,8 +176,8 @@ add_library(core STATIC
|
||||
frontend/applets/controller.h
|
||||
frontend/applets/error.cpp
|
||||
frontend/applets/error.h
|
||||
frontend/applets/general_frontend.cpp
|
||||
frontend/applets/general_frontend.h
|
||||
frontend/applets/general.cpp
|
||||
frontend/applets/general.h
|
||||
frontend/applets/mii_edit.cpp
|
||||
frontend/applets/mii_edit.h
|
||||
frontend/applets/profile_select.cpp
|
||||
@ -192,7 +200,6 @@ add_library(core STATIC
|
||||
hle/kernel/board/nintendo/nx/secure_monitor.h
|
||||
hle/kernel/code_set.cpp
|
||||
hle/kernel/code_set.h
|
||||
hle/kernel/svc_results.h
|
||||
hle/kernel/global_scheduler_context.cpp
|
||||
hle/kernel/global_scheduler_context.h
|
||||
hle/kernel/init/init_slab_setup.cpp
|
||||
@ -202,11 +209,11 @@ add_library(core STATIC
|
||||
hle/kernel/k_address_arbiter.h
|
||||
hle/kernel/k_address_space_info.cpp
|
||||
hle/kernel/k_address_space_info.h
|
||||
hle/kernel/k_affinity_mask.h
|
||||
hle/kernel/k_auto_object.cpp
|
||||
hle/kernel/k_auto_object.h
|
||||
hle/kernel/k_auto_object_container.cpp
|
||||
hle/kernel/k_auto_object_container.h
|
||||
hle/kernel/k_affinity_mask.h
|
||||
hle/kernel/k_capabilities.cpp
|
||||
hle/kernel/k_capabilities.h
|
||||
hle/kernel/k_class_token.cpp
|
||||
@ -230,9 +237,9 @@ add_library(core STATIC
|
||||
hle/kernel/k_event_info.h
|
||||
hle/kernel/k_handle_table.cpp
|
||||
hle/kernel/k_handle_table.h
|
||||
hle/kernel/k_hardware_timer_base.h
|
||||
hle/kernel/k_hardware_timer.cpp
|
||||
hle/kernel/k_hardware_timer.h
|
||||
hle/kernel/k_hardware_timer_base.h
|
||||
hle/kernel/k_interrupt_manager.cpp
|
||||
hle/kernel/k_interrupt_manager.h
|
||||
hle/kernel/k_light_client_session.cpp
|
||||
@ -259,10 +266,10 @@ add_library(core STATIC
|
||||
hle/kernel/k_page_bitmap.h
|
||||
hle/kernel/k_page_buffer.cpp
|
||||
hle/kernel/k_page_buffer.h
|
||||
hle/kernel/k_page_heap.cpp
|
||||
hle/kernel/k_page_heap.h
|
||||
hle/kernel/k_page_group.cpp
|
||||
hle/kernel/k_page_group.h
|
||||
hle/kernel/k_page_heap.cpp
|
||||
hle/kernel/k_page_heap.h
|
||||
hle/kernel/k_page_table.h
|
||||
hle/kernel/k_page_table_base.cpp
|
||||
hle/kernel/k_page_table_base.h
|
||||
@ -327,8 +334,6 @@ add_library(core STATIC
|
||||
hle/kernel/slab_helpers.h
|
||||
hle/kernel/svc.cpp
|
||||
hle/kernel/svc.h
|
||||
hle/kernel/svc_common.h
|
||||
hle/kernel/svc_types.h
|
||||
hle/kernel/svc/svc_activity.cpp
|
||||
hle/kernel/svc/svc_address_arbiter.cpp
|
||||
hle/kernel/svc/svc_address_translation.cpp
|
||||
@ -366,6 +371,9 @@ add_library(core STATIC
|
||||
hle/kernel/svc/svc_thread_profiler.cpp
|
||||
hle/kernel/svc/svc_tick.cpp
|
||||
hle/kernel/svc/svc_transfer_memory.cpp
|
||||
hle/kernel/svc_common.h
|
||||
hle/kernel/svc_results.h
|
||||
hle/kernel/svc_types.h
|
||||
hle/result.h
|
||||
hle/service/acc/acc.cpp
|
||||
hle/service/acc/acc.h
|
||||
@ -382,39 +390,101 @@ add_library(core STATIC
|
||||
hle/service/acc/errors.h
|
||||
hle/service/acc/profile_manager.cpp
|
||||
hle/service/acc/profile_manager.h
|
||||
hle/service/am/frontend/applet_cabinet.cpp
|
||||
hle/service/am/frontend/applet_cabinet.h
|
||||
hle/service/am/frontend/applet_controller.cpp
|
||||
hle/service/am/frontend/applet_controller.h
|
||||
hle/service/am/frontend/applet_error.cpp
|
||||
hle/service/am/frontend/applet_error.h
|
||||
hle/service/am/frontend/applet_general.cpp
|
||||
hle/service/am/frontend/applet_general.h
|
||||
hle/service/am/frontend/applet_mii_edit.cpp
|
||||
hle/service/am/frontend/applet_mii_edit.h
|
||||
hle/service/am/frontend/applet_mii_edit_types.h
|
||||
hle/service/am/frontend/applet_profile_select.cpp
|
||||
hle/service/am/frontend/applet_profile_select.h
|
||||
hle/service/am/frontend/applet_software_keyboard.cpp
|
||||
hle/service/am/frontend/applet_software_keyboard.h
|
||||
hle/service/am/frontend/applet_software_keyboard_types.h
|
||||
hle/service/am/frontend/applet_web_browser.cpp
|
||||
hle/service/am/frontend/applet_web_browser.h
|
||||
hle/service/am/frontend/applet_web_browser_types.h
|
||||
hle/service/am/frontend/applets.cpp
|
||||
hle/service/am/frontend/applets.h
|
||||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/am_results.h
|
||||
hle/service/am/am_types.h
|
||||
hle/service/am/applet.cpp
|
||||
hle/service/am/applet.h
|
||||
hle/service/am/applet_ae.cpp
|
||||
hle/service/am/applet_ae.h
|
||||
hle/service/am/applet_manager.cpp
|
||||
hle/service/am/applet_data_broker.cpp
|
||||
hle/service/am/applet_data_broker.h
|
||||
hle/service/am/applet_manager.h
|
||||
hle/service/am/applet_oe.cpp
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applet_cabinet.cpp
|
||||
hle/service/am/applets/applet_cabinet.h
|
||||
hle/service/am/applets/applet_controller.cpp
|
||||
hle/service/am/applets/applet_controller.h
|
||||
hle/service/am/applets/applet_error.cpp
|
||||
hle/service/am/applets/applet_error.h
|
||||
hle/service/am/applets/applet_general_backend.cpp
|
||||
hle/service/am/applets/applet_general_backend.h
|
||||
hle/service/am/applets/applet_mii_edit.cpp
|
||||
hle/service/am/applets/applet_mii_edit.h
|
||||
hle/service/am/applets/applet_mii_edit_types.h
|
||||
hle/service/am/applets/applet_profile_select.cpp
|
||||
hle/service/am/applets/applet_profile_select.h
|
||||
hle/service/am/applets/applet_software_keyboard.cpp
|
||||
hle/service/am/applets/applet_software_keyboard.h
|
||||
hle/service/am/applets/applet_software_keyboard_types.h
|
||||
hle/service/am/applets/applet_web_browser.cpp
|
||||
hle/service/am/applets/applet_web_browser.h
|
||||
hle/service/am/applets/applet_web_browser_types.h
|
||||
hle/service/am/applets/applets.cpp
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applet_common_functions.cpp
|
||||
hle/service/am/applet_common_functions.h
|
||||
hle/service/am/applet_message_queue.cpp
|
||||
hle/service/am/applet_message_queue.h
|
||||
hle/service/am/application_creator.cpp
|
||||
hle/service/am/application_creator.h
|
||||
hle/service/am/application_functions.cpp
|
||||
hle/service/am/application_functions.h
|
||||
hle/service/am/application_proxy.cpp
|
||||
hle/service/am/application_proxy.h
|
||||
hle/service/am/audio_controller.cpp
|
||||
hle/service/am/audio_controller.h
|
||||
hle/service/am/common_state_getter.cpp
|
||||
hle/service/am/common_state_getter.h
|
||||
hle/service/am/debug_functions.cpp
|
||||
hle/service/am/debug_functions.h
|
||||
hle/service/am/display_controller.cpp
|
||||
hle/service/am/display_controller.h
|
||||
hle/service/am/global_state_controller.cpp
|
||||
hle/service/am/global_state_controller.h
|
||||
hle/service/am/hid_registration.cpp
|
||||
hle/service/am/hid_registration.h
|
||||
hle/service/am/home_menu_functions.cpp
|
||||
hle/service/am/home_menu_functions.h
|
||||
hle/service/am/idle.cpp
|
||||
hle/service/am/idle.h
|
||||
hle/service/am/library_applet_accessor.cpp
|
||||
hle/service/am/library_applet_accessor.h
|
||||
hle/service/am/library_applet_creator.cpp
|
||||
hle/service/am/library_applet_creator.h
|
||||
hle/service/am/library_applet_proxy.cpp
|
||||
hle/service/am/library_applet_proxy.h
|
||||
hle/service/am/library_applet_self_accessor.cpp
|
||||
hle/service/am/library_applet_self_accessor.h
|
||||
hle/service/am/library_applet_storage.cpp
|
||||
hle/service/am/library_applet_storage.h
|
||||
hle/service/am/lock_accessor.cpp
|
||||
hle/service/am/lock_accessor.h
|
||||
hle/service/am/managed_layer_holder.cpp
|
||||
hle/service/am/managed_layer_holder.h
|
||||
hle/service/am/omm.cpp
|
||||
hle/service/am/omm.h
|
||||
hle/service/am/process_winding_controller.cpp
|
||||
hle/service/am/process_winding_controller.h
|
||||
hle/service/am/process.cpp
|
||||
hle/service/am/process.h
|
||||
hle/service/am/self_controller.cpp
|
||||
hle/service/am/self_controller.h
|
||||
hle/service/am/system_applet_proxy.cpp
|
||||
hle/service/am/system_applet_proxy.h
|
||||
hle/service/am/system_buffer_manager.cpp
|
||||
hle/service/am/system_buffer_manager.h
|
||||
hle/service/am/spsm.cpp
|
||||
hle/service/am/spsm.h
|
||||
hle/service/am/storage_accessor.cpp
|
||||
hle/service/am/storage_accessor.h
|
||||
hle/service/am/storage.cpp
|
||||
hle/service/am/storage.h
|
||||
hle/service/am/window_controller.cpp
|
||||
hle/service/am/window_controller.h
|
||||
hle/service/aoc/aoc_u.cpp
|
||||
hle/service/aoc/aoc_u.h
|
||||
hle/service/apm/apm.cpp
|
||||
@ -470,26 +540,41 @@ add_library(core STATIC
|
||||
hle/service/caps/caps_types.h
|
||||
hle/service/caps/caps_u.cpp
|
||||
hle/service/caps/caps_u.h
|
||||
hle/service/cmif_serialization.h
|
||||
hle/service/cmif_types.h
|
||||
hle/service/erpt/erpt.cpp
|
||||
hle/service/erpt/erpt.h
|
||||
hle/service/es/es.cpp
|
||||
hle/service/es/es.h
|
||||
hle/service/eupld/eupld.cpp
|
||||
hle/service/eupld/eupld.h
|
||||
hle/service/event.cpp
|
||||
hle/service/event.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
hle/service/fatal/fatal_p.h
|
||||
hle/service/fatal/fatal_u.cpp
|
||||
hle/service/fatal/fatal_u.h
|
||||
hle/service/fgm/fgm.cpp
|
||||
hle/service/fgm/fgm.h
|
||||
hle/service/filesystem/filesystem.cpp
|
||||
hle/service/filesystem/filesystem.h
|
||||
hle/service/filesystem/fsp_ldr.cpp
|
||||
hle/service/filesystem/fsp_ldr.h
|
||||
hle/service/filesystem/fsp_pr.cpp
|
||||
hle/service/filesystem/fsp_pr.h
|
||||
hle/service/filesystem/fsp_srv.cpp
|
||||
hle/service/filesystem/fsp_srv.h
|
||||
hle/service/filesystem/fsp/fs_i_directory.cpp
|
||||
hle/service/filesystem/fsp/fs_i_directory.h
|
||||
hle/service/filesystem/fsp/fs_i_file.cpp
|
||||
hle/service/filesystem/fsp/fs_i_file.h
|
||||
hle/service/filesystem/fsp/fs_i_filesystem.cpp
|
||||
hle/service/filesystem/fsp/fs_i_filesystem.h
|
||||
hle/service/filesystem/fsp/fs_i_storage.cpp
|
||||
hle/service/filesystem/fsp/fs_i_storage.h
|
||||
hle/service/filesystem/fsp/fsp_ldr.cpp
|
||||
hle/service/filesystem/fsp/fsp_ldr.h
|
||||
hle/service/filesystem/fsp/fsp_pr.cpp
|
||||
hle/service/filesystem/fsp/fsp_pr.h
|
||||
hle/service/filesystem/fsp/fsp_srv.cpp
|
||||
hle/service/filesystem/fsp/fsp_srv.h
|
||||
hle/service/filesystem/fsp/fsp_util.h
|
||||
hle/service/filesystem/romfs_controller.cpp
|
||||
hle/service/filesystem/romfs_controller.h
|
||||
hle/service/filesystem/save_data_controller.cpp
|
||||
@ -513,6 +598,24 @@ add_library(core STATIC
|
||||
hle/service/glue/glue_manager.h
|
||||
hle/service/glue/notif.cpp
|
||||
hle/service/glue/notif.h
|
||||
hle/service/glue/time/alarm_worker.cpp
|
||||
hle/service/glue/time/alarm_worker.h
|
||||
hle/service/glue/time/file_timestamp_worker.cpp
|
||||
hle/service/glue/time/file_timestamp_worker.h
|
||||
hle/service/glue/time/manager.cpp
|
||||
hle/service/glue/time/manager.h
|
||||
hle/service/glue/time/pm_state_change_handler.cpp
|
||||
hle/service/glue/time/pm_state_change_handler.h
|
||||
hle/service/glue/time/standard_steady_clock_resource.cpp
|
||||
hle/service/glue/time/standard_steady_clock_resource.h
|
||||
hle/service/glue/time/static.cpp
|
||||
hle/service/glue/time/static.h
|
||||
hle/service/glue/time/time_zone.cpp
|
||||
hle/service/glue/time/time_zone.h
|
||||
hle/service/glue/time/time_zone_binary.cpp
|
||||
hle/service/glue/time/time_zone_binary.h
|
||||
hle/service/glue/time/worker.cpp
|
||||
hle/service/glue/time/worker.h
|
||||
hle/service/grc/grc.cpp
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
@ -529,13 +632,18 @@ add_library(core STATIC
|
||||
hle/service/hid/irs.h
|
||||
hle/service/hid/xcd.cpp
|
||||
hle/service/hid/xcd.h
|
||||
hle/service/hle_ipc.cpp
|
||||
hle/service/hle_ipc.h
|
||||
hle/service/ipc_helpers.h
|
||||
hle/service/kernel_helpers.cpp
|
||||
hle/service/kernel_helpers.h
|
||||
hle/service/lbl/lbl.cpp
|
||||
hle/service/lbl/lbl.h
|
||||
hle/service/ldn/lan_discovery.cpp
|
||||
hle/service/ldn/lan_discovery.h
|
||||
hle/service/ldn/ldn_results.h
|
||||
hle/service/ldn/ldn.cpp
|
||||
hle/service/ldn/ldn.h
|
||||
hle/service/ldn/ldn_results.h
|
||||
hle/service/ldn/ldn_types.h
|
||||
hle/service/ldr/ldr.cpp
|
||||
hle/service/ldr/ldr.h
|
||||
@ -543,16 +651,6 @@ add_library(core STATIC
|
||||
hle/service/lm/lm.h
|
||||
hle/service/mig/mig.cpp
|
||||
hle/service/mig/mig.h
|
||||
hle/service/mii/types/char_info.cpp
|
||||
hle/service/mii/types/char_info.h
|
||||
hle/service/mii/types/core_data.cpp
|
||||
hle/service/mii/types/core_data.h
|
||||
hle/service/mii/types/raw_data.cpp
|
||||
hle/service/mii/types/raw_data.h
|
||||
hle/service/mii/types/store_data.cpp
|
||||
hle/service/mii/types/store_data.h
|
||||
hle/service/mii/types/ver3_store_data.cpp
|
||||
hle/service/mii/types/ver3_store_data.h
|
||||
hle/service/mii/mii.cpp
|
||||
hle/service/mii/mii.h
|
||||
hle/service/mii/mii_database.cpp
|
||||
@ -564,10 +662,22 @@ add_library(core STATIC
|
||||
hle/service/mii/mii_result.h
|
||||
hle/service/mii/mii_types.h
|
||||
hle/service/mii/mii_util.h
|
||||
hle/service/mii/types/char_info.cpp
|
||||
hle/service/mii/types/char_info.h
|
||||
hle/service/mii/types/core_data.cpp
|
||||
hle/service/mii/types/core_data.h
|
||||
hle/service/mii/types/raw_data.cpp
|
||||
hle/service/mii/types/raw_data.h
|
||||
hle/service/mii/types/store_data.cpp
|
||||
hle/service/mii/types/store_data.h
|
||||
hle/service/mii/types/ver3_store_data.cpp
|
||||
hle/service/mii/types/ver3_store_data.h
|
||||
hle/service/mm/mm_u.cpp
|
||||
hle/service/mm/mm_u.h
|
||||
hle/service/mnpp/mnpp_app.cpp
|
||||
hle/service/mnpp/mnpp_app.h
|
||||
hle/service/mutex.cpp
|
||||
hle/service/mutex.h
|
||||
hle/service/ncm/ncm.cpp
|
||||
hle/service/ncm/ncm.h
|
||||
hle/service/nfc/common/amiibo_crypto.cpp
|
||||
@ -609,6 +719,8 @@ add_library(core STATIC
|
||||
hle/service/ns/pdm_qry.h
|
||||
hle/service/nvdrv/core/container.cpp
|
||||
hle/service/nvdrv/core/container.h
|
||||
hle/service/nvdrv/core/heap_mapper.cpp
|
||||
hle/service/nvdrv/core/heap_mapper.h
|
||||
hle/service/nvdrv/core/nvmap.cpp
|
||||
hle/service/nvdrv/core/nvmap.h
|
||||
hle/service/nvdrv/core/syncpoint_manager.cpp
|
||||
@ -689,25 +801,58 @@ add_library(core STATIC
|
||||
hle/service/prepo/prepo.h
|
||||
hle/service/psc/psc.cpp
|
||||
hle/service/psc/psc.h
|
||||
hle/service/psc/time/alarms.cpp
|
||||
hle/service/psc/time/alarms.h
|
||||
hle/service/psc/time/clocks/context_writers.cpp
|
||||
hle/service/psc/time/clocks/context_writers.h
|
||||
hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
|
||||
hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
|
||||
hle/service/psc/time/clocks/standard_local_system_clock_core.h
|
||||
hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
|
||||
hle/service/psc/time/clocks/standard_network_system_clock_core.h
|
||||
hle/service/psc/time/clocks/standard_steady_clock_core.cpp
|
||||
hle/service/psc/time/clocks/standard_steady_clock_core.h
|
||||
hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
|
||||
hle/service/psc/time/clocks/standard_user_system_clock_core.h
|
||||
hle/service/psc/time/clocks/steady_clock_core.h
|
||||
hle/service/psc/time/clocks/system_clock_core.cpp
|
||||
hle/service/psc/time/clocks/system_clock_core.h
|
||||
hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
|
||||
hle/service/psc/time/clocks/tick_based_steady_clock_core.h
|
||||
hle/service/psc/time/common.cpp
|
||||
hle/service/psc/time/common.h
|
||||
hle/service/psc/time/errors.h
|
||||
hle/service/psc/time/shared_memory.cpp
|
||||
hle/service/psc/time/shared_memory.h
|
||||
hle/service/psc/time/static.cpp
|
||||
hle/service/psc/time/static.h
|
||||
hle/service/psc/time/manager.h
|
||||
hle/service/psc/time/power_state_service.cpp
|
||||
hle/service/psc/time/power_state_service.h
|
||||
hle/service/psc/time/service_manager.cpp
|
||||
hle/service/psc/time/service_manager.h
|
||||
hle/service/psc/time/steady_clock.cpp
|
||||
hle/service/psc/time/steady_clock.h
|
||||
hle/service/psc/time/system_clock.cpp
|
||||
hle/service/psc/time/system_clock.h
|
||||
hle/service/psc/time/time_zone.cpp
|
||||
hle/service/psc/time/time_zone.h
|
||||
hle/service/psc/time/time_zone_service.cpp
|
||||
hle/service/psc/time/time_zone_service.h
|
||||
hle/service/psc/time/power_state_request_manager.cpp
|
||||
hle/service/psc/time/power_state_request_manager.h
|
||||
hle/service/ptm/psm.cpp
|
||||
hle/service/ptm/psm.h
|
||||
hle/service/ptm/ptm.cpp
|
||||
hle/service/ptm/ptm.h
|
||||
hle/service/ptm/ts.cpp
|
||||
hle/service/ptm/ts.h
|
||||
hle/service/hle_ipc.cpp
|
||||
hle/service/hle_ipc.h
|
||||
hle/service/ipc_helpers.h
|
||||
hle/service/kernel_helpers.cpp
|
||||
hle/service/kernel_helpers.h
|
||||
hle/service/mutex.cpp
|
||||
hle/service/mutex.h
|
||||
hle/service/ro/ro.cpp
|
||||
hle/service/ro/ro.h
|
||||
hle/service/ro/ro_nro_utils.cpp
|
||||
hle/service/ro/ro_nro_utils.h
|
||||
hle/service/ro/ro_results.h
|
||||
hle/service/ro/ro_types.h
|
||||
hle/service/ro/ro.cpp
|
||||
hle/service/ro/ro.h
|
||||
hle/service/server_manager.cpp
|
||||
hle/service/server_manager.h
|
||||
hle/service/service.cpp
|
||||
@ -756,40 +901,6 @@ add_library(core STATIC
|
||||
hle/service/ssl/ssl.cpp
|
||||
hle/service/ssl/ssl.h
|
||||
hle/service/ssl/ssl_backend.h
|
||||
hle/service/time/clock_types.h
|
||||
hle/service/time/ephemeral_network_system_clock_context_writer.h
|
||||
hle/service/time/ephemeral_network_system_clock_core.h
|
||||
hle/service/time/errors.h
|
||||
hle/service/time/local_system_clock_context_writer.h
|
||||
hle/service/time/network_system_clock_context_writer.h
|
||||
hle/service/time/standard_local_system_clock_core.h
|
||||
hle/service/time/standard_network_system_clock_core.h
|
||||
hle/service/time/standard_steady_clock_core.cpp
|
||||
hle/service/time/standard_steady_clock_core.h
|
||||
hle/service/time/standard_user_system_clock_core.cpp
|
||||
hle/service/time/standard_user_system_clock_core.h
|
||||
hle/service/time/steady_clock_core.h
|
||||
hle/service/time/system_clock_context_update_callback.cpp
|
||||
hle/service/time/system_clock_context_update_callback.h
|
||||
hle/service/time/system_clock_core.cpp
|
||||
hle/service/time/system_clock_core.h
|
||||
hle/service/time/tick_based_steady_clock_core.cpp
|
||||
hle/service/time/tick_based_steady_clock_core.h
|
||||
hle/service/time/time.cpp
|
||||
hle/service/time/time.h
|
||||
hle/service/time/time_interface.cpp
|
||||
hle/service/time/time_interface.h
|
||||
hle/service/time/time_manager.cpp
|
||||
hle/service/time/time_manager.h
|
||||
hle/service/time/time_sharedmemory.cpp
|
||||
hle/service/time/time_sharedmemory.h
|
||||
hle/service/time/time_zone_content_manager.cpp
|
||||
hle/service/time/time_zone_content_manager.h
|
||||
hle/service/time/time_zone_manager.cpp
|
||||
hle/service/time/time_zone_manager.h
|
||||
hle/service/time/time_zone_service.cpp
|
||||
hle/service/time/time_zone_service.h
|
||||
hle/service/time/time_zone_types.h
|
||||
hle/service/usb/usb.cpp
|
||||
hle/service/usb/usb.h
|
||||
hle/service/vi/display/vi_display.cpp
|
||||
@ -808,9 +919,9 @@ add_library(core STATIC
|
||||
internal_network/network.h
|
||||
internal_network/network_interface.cpp
|
||||
internal_network/network_interface.h
|
||||
internal_network/sockets.h
|
||||
internal_network/socket_proxy.cpp
|
||||
internal_network/socket_proxy.h
|
||||
internal_network/sockets.h
|
||||
loader/deconstructed_rom_directory.cpp
|
||||
loader/deconstructed_rom_directory.h
|
||||
loader/kip.cpp
|
||||
@ -829,13 +940,13 @@ add_library(core STATIC
|
||||
loader/nsp.h
|
||||
loader/xci.cpp
|
||||
loader/xci.h
|
||||
memory.cpp
|
||||
memory.h
|
||||
memory/cheat_engine.cpp
|
||||
memory/cheat_engine.h
|
||||
memory/dmnt_cheat_types.h
|
||||
memory/dmnt_cheat_vm.cpp
|
||||
memory/dmnt_cheat_vm.h
|
||||
memory.cpp
|
||||
memory.h
|
||||
perf_stats.cpp
|
||||
perf_stats.h
|
||||
precompiled_headers.h
|
||||
@ -870,7 +981,7 @@ endif()
|
||||
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb)
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
|
||||
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
|
||||
if (MINGW)
|
||||
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
|
||||
|
@ -21,13 +21,14 @@
|
||||
#include "core/debugger/debugger.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/file_sys/bis_factory.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/file_sys/vfs/vfs_concat.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/gpu_dirty_memory_manager.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
@ -35,13 +36,19 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/glue/time/static.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory.h"
|
||||
@ -96,7 +103,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
Common::SplitPath(path, &dir_name, &filename, nullptr);
|
||||
|
||||
if (filename == "00") {
|
||||
const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
|
||||
const auto dir = vfs->OpenDirectory(dir_name, FileSys::OpenMode::Read);
|
||||
std::vector<FileSys::VirtualFile> concat;
|
||||
|
||||
for (u32 i = 0; i < 0x10; ++i) {
|
||||
@ -121,16 +128,16 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
}
|
||||
|
||||
if (Common::FS::IsDir(path)) {
|
||||
return vfs->OpenFile(path + "/main", FileSys::Mode::Read);
|
||||
return vfs->OpenFile(path + "/main", FileSys::OpenMode::Read);
|
||||
}
|
||||
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
return vfs->OpenFile(path, FileSys::OpenMode::Read);
|
||||
}
|
||||
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
|
||||
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
|
||||
reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
|
||||
|
||||
void Initialize(System& system) {
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
@ -142,8 +149,6 @@ struct System::Impl {
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
|
||||
RefreshTime();
|
||||
|
||||
// Create a default fs if one doesn't already exist.
|
||||
if (virtual_filesystem == nullptr) {
|
||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
@ -153,7 +158,7 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
// Create default implementations of applets if one is not provided.
|
||||
applet_manager.SetDefaultAppletsIfMissing();
|
||||
frontend_applets.SetDefaultAppletsIfMissing();
|
||||
|
||||
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||
|
||||
@ -181,14 +186,57 @@ struct System::Impl {
|
||||
Initialize(system);
|
||||
}
|
||||
|
||||
void RefreshTime() {
|
||||
void RefreshTime(System& system) {
|
||||
if (!system.IsPoweredOn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto settings_service =
|
||||
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys",
|
||||
true);
|
||||
auto static_service_a =
|
||||
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:a", true);
|
||||
|
||||
auto static_service_s =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock;
|
||||
static_service_a->GetStandardUserSystemClock(user_clock);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
|
||||
static_service_a->GetStandardLocalSystemClock(local_clock);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> network_clock;
|
||||
static_service_s->GetStandardNetworkSystemClock(network_clock);
|
||||
|
||||
std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service;
|
||||
static_service_a->GetTimeZoneService(timezone_service);
|
||||
|
||||
Service::PSC::Time::LocationName name{};
|
||||
auto new_name = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
|
||||
std::memcpy(name.name.data(), new_name.data(), std::min(name.name.size(), new_name.size()));
|
||||
|
||||
timezone_service->SetDeviceLocation(name);
|
||||
|
||||
u64 time_offset = 0;
|
||||
if (Settings::values.custom_rtc_enabled) {
|
||||
time_offset = Settings::values.custom_rtc_offset.GetValue();
|
||||
}
|
||||
|
||||
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
const auto current_time =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
|
||||
Settings::values.custom_rtc_differential =
|
||||
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
|
||||
: current_time) -
|
||||
current_time;
|
||||
const u64 current_time =
|
||||
+std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
|
||||
const u64 new_time = current_time + time_offset;
|
||||
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
settings_service->SetUserSystemClockContext(context);
|
||||
user_clock->SetCurrentTime(new_time);
|
||||
|
||||
local_clock->SetCurrentTime(new_time);
|
||||
|
||||
network_clock->GetSystemClockContext(context);
|
||||
settings_service->SetNetworkSystemClockContext(context);
|
||||
network_clock->SetCurrentTime(new_time);
|
||||
}
|
||||
|
||||
void Run() {
|
||||
@ -264,9 +312,6 @@ struct System::Impl {
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
services = std::make_unique<Service::Services>(service_manager, system);
|
||||
|
||||
// Initialize time manager, which must happen after kernel is created
|
||||
time_manager.Initialize();
|
||||
|
||||
is_powered_on = true;
|
||||
exit_locked = false;
|
||||
exit_requested = false;
|
||||
@ -286,16 +331,27 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath, u64 program_id,
|
||||
std::size_t program_index) {
|
||||
const std::string& filepath,
|
||||
Service::AM::FrontendAppletParameters& params) {
|
||||
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
|
||||
program_id, program_index);
|
||||
params.program_id, params.program_index);
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
return SystemResultStatus::ErrorGetLoader;
|
||||
}
|
||||
|
||||
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM!");
|
||||
}
|
||||
|
||||
std::string name = "Unknown program";
|
||||
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to read title for ROM!");
|
||||
}
|
||||
|
||||
LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
|
||||
|
||||
InitializeKernel(system);
|
||||
|
||||
// Create the application process.
|
||||
@ -329,9 +385,14 @@ struct System::Impl {
|
||||
cheat_engine->Initialize();
|
||||
}
|
||||
|
||||
// Register with applet manager.
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
|
||||
params);
|
||||
|
||||
// All threads are started, begin main process execution, now that we're in the clear.
|
||||
main_process->Run(load_parameters->main_thread_priority,
|
||||
load_parameters->main_thread_stack_size);
|
||||
main_process->Close();
|
||||
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
@ -342,21 +403,13 @@ struct System::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
|
||||
}
|
||||
perf_stats = std::make_unique<PerfStats>(program_id);
|
||||
perf_stats = std::make_unique<PerfStats>(params.program_id);
|
||||
// Reset counters and set time origin to current frame
|
||||
GetAndResetPerfStats();
|
||||
perf_stats->BeginSystemFrame();
|
||||
|
||||
std::string name = "Unknown Game";
|
||||
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
|
||||
}
|
||||
|
||||
std::string title_version;
|
||||
const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
|
||||
const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider());
|
||||
const auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
@ -365,14 +418,15 @@ struct System::Impl {
|
||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||
Network::GameInfo game_info;
|
||||
game_info.name = name;
|
||||
game_info.id = program_id;
|
||||
game_info.id = params.program_id;
|
||||
game_info.version = title_version;
|
||||
room_member->SendGameInfo(game_info);
|
||||
}
|
||||
|
||||
// Workarounds:
|
||||
// Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
|
||||
Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL;
|
||||
Settings::values.renderer_amdvlk_depth_bias_workaround =
|
||||
params.program_id == 0x1006A800016E000ULL;
|
||||
|
||||
status = SystemResultStatus::Success;
|
||||
return status;
|
||||
@ -411,12 +465,12 @@ struct System::Impl {
|
||||
}
|
||||
kernel.CloseServices();
|
||||
kernel.ShutdownCores();
|
||||
applet_manager.Reset();
|
||||
services.reset();
|
||||
service_manager.reset();
|
||||
fs_controller.Reset();
|
||||
cheat_engine.reset();
|
||||
telemetry_session.reset();
|
||||
time_manager.Shutdown();
|
||||
core_timing.ClearPendingEvents();
|
||||
app_loader.reset();
|
||||
audio_core.reset();
|
||||
@ -523,8 +577,9 @@ struct System::Impl {
|
||||
|
||||
std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
|
||||
|
||||
/// Frontend applets
|
||||
Service::AM::Applets::AppletManager applet_manager;
|
||||
/// Applets
|
||||
Service::AM::AppletManager applet_manager;
|
||||
Service::AM::Frontend::FrontendAppletHolder frontend_applets;
|
||||
|
||||
/// APM (Performance) services
|
||||
Service::APM::Controller apm_controller{core_timing};
|
||||
@ -532,7 +587,6 @@ struct System::Impl {
|
||||
/// Service State
|
||||
Service::Glue::ARPManager arp_manager;
|
||||
Service::Account::ProfileManager profile_manager;
|
||||
Service::Time::TimeManager time_manager;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@ -565,6 +619,9 @@ struct System::Impl {
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
|
||||
|
||||
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
|
||||
gpu_dirty_memory_managers;
|
||||
|
||||
std::deque<std::vector<u8>> user_channel;
|
||||
};
|
||||
|
||||
@ -635,8 +692,8 @@ void System::InitializeDebugger() {
|
||||
}
|
||||
|
||||
SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
u64 program_id, std::size_t program_index) {
|
||||
return impl->Load(*this, emu_window, filepath, program_id, program_index);
|
||||
Service::AM::FrontendAppletParameters& params) {
|
||||
return impl->Load(*this, emu_window, filepath, params);
|
||||
}
|
||||
|
||||
bool System::IsPoweredOn() const {
|
||||
@ -651,8 +708,14 @@ size_t System::GetCurrentHostThreadID() const {
|
||||
return impl->kernel.GetCurrentHostThreadID();
|
||||
}
|
||||
|
||||
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
|
||||
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
|
||||
std::span<GPUDirtyMemoryManager> System::GetGPUDirtyMemoryManager() {
|
||||
return impl->gpu_dirty_memory_managers;
|
||||
}
|
||||
|
||||
void System::GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback) {
|
||||
for (auto& manager : impl->gpu_dirty_memory_managers) {
|
||||
manager.Gather(callback);
|
||||
}
|
||||
}
|
||||
|
||||
PerfStatsResults System::GetAndResetPerfStats() {
|
||||
@ -820,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
|
||||
}
|
||||
|
||||
void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) {
|
||||
impl->applet_manager.SetAppletFrontendSet(std::move(set));
|
||||
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
||||
impl->frontend_applets.SetFrontendAppletSet(std::move(set));
|
||||
}
|
||||
|
||||
void System::SetDefaultAppletFrontendSet() {
|
||||
impl->applet_manager.SetDefaultAppletFrontendSet();
|
||||
Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
|
||||
return impl->frontend_applets;
|
||||
}
|
||||
|
||||
Service::AM::Applets::AppletManager& System::GetAppletManager() {
|
||||
return impl->applet_manager;
|
||||
const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
|
||||
return impl->frontend_applets;
|
||||
}
|
||||
|
||||
const Service::AM::Applets::AppletManager& System::GetAppletManager() const {
|
||||
Service::AM::AppletManager& System::GetAppletManager() {
|
||||
return impl->applet_manager;
|
||||
}
|
||||
|
||||
@ -901,14 +964,6 @@ const Service::Account::ProfileManager& System::GetProfileManager() const {
|
||||
return impl->profile_manager;
|
||||
}
|
||||
|
||||
Service::Time::TimeManager& System::GetTimeManager() {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
const Service::Time::TimeManager& System::GetTimeManager() const {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
void System::SetExitLocked(bool locked) {
|
||||
impl->exit_locked = locked;
|
||||
}
|
||||
@ -1020,13 +1075,9 @@ void System::Exit() {
|
||||
}
|
||||
|
||||
void System::ApplySettings() {
|
||||
impl->RefreshTime();
|
||||
impl->RefreshTime(*this);
|
||||
|
||||
if (IsPoweredOn()) {
|
||||
if (Settings::values.custom_rtc_enabled) {
|
||||
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
|
||||
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
|
||||
}
|
||||
Renderer().RefreshBaseSettings();
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,12 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
@ -49,10 +50,15 @@ namespace Account {
|
||||
class ProfileManager;
|
||||
} // namespace Account
|
||||
|
||||
namespace AM::Applets {
|
||||
struct AppletFrontendSet;
|
||||
namespace AM {
|
||||
struct FrontendAppletParameters;
|
||||
class AppletManager;
|
||||
} // namespace AM::Applets
|
||||
} // namespace AM
|
||||
|
||||
namespace AM::Frontend {
|
||||
struct FrontendAppletSet;
|
||||
class FrontendAppletHolder;
|
||||
} // namespace AM::Frontend
|
||||
|
||||
namespace APM {
|
||||
class Controller;
|
||||
@ -72,10 +78,6 @@ namespace SM {
|
||||
class ServiceManager;
|
||||
} // namespace SM
|
||||
|
||||
namespace Time {
|
||||
class TimeManager;
|
||||
} // namespace Time
|
||||
|
||||
} // namespace Service
|
||||
|
||||
namespace Tegra {
|
||||
@ -116,6 +118,7 @@ class CpuManager;
|
||||
class Debugger;
|
||||
class DeviceMemory;
|
||||
class ExclusiveMonitor;
|
||||
class GPUDirtyMemoryManager;
|
||||
class PerfStats;
|
||||
class Reporter;
|
||||
class SpeedLimiter;
|
||||
@ -205,8 +208,8 @@ public:
|
||||
* @returns SystemResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
[[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath, u64 program_id = 0,
|
||||
std::size_t program_index = 0);
|
||||
const std::string& filepath,
|
||||
Service::AM::FrontendAppletParameters& params);
|
||||
|
||||
/**
|
||||
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
||||
@ -224,7 +227,9 @@ public:
|
||||
/// Prepare the core emulation for a reschedule
|
||||
void PrepareReschedule(u32 core_index);
|
||||
|
||||
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
|
||||
std::span<GPUDirtyMemoryManager> GetGPUDirtyMemoryManager();
|
||||
|
||||
void GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback);
|
||||
|
||||
[[nodiscard]] size_t GetCurrentHostThreadID() const;
|
||||
|
||||
@ -344,11 +349,13 @@ public:
|
||||
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
|
||||
u64 main_region_size);
|
||||
|
||||
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
|
||||
void SetDefaultAppletFrontendSet();
|
||||
void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
|
||||
|
||||
[[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
|
||||
[[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
|
||||
[[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
|
||||
[[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
|
||||
const;
|
||||
|
||||
[[nodiscard]] Service::AM::AppletManager& GetAppletManager();
|
||||
|
||||
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
|
||||
|
||||
@ -377,9 +384,6 @@ public:
|
||||
[[nodiscard]] Service::Account::ProfileManager& GetProfileManager();
|
||||
[[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const;
|
||||
|
||||
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
|
||||
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
|
||||
|
||||
[[nodiscard]] Core::Debugger& GetDebugger();
|
||||
[[nodiscard]] const Core::Debugger& GetDebugger() const;
|
||||
|
||||
|
@ -157,7 +157,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
}
|
||||
}
|
||||
|
||||
for (auto h : to_remove) {
|
||||
for (auto& h : to_remove) {
|
||||
event_queue.erase(h);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
|
@ -21,9 +21,9 @@
|
||||
#include "core/crypto/partition_data_manager.h"
|
||||
#include "core/crypto/xts_encryption_layer.h"
|
||||
#include "core/file_sys/kernel_executable.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_offset.h"
|
||||
#include "core/file_sys/vfs/vfs_vector.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
using Common::AsArray;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
|
@ -31,6 +31,12 @@ public:
|
||||
DramMemoryMap::Base;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PAddr GetRawPhysicalAddr(const T* ptr) const {
|
||||
return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) -
|
||||
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* GetPointer(Common::PhysicalAddress addr) {
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() +
|
||||
@ -43,6 +49,16 @@ public:
|
||||
(GetInteger(addr) - DramMemoryMap::Base));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* GetPointerFromRaw(PAddr addr) {
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* GetPointerFromRaw(PAddr addr) const {
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
|
||||
}
|
||||
|
||||
Common::HostMemory buffer;
|
||||
};
|
||||
|
||||
|
212
src/core/device_memory_manager.h
Normal file
212
src/core/device_memory_manager.h
Normal file
@ -0,0 +1,212 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/range_mutex.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
constexpr size_t DEVICE_PAGEBITS = 12ULL;
|
||||
constexpr size_t DEVICE_PAGESIZE = 1ULL << DEVICE_PAGEBITS;
|
||||
constexpr size_t DEVICE_PAGEMASK = DEVICE_PAGESIZE - 1ULL;
|
||||
|
||||
class DeviceMemory;
|
||||
|
||||
namespace Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
template <typename DTraits>
|
||||
struct DeviceMemoryManagerAllocator;
|
||||
|
||||
struct Asid {
|
||||
size_t id;
|
||||
};
|
||||
|
||||
template <typename Traits>
|
||||
class DeviceMemoryManager {
|
||||
using DeviceInterface = typename Traits::DeviceInterface;
|
||||
using DeviceMethods = typename Traits::DeviceMethods;
|
||||
|
||||
public:
|
||||
DeviceMemoryManager(const DeviceMemory& device_memory);
|
||||
~DeviceMemoryManager();
|
||||
|
||||
void BindInterface(DeviceInterface* device_inter);
|
||||
|
||||
DAddr Allocate(size_t size);
|
||||
void AllocateFixed(DAddr start, size_t size);
|
||||
void Free(DAddr start, size_t size);
|
||||
|
||||
void Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, bool track = false);
|
||||
|
||||
void Unmap(DAddr address, size_t size);
|
||||
|
||||
void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, Asid asid);
|
||||
void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, Asid asid) {
|
||||
std::scoped_lock lk(mapping_guard);
|
||||
TrackContinuityImpl(address, virtual_address, size, asid);
|
||||
}
|
||||
|
||||
// Write / Read
|
||||
template <typename T>
|
||||
T* GetPointer(DAddr address);
|
||||
|
||||
template <typename T>
|
||||
const T* GetPointer(DAddr address) const;
|
||||
|
||||
template <typename Func>
|
||||
void ApplyOpOnPAddr(PAddr address, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
|
||||
DAddr subbits = static_cast<DAddr>(address & page_mask);
|
||||
const u32 base = compressed_device_addr[(address >> page_bits)];
|
||||
if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] {
|
||||
const DAddr d_address = (static_cast<DAddr>(base) << page_bits) + subbits;
|
||||
operation(d_address);
|
||||
return;
|
||||
}
|
||||
InnerGatherDeviceAddresses(buffer, address);
|
||||
for (u32 value : buffer) {
|
||||
operation((static_cast<DAddr>(value) << page_bits) + subbits);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void ApplyOpOnPointer(const u8* p, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
|
||||
PAddr address = GetRawPhysicalAddr<u8>(p);
|
||||
ApplyOpOnPAddr(address, buffer, operation);
|
||||
}
|
||||
|
||||
PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
|
||||
PAddr subbits = static_cast<PAddr>(address & page_mask);
|
||||
auto paddr = compressed_physical_ptr[(address >> page_bits)];
|
||||
if (paddr == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (static_cast<PAddr>(paddr - 1) << page_bits) + subbits;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Write(DAddr address, T value);
|
||||
|
||||
template <typename T>
|
||||
T Read(DAddr address) const;
|
||||
|
||||
u8* GetSpan(const DAddr src_addr, const std::size_t size);
|
||||
const u8* GetSpan(const DAddr src_addr, const std::size_t size) const;
|
||||
|
||||
void ReadBlock(DAddr address, void* dest_pointer, size_t size);
|
||||
void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size);
|
||||
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
|
||||
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
|
||||
|
||||
Asid RegisterProcess(Memory::Memory* memory);
|
||||
void UnregisterProcess(Asid id);
|
||||
|
||||
void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta);
|
||||
|
||||
static constexpr size_t AS_BITS = Traits::device_virtual_bits;
|
||||
|
||||
private:
|
||||
static constexpr size_t device_virtual_bits = Traits::device_virtual_bits;
|
||||
static constexpr size_t device_as_size = 1ULL << device_virtual_bits;
|
||||
static constexpr size_t physical_min_bits = 32;
|
||||
static constexpr size_t physical_max_bits = 33;
|
||||
static constexpr size_t page_bits = 12;
|
||||
static constexpr size_t page_size = 1ULL << page_bits;
|
||||
static constexpr size_t page_mask = page_size - 1ULL;
|
||||
static constexpr u32 physical_address_base = 1U << page_bits;
|
||||
static constexpr u32 MULTI_FLAG_BITS = 31;
|
||||
static constexpr u32 MULTI_FLAG = 1U << MULTI_FLAG_BITS;
|
||||
static constexpr u32 MULTI_MASK = ~MULTI_FLAG;
|
||||
|
||||
template <typename T>
|
||||
T* GetPointerFromRaw(PAddr addr) {
|
||||
return reinterpret_cast<T*>(physical_base + addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* GetPointerFromRaw(PAddr addr) const {
|
||||
return reinterpret_cast<T*>(physical_base + addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PAddr GetRawPhysicalAddr(const T* ptr) const {
|
||||
return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) - physical_base);
|
||||
}
|
||||
|
||||
void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory,
|
||||
auto increment);
|
||||
|
||||
void InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer, PAddr address);
|
||||
|
||||
std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
|
||||
|
||||
const uintptr_t physical_base;
|
||||
DeviceInterface* device_inter;
|
||||
Common::VirtualBuffer<u32> compressed_physical_ptr;
|
||||
Common::VirtualBuffer<u32> compressed_device_addr;
|
||||
Common::VirtualBuffer<u32> continuity_tracker;
|
||||
|
||||
// Process memory interfaces
|
||||
|
||||
std::deque<size_t> id_pool;
|
||||
std::deque<Memory::Memory*> registered_processes;
|
||||
|
||||
// Memory protection management
|
||||
|
||||
static constexpr size_t guest_max_as_bits = 39;
|
||||
static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits;
|
||||
static constexpr size_t guest_mask = guest_as_size - 1ULL;
|
||||
static constexpr size_t asid_start_bit = guest_max_as_bits;
|
||||
|
||||
std::pair<Asid, VAddr> ExtractCPUBacking(size_t page_index) {
|
||||
auto content = cpu_backing_address[page_index];
|
||||
const VAddr address = content & guest_mask;
|
||||
const Asid asid{static_cast<size_t>(content >> asid_start_bit)};
|
||||
return std::make_pair(asid, address);
|
||||
}
|
||||
|
||||
void InsertCPUBacking(size_t page_index, VAddr address, Asid asid) {
|
||||
cpu_backing_address[page_index] = address | (asid.id << asid_start_bit);
|
||||
}
|
||||
|
||||
Common::VirtualBuffer<VAddr> cpu_backing_address;
|
||||
static constexpr size_t subentries = 8 / sizeof(u8);
|
||||
static constexpr size_t subentries_mask = subentries - 1;
|
||||
class CounterEntry final {
|
||||
public:
|
||||
CounterEntry() = default;
|
||||
|
||||
std::atomic_uint8_t& Count(std::size_t page) {
|
||||
return values[page & subentries_mask];
|
||||
}
|
||||
|
||||
const std::atomic_uint8_t& Count(std::size_t page) const {
|
||||
return values[page & subentries_mask];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<std::atomic_uint8_t, subentries> values{};
|
||||
};
|
||||
static_assert(sizeof(CounterEntry) == subentries * sizeof(u8),
|
||||
"CounterEntry should be 8 bytes!");
|
||||
|
||||
static constexpr size_t num_counter_entries =
|
||||
(1ULL << (device_virtual_bits - page_bits)) / subentries;
|
||||
using CachedPages = std::array<CounterEntry, num_counter_entries>;
|
||||
std::unique_ptr<CachedPages> cached_pages;
|
||||
Common::RangeMutex counter_guard;
|
||||
std::mutex mapping_guard;
|
||||
};
|
||||
|
||||
} // namespace Core
|
572
src/core/device_memory_manager.inc
Normal file
572
src/core/device_memory_manager.inc
Normal file
@ -0,0 +1,572 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/address_space.h"
|
||||
#include "common/address_space.inc"
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/device_memory_manager.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
class MultiAddressContainer {
|
||||
public:
|
||||
MultiAddressContainer() = default;
|
||||
~MultiAddressContainer() = default;
|
||||
|
||||
void GatherValues(u32 start_entry, Common::ScratchBuffer<u32>& buffer) {
|
||||
buffer.resize(8);
|
||||
buffer.resize(0);
|
||||
size_t index = 0;
|
||||
const auto add_value = [&](u32 value) {
|
||||
buffer.resize(index + 1);
|
||||
buffer[index++] = value;
|
||||
};
|
||||
|
||||
u32 iter_entry = start_entry;
|
||||
Entry* current = &storage[iter_entry - 1];
|
||||
add_value(current->value);
|
||||
while (current->next_entry != 0) {
|
||||
iter_entry = current->next_entry;
|
||||
current = &storage[iter_entry - 1];
|
||||
add_value(current->value);
|
||||
}
|
||||
}
|
||||
|
||||
u32 Register(u32 value) {
|
||||
return RegisterImplementation(value);
|
||||
}
|
||||
|
||||
void Register(u32 value, u32 start_entry) {
|
||||
auto entry_id = RegisterImplementation(value);
|
||||
u32 iter_entry = start_entry;
|
||||
Entry* current = &storage[iter_entry - 1];
|
||||
while (current->next_entry != 0) {
|
||||
iter_entry = current->next_entry;
|
||||
current = &storage[iter_entry - 1];
|
||||
}
|
||||
current->next_entry = entry_id;
|
||||
}
|
||||
|
||||
std::pair<bool, u32> Unregister(u32 value, u32 start_entry) {
|
||||
u32 iter_entry = start_entry;
|
||||
Entry* previous{};
|
||||
Entry* current = &storage[iter_entry - 1];
|
||||
Entry* next{};
|
||||
bool more_than_one_remaining = false;
|
||||
u32 result_start{start_entry};
|
||||
size_t count = 0;
|
||||
while (current->value != value) {
|
||||
count++;
|
||||
previous = current;
|
||||
iter_entry = current->next_entry;
|
||||
current = &storage[iter_entry - 1];
|
||||
}
|
||||
// Find next
|
||||
u32 next_entry = current->next_entry;
|
||||
if (next_entry != 0) {
|
||||
next = &storage[next_entry - 1];
|
||||
more_than_one_remaining = next->next_entry != 0 || previous != nullptr;
|
||||
}
|
||||
if (previous) {
|
||||
previous->next_entry = next_entry;
|
||||
} else {
|
||||
result_start = next_entry;
|
||||
}
|
||||
free_entries.emplace_back(iter_entry);
|
||||
return std::make_pair(more_than_one_remaining || count > 1, result_start);
|
||||
}
|
||||
|
||||
u32 ReleaseEntry(u32 start_entry) {
|
||||
Entry* current = &storage[start_entry - 1];
|
||||
free_entries.emplace_back(start_entry);
|
||||
return current->value;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 RegisterImplementation(u32 value) {
|
||||
auto entry_id = GetNewEntry();
|
||||
auto& entry = storage[entry_id - 1];
|
||||
entry.next_entry = 0;
|
||||
entry.value = value;
|
||||
return entry_id;
|
||||
}
|
||||
u32 GetNewEntry() {
|
||||
if (!free_entries.empty()) {
|
||||
u32 result = free_entries.front();
|
||||
free_entries.pop_front();
|
||||
return result;
|
||||
}
|
||||
storage.emplace_back();
|
||||
u32 new_entry = static_cast<u32>(storage.size());
|
||||
return new_entry;
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
u32 next_entry{};
|
||||
u32 value{};
|
||||
};
|
||||
|
||||
std::deque<Entry> storage;
|
||||
std::deque<u32> free_entries;
|
||||
};
|
||||
|
||||
struct EmptyAllocator {
|
||||
EmptyAllocator([[maybe_unused]] DAddr address) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename DTraits>
|
||||
struct DeviceMemoryManagerAllocator {
|
||||
static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits;
|
||||
static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS;
|
||||
static constexpr DAddr max_device_area = 1ULL << device_virtual_bits;
|
||||
|
||||
DeviceMemoryManagerAllocator() : main_allocator(first_address) {}
|
||||
|
||||
Common::FlatAllocator<DAddr, 0, device_virtual_bits> main_allocator;
|
||||
MultiAddressContainer multi_dev_address;
|
||||
|
||||
/// Returns true when vaddr -> vaddr+size is fully contained in the buffer
|
||||
template <bool pin_area>
|
||||
[[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept {
|
||||
return addr >= 0 && addr + size <= max_device_area;
|
||||
}
|
||||
|
||||
DAddr Allocate(size_t size) {
|
||||
return main_allocator.Allocate(size);
|
||||
}
|
||||
|
||||
void AllocateFixed(DAddr b_address, size_t b_size) {
|
||||
main_allocator.AllocateFixed(b_address, b_size);
|
||||
}
|
||||
|
||||
void Free(DAddr b_address, size_t b_size) {
|
||||
main_allocator.Free(b_address, b_size);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
|
||||
: physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())},
|
||||
device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS),
|
||||
compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
|
||||
Settings::MemoryLayout::Memory_4Gb
|
||||
? physical_min_bits
|
||||
: physical_max_bits) -
|
||||
Memory::YUZU_PAGEBITS)),
|
||||
continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS),
|
||||
cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) {
|
||||
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
|
||||
cached_pages = std::make_unique<CachedPages>();
|
||||
|
||||
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
|
||||
for (size_t i = 0; i < total_virtual; i++) {
|
||||
compressed_physical_ptr[i] = 0;
|
||||
continuity_tracker[i] = 1;
|
||||
cpu_backing_address[i] = 0;
|
||||
}
|
||||
const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
|
||||
Settings::MemoryLayout::Memory_4Gb
|
||||
? physical_min_bits
|
||||
: physical_max_bits) -
|
||||
Memory::YUZU_PAGEBITS);
|
||||
for (size_t i = 0; i < total_phys; i++) {
|
||||
compressed_device_addr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::~DeviceMemoryManager() = default;
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::BindInterface(DeviceInterface* device_inter_) {
|
||||
device_inter = device_inter_;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
DAddr DeviceMemoryManager<Traits>::Allocate(size_t size) {
|
||||
return impl->Allocate(size);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::AllocateFixed(DAddr start, size_t size) {
|
||||
return impl->AllocateFixed(start, size);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
|
||||
impl->Free(start, size);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
|
||||
Asid asid, bool track) {
|
||||
Core::Memory::Memory* process_memory = registered_processes[asid.id];
|
||||
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
||||
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
||||
std::scoped_lock lk(mapping_guard);
|
||||
for (size_t i = 0; i < num_pages; i++) {
|
||||
const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE;
|
||||
auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress));
|
||||
if (ptr == nullptr) [[unlikely]] {
|
||||
compressed_physical_ptr[start_page_d + i] = 0;
|
||||
continue;
|
||||
}
|
||||
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
|
||||
compressed_physical_ptr[start_page_d + i] = phys_addr;
|
||||
InsertCPUBacking(start_page_d + i, new_vaddress, asid);
|
||||
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
||||
const u32 new_dev = static_cast<u32>(start_page_d + i);
|
||||
if (base_dev == 0) [[likely]] {
|
||||
compressed_device_addr[phys_addr - 1U] = new_dev;
|
||||
continue;
|
||||
}
|
||||
u32 start_id = base_dev & MULTI_MASK;
|
||||
if ((base_dev >> MULTI_FLAG_BITS) == 0) {
|
||||
start_id = impl->multi_dev_address.Register(base_dev);
|
||||
compressed_device_addr[phys_addr - 1U] = MULTI_FLAG | start_id;
|
||||
}
|
||||
impl->multi_dev_address.Register(new_dev, start_id);
|
||||
}
|
||||
if (track) {
|
||||
TrackContinuityImpl(address, virtual_address, size, asid);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
|
||||
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
||||
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
||||
device_inter->InvalidateRegion(address, size);
|
||||
std::scoped_lock lk(mapping_guard);
|
||||
for (size_t i = 0; i < num_pages; i++) {
|
||||
auto phys_addr = compressed_physical_ptr[start_page_d + i];
|
||||
compressed_physical_ptr[start_page_d + i] = 0;
|
||||
cpu_backing_address[start_page_d + i] = 0;
|
||||
if (phys_addr != 0) [[likely]] {
|
||||
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
||||
if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
|
||||
compressed_device_addr[phys_addr - 1] = 0;
|
||||
continue;
|
||||
}
|
||||
const auto [more_entries, new_start] = impl->multi_dev_address.Unregister(
|
||||
static_cast<u32>(start_page_d + i), base_dev & MULTI_MASK);
|
||||
if (!more_entries) {
|
||||
compressed_device_addr[phys_addr - 1] =
|
||||
impl->multi_dev_address.ReleaseEntry(new_start);
|
||||
continue;
|
||||
}
|
||||
compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
|
||||
size_t size, Asid asid) {
|
||||
Core::Memory::Memory* process_memory = registered_processes[asid.id];
|
||||
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
||||
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
||||
uintptr_t last_ptr = 0;
|
||||
size_t page_count = 1;
|
||||
for (size_t i = num_pages; i > 0; i--) {
|
||||
size_t index = i - 1;
|
||||
const VAddr new_vaddress = virtual_address + index * Memory::YUZU_PAGESIZE;
|
||||
const uintptr_t new_ptr = reinterpret_cast<uintptr_t>(
|
||||
process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress)));
|
||||
if (new_ptr + page_size == last_ptr) {
|
||||
page_count++;
|
||||
} else {
|
||||
page_count = 1;
|
||||
}
|
||||
last_ptr = new_ptr;
|
||||
continuity_tracker[start_page_d + index] = static_cast<u32>(page_count);
|
||||
}
|
||||
}
|
||||
template <typename Traits>
|
||||
u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) {
|
||||
size_t page_index = src_addr >> page_bits;
|
||||
size_t subbits = src_addr & page_mask;
|
||||
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
|
||||
return GetPointer<u8>(src_addr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
const u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) const {
|
||||
size_t page_index = src_addr >> page_bits;
|
||||
size_t subbits = src_addr & page_mask;
|
||||
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
|
||||
return GetPointer<u8>(src_addr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
|
||||
PAddr address) {
|
||||
size_t phys_addr = address >> page_bits;
|
||||
std::scoped_lock lk(mapping_guard);
|
||||
u32 backing = compressed_device_addr[phys_addr];
|
||||
if ((backing >> MULTI_FLAG_BITS) != 0) {
|
||||
impl->multi_dev_address.GatherValues(backing & MULTI_MASK, buffer);
|
||||
return;
|
||||
}
|
||||
buffer.resize(1);
|
||||
buffer[0] = backing;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
template <typename T>
|
||||
T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
|
||||
const size_t index = address >> Memory::YUZU_PAGEBITS;
|
||||
const size_t offset = address & Memory::YUZU_PAGEMASK;
|
||||
auto phys_addr = compressed_physical_ptr[index];
|
||||
if (phys_addr == 0) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
|
||||
offset);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
template <typename T>
|
||||
const T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) const {
|
||||
const size_t index = address >> Memory::YUZU_PAGEBITS;
|
||||
const size_t offset = address & Memory::YUZU_PAGEMASK;
|
||||
auto phys_addr = compressed_physical_ptr[index];
|
||||
if (phys_addr == 0) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
|
||||
offset);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
template <typename T>
|
||||
void DeviceMemoryManager<Traits>::Write(DAddr address, T value) {
|
||||
T* ptr = GetPointer<T>(address);
|
||||
if (!ptr) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
std::memcpy(ptr, &value, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
template <typename T>
|
||||
T DeviceMemoryManager<Traits>::Read(DAddr address) const {
|
||||
const T* ptr = GetPointer<T>(address);
|
||||
T result{};
|
||||
if (!ptr) [[unlikely]] {
|
||||
return result;
|
||||
}
|
||||
std::memcpy(&result, ptr, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped,
|
||||
auto on_memory, auto increment) {
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = addr >> Memory::YUZU_PAGEBITS;
|
||||
std::size_t page_offset = addr & Memory::YUZU_PAGEMASK;
|
||||
|
||||
while (remaining_size) {
|
||||
const size_t next_pages = static_cast<std::size_t>(continuity_tracker[page_index]);
|
||||
const std::size_t copy_amount =
|
||||
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
|
||||
const auto current_vaddr =
|
||||
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
SCOPE_EXIT({
|
||||
page_index += next_pages;
|
||||
page_offset = 0;
|
||||
increment(copy_amount);
|
||||
remaining_size -= copy_amount;
|
||||
});
|
||||
|
||||
auto phys_addr = compressed_physical_ptr[page_index];
|
||||
if (phys_addr == 0) {
|
||||
on_unmapped(copy_amount, current_vaddr);
|
||||
continue;
|
||||
}
|
||||
auto* mem_ptr = GetPointerFromRaw<u8>(
|
||||
(static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
on_memory(copy_amount, mem_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) {
|
||||
device_inter->FlushRegion(address, size);
|
||||
WalkBlock(
|
||||
address, size,
|
||||
[&](size_t copy_amount, DAddr current_vaddr) {
|
||||
LOG_ERROR(
|
||||
HW_Memory,
|
||||
"Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
|
||||
current_vaddr, address, size);
|
||||
std::memset(dest_pointer, 0, copy_amount);
|
||||
},
|
||||
[&](size_t copy_amount, const u8* const src_ptr) {
|
||||
std::memcpy(dest_pointer, src_ptr, copy_amount);
|
||||
},
|
||||
[&](const std::size_t copy_amount) {
|
||||
dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, const void* src_pointer, size_t size) {
|
||||
WalkBlock(
|
||||
address, size,
|
||||
[&](size_t copy_amount, DAddr current_vaddr) {
|
||||
LOG_ERROR(
|
||||
HW_Memory,
|
||||
"Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
|
||||
current_vaddr, address, size);
|
||||
},
|
||||
[&](size_t copy_amount, u8* const dst_ptr) {
|
||||
std::memcpy(dst_ptr, src_pointer, copy_amount);
|
||||
},
|
||||
[&](const std::size_t copy_amount) {
|
||||
src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
|
||||
});
|
||||
device_inter->InvalidateRegion(address, size);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) {
|
||||
WalkBlock(
|
||||
address, size,
|
||||
[&](size_t copy_amount, DAddr current_vaddr) {
|
||||
LOG_ERROR(
|
||||
HW_Memory,
|
||||
"Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
|
||||
current_vaddr, address, size);
|
||||
std::memset(dest_pointer, 0, copy_amount);
|
||||
},
|
||||
[&](size_t copy_amount, const u8* const src_ptr) {
|
||||
std::memcpy(dest_pointer, src_ptr, copy_amount);
|
||||
},
|
||||
[&](const std::size_t copy_amount) {
|
||||
dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::WriteBlockUnsafe(DAddr address, const void* src_pointer,
|
||||
size_t size) {
|
||||
WalkBlock(
|
||||
address, size,
|
||||
[&](size_t copy_amount, DAddr current_vaddr) {
|
||||
LOG_ERROR(
|
||||
HW_Memory,
|
||||
"Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
|
||||
current_vaddr, address, size);
|
||||
},
|
||||
[&](size_t copy_amount, u8* const dst_ptr) {
|
||||
std::memcpy(dst_ptr, src_pointer, copy_amount);
|
||||
},
|
||||
[&](const std::size_t copy_amount) {
|
||||
src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
Asid DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_inter) {
|
||||
size_t new_id{};
|
||||
if (!id_pool.empty()) {
|
||||
new_id = id_pool.front();
|
||||
id_pool.pop_front();
|
||||
registered_processes[new_id] = memory_device_inter;
|
||||
} else {
|
||||
registered_processes.emplace_back(memory_device_inter);
|
||||
new_id = registered_processes.size() - 1U;
|
||||
}
|
||||
return Asid{new_id};
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
|
||||
registered_processes[asid.id] = nullptr;
|
||||
id_pool.push_front(asid.id);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
|
||||
Common::ScopedRangeLock lk(counter_guard, addr, size);
|
||||
u64 uncache_begin = 0;
|
||||
u64 cache_begin = 0;
|
||||
u64 uncache_bytes = 0;
|
||||
u64 cache_bytes = 0;
|
||||
const auto MarkRegionCaching = &DeviceMemoryManager<Traits>::DeviceMethods::MarkRegionCaching;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
|
||||
size_t page = addr >> Memory::YUZU_PAGEBITS;
|
||||
auto [asid, base_vaddress] = ExtractCPUBacking(page);
|
||||
size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
|
||||
auto* memory_device_inter = registered_processes[asid.id];
|
||||
for (; page != page_end; ++page) {
|
||||
std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page);
|
||||
|
||||
if (delta > 0) {
|
||||
ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(),
|
||||
"Count may overflow!");
|
||||
} else if (delta < 0) {
|
||||
ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
|
||||
} else {
|
||||
ASSERT_MSG(false, "Delta must be non-zero!");
|
||||
}
|
||||
|
||||
// Adds or subtracts 1, as count is a unsigned 8-bit value
|
||||
count.fetch_add(static_cast<u8>(delta), std::memory_order_release);
|
||||
|
||||
// Assume delta is either -1 or 1
|
||||
if (count.load(std::memory_order::relaxed) == 0) {
|
||||
if (uncache_bytes == 0) {
|
||||
uncache_begin = vpage;
|
||||
}
|
||||
uncache_bytes += Memory::YUZU_PAGESIZE;
|
||||
} else if (uncache_bytes > 0) {
|
||||
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
|
||||
uncache_bytes, false);
|
||||
uncache_bytes = 0;
|
||||
}
|
||||
if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
|
||||
if (cache_bytes == 0) {
|
||||
cache_begin = vpage;
|
||||
}
|
||||
cache_bytes += Memory::YUZU_PAGESIZE;
|
||||
} else if (cache_bytes > 0) {
|
||||
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
||||
true);
|
||||
cache_bytes = 0;
|
||||
}
|
||||
vpage++;
|
||||
}
|
||||
if (uncache_bytes > 0) {
|
||||
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
|
||||
false);
|
||||
}
|
||||
if (cache_bytes > 0) {
|
||||
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
@ -4,9 +4,8 @@
|
||||
#include <fmt/format.h>
|
||||
#include "common/fs/path_util.h"
|
||||
#include "core/file_sys/bis_factory.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@ -84,7 +83,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
|
||||
VirtualFilesystem file_system) const {
|
||||
auto& keys = Core::Crypto::KeyManager::Instance();
|
||||
Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
|
||||
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), Mode::Read)};
|
||||
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), OpenMode::Read)};
|
||||
keys.PopulateFromPartitionData(pdm);
|
||||
|
||||
switch (id) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/partition_filesystem.h"
|
||||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
#include "core/file_sys/vfs/vfs_offset.h"
|
||||
#include "core/file_sys/vfs/vfs_vector.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
class KeyManager;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/partition_filesystem.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs/vfs_offset.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
#include "core/file_sys/fssystem/fssystem_compression_configuration.h"
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace Loader {
|
||||
enum class ResultStatus : u16;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "common/string_util.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
enum class EntryType : u8 {
|
||||
Directory = 0,
|
||||
File = 1,
|
||||
};
|
||||
|
||||
// Structure of a directory entry, from
|
||||
// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
|
||||
struct Entry {
|
||||
Entry(std::string_view view, EntryType entry_type, u64 entry_size)
|
||||
: type{entry_type}, file_size{entry_size} {
|
||||
const std::size_t copy_size = view.copy(filename, std::size(filename) - 1);
|
||||
filename[copy_size] = '\0';
|
||||
}
|
||||
|
||||
char filename[0x301];
|
||||
INSERT_PADDING_BYTES(3);
|
||||
EntryType type;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u64 file_size;
|
||||
};
|
||||
static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!");
|
||||
static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry.");
|
||||
static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
|
||||
|
||||
} // namespace FileSys
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user