Compare commits

..

1 Commits

Author SHA1 Message Date
xbzk a3578fafdd [android, ui] remove the wash (white tint) of focused game cards) 2026-08-22 19:00:55 -03:00
201 changed files with 1608 additions and 4146 deletions
@@ -624,7 +624,6 @@ abstract class SettingsItem(
IntSetting.FSR_SHARPENING_SLIDER,
titleId = R.string.fsr_sharpness,
descriptionId = R.string.fsr_sharpness_description,
max = 200,
units = "%"
)
)
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,6 +24,6 @@ object SettingsFile {
fun loadCustomConfig(game: Game) {
val fileName = FileUtil.getFilename(Uri.parse(game.path))
NativeConfig.initializePerGameConfig(game.applicationId, fileName)
NativeConfig.initializePerGameConfig(game.programId, fileName)
}
}
@@ -189,7 +189,7 @@ class AddonsFragment : Fragment() {
fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel,
documents = documents,
programId = args.game.applicationId
programId = args.game.programId
)
}
@@ -347,7 +347,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
try {
if (GpuDriverHelper.isAdrenoGpu()) {
val programIdHex = game!!.applicationIdHex
val programIdHex = game!!.programIdHex
if (NativeFreedrenoConfig.loadPerGameConfigWithGlobalFallback(programIdHex)) {
Log.info("[EmulationFragment] Loaded per-game Freedreno config for $programIdHex")
} else {
@@ -1182,7 +1182,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
container,
IntSetting.FSR_SHARPENING_SLIDER,
minValue = 0,
maxValue = 200,
maxValue = 100,
units = "%"
)
}
@@ -59,7 +59,7 @@ class FreedrenoSettingsFragment : Fragment() {
NativeFreedrenoConfig.initializeFreedrenoConfig()
if (isPerGameConfig) {
NativeFreedrenoConfig.loadPerGameConfig(game!!.applicationIdHex)
NativeFreedrenoConfig.loadPerGameConfig(game!!.programIdHex)
} else {
NativeFreedrenoConfig.reloadFreedrenoConfig()
}
@@ -157,7 +157,7 @@ class FreedrenoSettingsFragment : Fragment() {
binding.buttonSave.setOnClickListener {
if (isPerGameConfig) {
NativeFreedrenoConfig.savePerGameConfig(game!!.applicationIdHex)
NativeFreedrenoConfig.savePerGameConfig(game!!.programIdHex)
showSnackbar(getString(R.string.freedreno_per_game_saved))
} else {
NativeFreedrenoConfig.saveFreedrenoConfig()
@@ -455,7 +455,7 @@ class GamePropertiesFragment : Fragment() {
val shaderCacheDir = File(
DirectoryInitialization.userDirectory +
"/cache/shader/" + args.game.shaderCacheName.lowercase()
"/cache/shader/" + args.game.settingsName.lowercase()
)
if (shaderCacheDir.exists()) {
add(
@@ -600,7 +600,7 @@ class GamePropertiesFragment : Fragment() {
val files = cacheSaveDir.listFiles()
var savesFolderFile: File? = null
if (files != null) {
val savesFolderName = args.game.applicationIdHex
val savesFolderName = args.game.programIdHex
for (file in files) {
if (file.isDirectory && file.name == savesFolderName) {
savesFolderFile = file
@@ -232,7 +232,7 @@ class InstallableFragment : Fragment() {
fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel,
documents = documents,
programId = addonViewModel.game?.applicationId
programId = addonViewModel.game?.programId
)
}
@@ -142,11 +142,10 @@ class AddonViewModel : ViewModel() {
}
fun onDeleteAddon(patch: Patch) {
val currentGame = game ?: return
when (PatchType.from(patch.type)) {
PatchType.Update -> NativeLibrary.removeUpdate(currentGame.programId)
PatchType.DLC -> NativeLibrary.removeDLC(currentGame.applicationId)
PatchType.Mod -> NativeLibrary.removeMod(currentGame.programId, patch.name)
PatchType.Update -> NativeLibrary.removeUpdate(patch.programId)
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
refreshAddons(force = true)
}
@@ -166,7 +165,7 @@ class AddonViewModel : ViewModel() {
}
NativeConfig.setDisabledAddons(
currentGame.applicationId,
currentGame.programId,
currentList.mapNotNull {
if (it.enabled) {
null
@@ -200,6 +199,6 @@ class AddonViewModel : ViewModel() {
}
private fun gameKey(game: Game): String {
return "${game.applicationId}|${game.path}"
return "${game.programId}|${game.path}"
}
}
@@ -150,7 +150,7 @@ class DriverViewModel : ViewModel() {
?: return@withContext
val shaderDir = File(
externalFilesDir.absolutePath +
"/shader/" + game.shaderCacheName.lowercase()
"/shader/" + game.settingsName.lowercase()
)
if (shaderDir.exists()) {
shaderDir.deleteRecursively()
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -35,46 +35,23 @@ class Game(
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${path}_LastPlayed"
private val programIdLong: Long
get() = programId.toLongOrNull() ?: 0L
private val applicationIdLong: Long
get() = programIdLong and -8192L
val applicationId: String
get() = applicationIdLong.toString()
val settingsName: String
get() {
return if (applicationIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + applicationIdLong.toString(16).uppercase()
}
}
val programIdHex: String
get() {
val programIdLong = programId.toLong()
return if (programIdLong == 0L) {
"0"
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + programIdLong.toString(16).uppercase()
}
}
val shaderCacheName: String
get() = if (programIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + programIdLong.toString(16).uppercase()
}
val applicationIdHex: String
val programIdHex: String
get() {
return if (applicationIdLong == 0L) {
val programIdLong = programId.toLong()
return if (programIdLong == 0L) {
"0"
} else {
"0" + applicationIdLong.toString(16).uppercase()
"0" + programIdLong.toString(16).uppercase()
}
}
@@ -84,10 +61,10 @@ class Game(
}.zip"
val saveDir: String
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(applicationId)
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(programId)
val addonDir: String
get() = DirectoryInitialization.userDirectory + "/load/" + applicationIdHex + "/"
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
val launchIntent: Intent
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -65,7 +65,7 @@ object CustomSettingsHandler {
// Initialize per-game config
try {
val fileName = FileUtil.getFilename(Uri.parse(game.path))
NativeConfig.initializePerGameConfig(game.applicationId, fileName)
NativeConfig.initializePerGameConfig(game.programId, fileName)
Log.info("[CustomSettingsHandler] Successfully applied custom settings")
return game
} catch (e: Exception) {
@@ -333,20 +333,20 @@ object CustomSettingsHandler {
*/
fun findGameByTitleId(titleId: String, context: Context): Game? {
Log.info("[CustomSettingsHandler] Searching for game with title ID: $titleId")
// Convert the program ID to the application ID used by per-game settings.
val applicationIdLong = try {
titleId.toLong(16) and -8192L
// Convert hex title ID to decimal for comparison with programId
val programIdDecimal = try {
titleId.toLong(16).toString()
} catch (e: NumberFormatException) {
Log.error("[CustomSettingsHandler] Invalid title ID format: $titleId")
return null
}
val applicationIdDecimal = applicationIdLong.toString()
// Expected hex format with "0" prefix
val expectedHex = "0${applicationIdLong.toString(16).uppercase()}"
val expectedHex = "0${titleId.uppercase()}"
// First check cached games for fast lookup
GameHelper.cachedGameList.find { game ->
game.applicationId == applicationIdDecimal || game.applicationIdHex.equals(expectedHex, ignoreCase = true)
game.programId == programIdDecimal ||
game.programIdHex.equals(expectedHex, ignoreCase = true)
}?.let { foundGame ->
Log.info("[CustomSettingsHandler] Found game in cache: ${foundGame.title}")
return foundGame
@@ -355,7 +355,8 @@ object CustomSettingsHandler {
Log.info("[CustomSettingsHandler] Game not in cache, scanning full library...")
val allGames = GameHelper.getGames()
val foundGame = allGames.find { game ->
game.applicationId == applicationIdDecimal || game.applicationIdHex.equals(expectedHex, ignoreCase = true)
game.programId == programIdDecimal ||
game.programIdHex.equals(expectedHex, ignoreCase = true)
}
if (foundGame != null) {
Log.info("[CustomSettingsHandler] Found game: ${foundGame.title} at ${foundGame.path}")
@@ -31,7 +31,6 @@ object GameHelper {
fun getGames(): List<Game> {
val games = mutableListOf<Game>()
val gamesByProgramId = mutableMapOf<String, Game>()
val context = YuzuApplication.appContext
preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -64,7 +63,6 @@ object GameHelper {
addGamesRecursive(
games,
gamesByProgramId,
FileUtil.listFiles(gameDirUri),
scanDepth,
mountedContainerUris
@@ -138,7 +136,6 @@ object GameHelper {
private fun addGamesRecursive(
games: MutableList<Game>,
gamesByProgramId: MutableMap<String, Game>,
files: Array<MinimalDocumentFile>,
depth: Int,
mountedContainerUris: MutableSet<String>
@@ -151,7 +148,6 @@ object GameHelper {
if (it.isDirectory) {
addGamesRecursive(
games,
gamesByProgramId,
FileUtil.listFiles(it.uri),
depth - 1,
mountedContainerUris
@@ -160,9 +156,8 @@ object GameHelper {
val extension = FileUtil.getExtension(it.uri).lowercase()
val filePath = it.uri.toString()
val mountedContainer = externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)
if (mountedContainer) {
if (externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
}
@@ -170,20 +165,6 @@ object GameHelper {
val game = getGame(it.uri, true, false)
if (game != null) {
games.add(game)
if (game.applicationId != "0") {
gamesByProgramId[game.applicationId] = game
}
} else if (mountedContainer) {
GameMetadata.getProgramId(filePath).toLongOrNull()?.let { programId ->
gamesByProgramId[(programId and -8192L).toString()]
}?.let { existingGame ->
NativeLibrary.getPatchesForFile(existingGame.path, existingGame.programId)
existingGame.version = GameMetadata.getVersion(
existingGame.path,
true
)
GameIconUtils.refreshGameIcon(existingGame)
}
}
}
}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,15 +24,6 @@ import coil.request.Options
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game
import java.util.Collections
import java.util.WeakHashMap
private val gameIconHashes = Collections.synchronizedMap(mutableMapOf<String, Int>())
private val gameIconTargets = Collections.synchronizedMap(WeakHashMap<ImageView, GameIconTarget>())
private fun Game.iconCacheKey(): String = "$path|$version"
private data class GameIconTarget(val game: Game, var iconHash: Int? = null)
class GameIconFetcher(
private val game: Game,
@@ -43,15 +31,14 @@ class GameIconFetcher(
) : Fetcher {
override suspend fun fetch(): FetchResult {
return DrawableResult(
drawable = decodeGameIcon(game)!!.toDrawable(options.context.resources),
drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources),
isSampled = false,
dataSource = DataSource.DISK
)
}
private fun decodeGameIcon(game: Game): Bitmap? {
val data = GameMetadata.getIcon(game.path)
gameIconHashes[game.iconCacheKey()] = data.contentHashCode()
private fun decodeGameIcon(uri: String): Bitmap? {
val data = GameMetadata.getIcon(uri)
return BitmapFactory.decodeByteArray(
data,
0,
@@ -67,7 +54,7 @@ class GameIconFetcher(
}
class GameIconKeyer : Keyer<Game> {
override fun key(data: Game, options: Options): String = data.iconCacheKey()
override fun key(data: Game, options: Options): String = data.path
}
object GameIconUtils {
@@ -84,58 +71,14 @@ object GameIconUtils {
.build()
fun loadGameIcon(game: Game, imageView: ImageView) {
gameIconTargets[imageView] = GameIconTarget(game)
val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game)
.target(imageView)
.error(R.drawable.default_icon)
.listener(
onSuccess = { _, _ ->
val target = gameIconTargets[imageView]
if (target?.game?.iconCacheKey() == game.iconCacheKey()) {
gameIconHashes[game.iconCacheKey()]?.let {
target.iconHash = it
}
}
},
onError = { _, _ ->
gameIconTargets[imageView]?.iconHash = null
}
)
.build()
imageLoader.enqueue(request)
}
fun refreshGameIcon(game: Game) {
val targets = synchronized(gameIconTargets) {
gameIconTargets
.filterValues { it.game.path == game.path && it.game.programId == game.programId }
.keys
.toList()
}
if (targets.isEmpty()) {
return
}
val iconHash = GameMetadata.getIcon(game.path).contentHashCode()
val targetsToRefresh = targets.filter { gameIconTargets[it]?.iconHash != iconHash }
if (targetsToRefresh.isEmpty()) {
return
}
imageLoader.memoryCache?.remove(MemoryCache.Key(game.iconCacheKey()))
targetsToRefresh.forEach { imageView ->
imageView.post {
val target = gameIconTargets[imageView] ?: return@post
if (target.game.path == game.path && target.game.programId == game.programId) {
if (target.iconHash != iconHash) {
loadGameIcon(game, imageView)
}
}
}
}
}
suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game)
+11 -67
View File
@@ -76,7 +76,6 @@ extern "C" {
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "common/android/applets/web_browser.h"
#include "core/file_sys/common_funcs.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -312,23 +311,11 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
ConfigureFilesystemProvider(filepath);
// Load the ROM.
const u64 previous_program_id =
program_index != 0 && m_next_program_id.load() >
static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)
? m_next_program_id.load()
: 0;
Service::AM::FrontendAppletParameters params{
.program_id = previous_program_id,
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
: Service::AM::LaunchType::ApplicationInitiated,
.program_index = static_cast<s32>(program_index),
.previous_program_index =
previous_program_id != 0
? static_cast<s32>(previous_program_id -
FileSys::GetBaseTitleID(previous_program_id))
: -1,
};
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
@@ -341,12 +328,8 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
m_system.GetCpuManager().OnGpuReady();
m_system.RegisterExitCallback([&] { HaltEmulation(); });
m_system.RegisterApplicationChangedCallback(
[&](u64 changed_program_id) { RequestDiskShaderCacheReload(changed_program_id); });
// Register an ExecuteProgram callback such that Core can execute a sub-program
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
m_next_program_id = m_system.GetApplicationProcessProgramID();
m_next_program_index = program_index_;
EmulationSession::GetInstance().HaltEmulation();
});
@@ -424,58 +407,20 @@ void EmulationSession::RunEmulation() {
}
while (true) {
std::optional<u64> reload_title;
{
[[maybe_unused]] std::unique_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800), [&]() {
return !m_is_running || m_pending_shader_cache_title.has_value();
})) {
if (!m_is_running) {
break;
}
reload_title = std::exchange(m_pending_shader_cache_title, std::nullopt);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
[&]() { return !m_is_running; })) {
// Emulation halted.
break;
}
}
if (reload_title.has_value())
ReloadDiskShaderCache(*reload_title);
}
// Reset current applet ID.
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
}
void EmulationSession::RequestDiskShaderCacheReload(u64 program_id) {
{
std::scoped_lock lock(m_mutex);
m_pending_shader_cache_title = program_id;
}
m_cv.notify_one();
}
void EmulationSession::ReloadDiskShaderCache(u64 program_id) {
if (!Settings::values.use_disk_shader_cache.GetValue())
return;
LOG_INFO(Frontend, "Reloading disk shader cache for {:016X}", program_id);
const bool was_paused = m_is_paused;
m_system.Pause();
m_system.GPU().WaitForIdle();
m_system.GPU().ObtainContext();
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
m_system.Renderer().ReadRasterizer()->LoadDiskResources(program_id, std::stop_token{},
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
m_system.GPU().ReleaseContext();
if (!was_paused)
m_system.Run();
}
Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard;
}
@@ -788,7 +733,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId,
jstring jupdatePath) {
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
@@ -796,7 +741,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
if (update_id == program_id) {
return true;
}
@@ -1491,7 +1436,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclas
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_gameRequiresFirmware(JNIEnv* env, jclass clazz, jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
return FirmwareManager::GameRequiresFirmware(program_id);
}
@@ -1575,21 +1520,20 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(
EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
jstring jname) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, Common::Android::GetJString(env, jname));
}
@@ -1636,7 +1580,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) {
return Common::Android::ToJString(env, "");
}
-6
View File
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <optional>
#include <android/native_window_jni.h>
#include "common/android/applets/software_keyboard.h"
#include "core/core.h"
@@ -46,7 +44,6 @@ public:
void HaltEmulation();
void RunEmulation();
void ShutdownEmulation();
void RequestDiskShaderCacheReload(u64 program_id);
const Core::PerfStatsResults& PerfStats();
int ShadersBuilding();
@@ -68,7 +65,6 @@ 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);
void ReloadDiskShaderCache(u64 program_id);
private:
// Window management
@@ -87,7 +83,6 @@ private:
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1};
std::optional<u64> m_pending_shader_cache_title;
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
@@ -98,5 +93,4 @@ private:
// Program index for next boot
std::atomic<s32> m_next_program_index = -1;
std::atomic<u64> m_next_program_id = 0;
};
@@ -12,7 +12,6 @@
#include "common/fs/path_util.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/file_sys/common_funcs.h"
#include "frontend_common/config.h"
#include "frontend_common/settings_generator.h"
#include "native.h"
@@ -57,7 +56,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jo
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv* env, jobject obj,
jstring jprogramId,
jstring jfileName) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto file_name = Common::Android::GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config =
@@ -323,7 +322,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(),
@@ -338,7 +337,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId,
jobjectArray jdisabledAddons) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
Settings::values.disabled_addons[program_id].clear();
std::vector<std::string> disabled_addons;
const int size = env->GetArrayLength(jdisabledAddons);
@@ -1107,6 +1107,7 @@
<string name="theme_mode_light">فاتح</string>
<string name="theme_mode_dark">داكن</string>
<string name="multiplier_none">لا شيء</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">خلفيات سوداء</string>
@@ -991,6 +991,7 @@ Wirklich fortfahren?</string>
<string name="theme_mode_light">Hell</string>
<string name="theme_mode_dark">Dunkel</string>
<string name="multiplier_none">Keine</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Schwarze Hintergründe</string>
@@ -1092,6 +1092,7 @@
<string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Oscuro</string>
<string name="multiplier_none">Nada</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Fondos oscuros</string>
@@ -808,6 +808,9 @@
<string name="multiplier_x4">x4</string>
<string name="multiplier_x8">x8</string>
<string name="multiplier_x16">x16</string>
<string name="multiplier_x32">x32</string>
<string name="multiplier_x64">x64</string>
<string name="multiplier_none">None</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">پس‌زمینه مشکی</string>
@@ -1004,6 +1004,7 @@
<string name="theme_mode_light">Lumineux</string>
<string name="theme_mode_dark">Sombre</string>
<string name="multiplier_none">Aucun</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Arrière-plan noir</string>
@@ -935,6 +935,7 @@
<string name="theme_mode_light">Jasny</string>
<string name="theme_mode_dark">Ciemny</string>
<string name="multiplier_none">Brak</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Czarne tła</string>
@@ -891,6 +891,7 @@
<string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Escuro</string>
<string name="multiplier_none">Nenhum</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Planos de fundo pretos</string>
@@ -1071,6 +1071,7 @@
<string name="theme_mode_light">Светлая</string>
<string name="theme_mode_dark">Темная</string>
<string name="multiplier_none">Отключено</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чёрный фон</string>
@@ -1053,6 +1053,7 @@
<string name="theme_mode_light">Світла</string>
<string name="theme_mode_dark">Темна</string>
<string name="multiplier_none">Жодного</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чорний фон</string>
@@ -1081,6 +1081,7 @@
<string name="theme_mode_light">浅色</string>
<string name="theme_mode_dark">深色</string>
<string name="multiplier_none"></string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">使用黑色背景</string>
@@ -1006,6 +1006,7 @@
<string name="theme_mode_light">淺色</string>
<string name="theme_mode_dark">深色</string>
<string name="multiplier_none"></string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">黑色背景</string>
+23 -12
View File
@@ -111,38 +111,43 @@
<item>1</item>
</integer-array>
<!-- VRAM USAGE MODE CHOICES -->
<string-array name="vramUsageMethodNames">
<item>@string/vram_usage_conservative</item>
<item>@string/vram_usage_aggressive</item>
</string-array>
<!-- VRAM USAGE MODE VALUES -->
<integer-array name="vramUsageMethodValues">
<item>0</item>
<item>1</item>
<item>0</item> <!-- Conservative -->
<item>1</item> <!-- Aggressive -->
</integer-array>
<!-- ASTC Decoding Method Choices -->
<string-array name="astcDecodingMethodNames">
<item>@string/accelerate_astc_cpu</item>
<item>@string/accelerate_astc_gpu</item>
<item>@string/accelerate_astc_async</item>
</string-array>
<!-- ASTC Decoding Method Values -->
<integer-array name="astcDecodingMethodValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>0</item> <!-- CPU -->
<item>1</item> <!-- GPU -->
<item>2</item> <!-- CPU Asynchronously -->
</integer-array>
<!-- NVDEC Emulation Choices -->
<string-array name="rendererNvdecNames">
<item>@string/nvdec_emulation_none</item>
<item>@string/nvdec_emulation_cpu</item>
<item>@string/nvdec_emulation_gpu</item>
<item>@string/nvdec_emulation_none</item> <!-- Off -->
<item>@string/nvdec_emulation_cpu</item> <!-- Cpu -->
<item>@string/nvdec_emulation_gpu</item> <!-- Gpu -->
</string-array>
<!-- NVDEC Emulation Values -->
<integer-array name="rendererNvdecValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item> <!-- Off value -->
<item>1</item> <!-- CPU value -->
<item>2</item> <!-- GPU value -->
</integer-array>
<string-array name="rendererResolutionNames">
@@ -508,6 +513,9 @@
<item>@string/multiplier_x4</item>
<item>@string/multiplier_x8</item>
<item>@string/multiplier_x16</item>
<item>@string/multiplier_x32</item>
<item>@string/multiplier_x64</item>
<item>@string/multiplier_none</item>
</string-array>
<integer-array name="anisoValues">
<item>0</item>
@@ -516,6 +524,9 @@
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
</integer-array>
<string-array name="verticalAlignmentEntries">
@@ -1246,6 +1246,9 @@
<string name="multiplier_x4" translatable="false">x4</string>
<string name="multiplier_x8" translatable="false">x8</string>
<string name="multiplier_x16" translatable="false">x16</string>
<string name="multiplier_x32" translatable="false">x32</string>
<string name="multiplier_x64" translatable="false">x64</string>
<string name="multiplier_none">None</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Black backgrounds</string>
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,12 +7,13 @@
namespace AudioCore::ADSP::OpusDecoder {
namespace {
constexpr u32 OpusStreamCountMax = 255;
bool IsValidChannelCount(u32 channel_count) {
return channel_count == 1 || channel_count == 2;
}
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax &&
static_cast<s32>(stereo_stream_count) >= 0 &&
stereo_stream_count <= total_stream_count;
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
}
} // namespace
+1 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -108,7 +105,7 @@ Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 chan
shared_memory.host_send_data[4] = total_stream_count;
shared_memory.host_send_data[5] = stereo_stream_count;
ASSERT(channel_count <= shared_memory.channel_mapping.size());
ASSERT(channel_count <= MaxChannels);
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
opus_decoder.Send(ADSP::Direction::DSP,
+27 -28
View File
@@ -19,23 +19,6 @@
namespace AudioCore::Sink {
namespace {
[[nodiscard]] bool InitializeAudio() {
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
// See https://github.com/PCSX2/pcsx2/pull/12312
// "SDL and cubeb backends previously resulted in different names for the output which
// caused them be identified as different applications by the OS."
//
// Keep in sync with cubeb_sink.cpp name.
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return false;
}
}
return true;
}
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
int device_count = 0;
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -221,14 +204,20 @@ private:
};
SDLSink::SDLSink(std::string_view target_device_name) {
if (InitializeAudio()) {
if (target_device_name != auto_device_name && !target_device_name.empty()) {
output_device = target_device_name;
} else {
output_device.clear();
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return;
}
device_channels = 2;
}
if (target_device_name != auto_device_name && !target_device_name.empty()) {
output_device = target_device_name;
} else {
output_device.clear();
}
device_channels = 2;
}
SDLSink::~SDLSink() = default;
@@ -276,10 +265,15 @@ void SDLSink::SetSystemVolume(f32 volume) {
}
std::vector<std::string> ListSDLSinkDevices(bool capture) {
if (!InitializeAudio())
return {}; //no devices
std::vector<std::string> device_list;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return {};
}
}
int device_count = 0;
SDL_AudioDeviceID* devices =
capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -310,8 +304,13 @@ bool IsSDLSuitable() {
return false;
#else
// Check SDL can init
if (!InitializeAudio()!
return false;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
SDL_GetError());
return false;
}
}
// We can set any latency frequency we want with SDL, so no need to check that.
+45 -56
View File
@@ -39,19 +39,6 @@
namespace Common::Log {
/// @brief A log entry. Log entries are store in a structured format to permit more varied output
/// formatting on different frontends, as well as facilitating filtering and aggregation.
struct Entry {
char const* message = nullptr;
size_t message_len = 0;
std::chrono::microseconds timestamp;
Class log_class{};
Level log_level{};
const char* filename = nullptr;
const char* function = nullptr;
uint32_t line_num = 0;
};
namespace {
/// @brief Returns the name of the passed log class as a C-string. Subclasses are separated by periods
@@ -83,6 +70,8 @@ const char* GetLevelName(Level log_level) {
}
}
}
// Some IDEs prefer <file>:<line> instead, so let's just do that :)
std::string FormatLogMessage(const Entry& entry) noexcept {
if (!entry.filename) return "";
@@ -90,9 +79,10 @@ std::string FormatLogMessage(const Entry& entry) noexcept {
auto const time_fractional = uint32_t(entry.timestamp.count() % 1000000);
auto const class_name = GetLogClassName(entry.log_class);
auto const level_name = GetLevelName(entry.log_level);
return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}\n", time_seconds, time_fractional, class_name, level_name, entry.filename, entry.line_num, entry.function, entry.message);
return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional, class_name, level_name, entry.filename, entry.line_num, entry.function, entry.message);
}
namespace {
template <typename It>
Level GetLevelByName(const It begin, const It end) {
for (u32 i = 0; i < u32(Level::Count); ++i) {
@@ -137,6 +127,25 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
instance.SetClassLevel(log_class, level);
return true;
}
} // Anonymous namespace
void Filter::ParseFilterString(std::string_view filter_view) {
auto clause_begin = filter_view.cbegin();
while (clause_begin != filter_view.cend()) {
auto clause_end = std::find(clause_begin, filter_view.cend(), ' ');
// If clause isn't empty
if (clause_end != clause_begin) {
ParseFilterRule(*this, clause_begin, clause_end);
}
if (clause_end != filter_view.cend()) {
// Skip over the whitespace
++clause_end;
}
clause_begin = clause_end;
}
}
namespace {
/// @brief Trims up to and including the last of ../, ..\, src/, src\ in a string
/// do not be fooled this isn't generating new strings on .rodata :)
@@ -199,7 +208,7 @@ struct ColorConsoleBackend final : public Backend {
}());
SetConsoleTextAttribute(console_handle, color);
auto const df = GetDirectFormatArgs(entry);
std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
}
}
void Flush() noexcept override {}
@@ -211,24 +220,22 @@ struct ColorConsoleBackend final : public Backend {
~ColorConsoleBackend() noexcept override {}
void Write(const Entry& entry) noexcept override {
if (enabled) {
#define ESC "\x1b"
auto const color_str = [&entry]() -> const char* {
switch (entry.log_level) {
case Level::Debug: return "[0;36m"; // Cyan
case Level::Info: return "[0;37m"; // Bright gray
case Level::Warning: return "[1;33m"; // Bright yellow
case Level::Error: return "[1;31m"; // Bright red
case Level::Critical: return "[1;35m"; // Bright magenta
default: return "[1;30m"; // Grey
#define CCB_MAKE_COLOR_FMT(X) ESC X CCB_PRINTF_FMT ESC "[0m\n"
case Level::Debug: return CCB_MAKE_COLOR_FMT("[0;36m"); // Cyan
case Level::Info: return CCB_MAKE_COLOR_FMT("[0;37m"); // Bright gray
case Level::Warning: return CCB_MAKE_COLOR_FMT("[1;33m"); // Bright yellow
case Level::Error: return CCB_MAKE_COLOR_FMT("[1;31m"); // Bright red
case Level::Critical: return CCB_MAKE_COLOR_FMT("[1;35m"); // Bright magenta
default: return CCB_MAKE_COLOR_FMT("[1;30m"); // Grey
#undef CCB_MAKE_COLOR_FMT
}
}();
auto const df = GetDirectFormatArgs(entry);
// more restrictive, because take for example this simple prelude:
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
char buffer[256];
auto result = fmt::format_to_n(buffer, sizeof(buffer) - 1, "\x1b{}[{:4d}.{:06d}] {} <{}> {}:{}:{}: ", color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
std::fwrite(buffer, 1, (std::min)(sizeof(buffer) - 1, result.size), stdout);
std::fwrite(entry.message, 1, entry.message_len, stdout);
std::fwrite("\x1b[0m\n", 1, sizeof("\x1b[0m\n"), stdout);
std::fprintf(stdout, color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
#undef ESC
}
}
void Flush() noexcept override {}
@@ -239,7 +246,7 @@ struct ColorConsoleBackend final : public Backend {
#ifndef __OPENORBIS__
/// @brief Backend that writes to a file passed into the constructor
struct FileBackend final : public Backend {
explicit FileBackend(const std::filesystem::path filename) noexcept {
explicit FileBackend(const std::filesystem::path& filename) noexcept {
auto old_filename = filename;
old_filename += ".old.txt";
// Existence checks are done within the functions themselves.
@@ -254,7 +261,7 @@ struct FileBackend final : public Backend {
if (!enabled)
return;
auto message = FormatLogMessage(entry);
auto message = FormatLogMessage(entry).append(1, '\n');
#ifndef __ANDROID__
if (Settings::values.censor_username.GetValue()) {
// This must be a static otherwise it would get checked on EVERY
@@ -262,7 +269,8 @@ struct FileBackend final : public Backend {
static std::string username = []() -> std::string {
// in order of precedence
// LOGNAME usually works on UNIX, USERNAME on Windows
// Some UNIX systems suck and don't use LOGNAME so we also need USER :(
// Some UNIX systems suck and don't use LOGNAME so we also
// need USER :(
for (auto const var : { "LOGNAME", "USERNAME", "USER", })
if (auto const s = ::getenv(var); s != nullptr)
return std::string{s};
@@ -272,7 +280,7 @@ struct FileBackend final : public Backend {
boost::replace_all(message, username, "user");
}
#endif
bytes_written += file->WriteSpan(std::span<const char>{message.begin(), message.end()});
bytes_written += file->WriteString(message);
// Option to log each line rather than 4k buffers
if (Settings::values.log_flush_line.GetValue())
@@ -300,13 +308,14 @@ private:
bool enabled = true;
};
#endif
#ifdef _WIN32
/// @brief Backend that writes to Visual Studio's output window
struct DebuggerBackend final : public Backend {
explicit DebuggerBackend() noexcept = default;
~DebuggerBackend() noexcept override = default;
void Write(const Entry& entry) noexcept override {
::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry)).c_str());
::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
}
void Flush() noexcept override {}
};
@@ -329,7 +338,7 @@ struct LogcatBackend : public Backend {
}
}();
auto const df = GetDirectFormatArgs(entry);
__android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
__android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
}
void Flush() noexcept override {}
};
@@ -368,23 +377,7 @@ struct Impl {
#endif
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
} // Anonymous namespace
void Filter::ParseFilterString(std::string_view filter_view) {
auto clause_begin = filter_view.cbegin();
while (clause_begin < filter_view.cend()) {
auto clause_end = std::find(clause_begin, filter_view.cend(), ' ');
// If clause isn't empty
if (clause_end != clause_begin) {
ParseFilterRule(*this, clause_begin, clause_end);
}
if (clause_end != filter_view.cend()) {
// Skip over the whitespace
++clause_end;
}
clause_begin = clause_end;
}
}
} // namespace
// Constructor shall NOT depend upon Settings() or whatever
// it's ran at global static ctor() time... so BE CAREFUL MFER!
@@ -426,13 +419,9 @@ void SetColorConsoleBackendEnabled(bool enabled) {
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
auto const flush = ::Settings::values.log_flush_line.GetValue();
char buffer[BUFSIZ];
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
buffer[(std::min)(result.size, sizeof(buffer) - 1)] = '\0';
logging_instance->ForEachBackend([=](Backend& backend) {
backend.Write(Entry{
.message = buffer,
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
.message = fmt::vformat(format, args),
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
.log_class = log_class,
.log_level = log_level,
+21
View File
@@ -140,4 +140,25 @@ void Stop();
void SetGlobalFilter(const Filter& filter);
void SetColorConsoleBackendEnabled(bool enabled);
/// @brief A log entry. Log entries are store in a structured format to permit more varied output
/// formatting on different frontends, as well as facilitating filtering and aggregation.
struct Entry {
std::string message;
std::chrono::microseconds timestamp;
Class log_class{};
Level log_level{};
const char* filename = nullptr;
const char* function = nullptr;
unsigned int line_num = 0;
};
/// Formats a log entry into the provided text buffer.
std::string FormatLogMessage(const Entry& entry) noexcept;
/// Prints the same message as `PrintMessage`, but colored according to the severity level.
void PrintColoredMessage(const Entry& entry) noexcept;
/// Formats and prints a log entry to the android logcat.
void PrintMessageToLogcat(const Entry& entry) noexcept;
} // namespace Common::Log
+4 -2
View File
@@ -132,9 +132,11 @@ void LogSettings() {
}
}
}
LOG_INFO(Config, "Eden Configuration:");
std::string settings_str{};
for (auto const& e : settings_list)
LOG_INFO(Config, "{}", e);
settings_str += e;
LOG_INFO(Config, "Eden Configuration:\n{}", settings_str);
#define LOG_PATH(NAME) \
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
LOG_PATH(CacheDir);
+1 -1
View File
@@ -128,7 +128,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
+2
View File
@@ -7,4 +7,6 @@
#define STB_IMAGE_IMPLEMENTATION 1
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#define STBI_ONLY_JPEG 1
#include "common/stb.h"
-1
View File
@@ -7,7 +7,6 @@
#pragma once
#define STBI_ONLY_JPEG 1
#define STBI_WRITE_NO_STDIO 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
@@ -286,7 +286,6 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
break;
// Paranoia mode for debugging optimizations
case Settings::CpuAccuracy::Paranoid:
@@ -338,7 +338,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
config.unsafe_optimizations = true;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.fastmem_address_space_bits = 64;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
break;
// Paranoia mode for debugging optimizations
case Settings::CpuAccuracy::Paranoid:
+9 -79
View File
@@ -4,7 +4,6 @@
#include <array>
#include <atomic>
#include <memory>
#include <unordered_map>
#include <utility>
#include "game_settings.h"
@@ -17,7 +16,6 @@
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "launch_timestamp_cache.h"
#include "core/core_timing.h"
@@ -250,30 +248,12 @@ struct System::Impl {
}
}
void NotifyNVDECChannelOpen(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
++nvdec_active_channels[process_id];
}
void NotifyNVDECChannelClose(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
const auto it = nvdec_active_channels.find(process_id);
if (it == nvdec_active_channels.end()) {
return;
}
if (--it->second == 0) {
nvdec_active_channels.erase(it);
}
void SetNVDECActive(bool is_nvdec_active) {
nvdec_active = is_nvdec_active;
}
bool GetNVDECActive() {
std::scoped_lock lock{nvdec_active_mutex};
return !nvdec_active_channels.empty();
}
bool IsNVDECActiveForProcess(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
return nvdec_active_channels.contains(process_id);
return nvdec_active;
}
void InitializeDebugger(System& system, u16 port) {
@@ -315,10 +295,6 @@ struct System::Impl {
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) {
InitializeKernel(system);
if (params.applet_type == Service::AM::AppletType::Application) {
current_application_filepath = filepath;
}
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
// Create the application process
@@ -354,7 +330,7 @@ struct System::Impl {
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
// Make the process created be the application
kernel.SetApplicationProcess(process->GetHandle());
kernel.MakeApplicationProcess(process->GetHandle());
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
@@ -397,7 +373,7 @@ struct System::Impl {
LOG_ERROR(Core, "Failed to find program id for ROM");
}
GameSettings::LoadOverrides(FileSys::GetBaseTitleID(program_id), gpu_core->Renderer());
GameSettings::LoadOverrides(program_id, gpu_core->Renderer());
if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info;
game_info.name = name;
@@ -491,7 +467,6 @@ struct System::Impl {
Core::SpeedLimiter speed_limiter;
ExecuteProgramCallback execute_program_callback;
ExitCallback exit_callback;
ApplicationChangedCallback application_changed_callback;
std::optional<Service::Services> services;
std::optional<Core::Debugger> debugger;
@@ -513,8 +488,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<u8, 0x20> build_id{};
std::string current_application_filepath;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
/// ContentProviderUnion instance
@@ -525,8 +498,6 @@ struct System::Impl {
mutable std::mutex suspend_guard;
std::mutex general_channel_mutex;
std::mutex nvdec_active_mutex;
std::unordered_map<u64, u32> nvdec_active_channels;
std::atomic_bool is_paused{};
std::atomic_bool is_shutting_down{};
std::atomic_bool is_powered_on{};
@@ -534,6 +505,7 @@ struct System::Impl {
bool extended_memory_layout : 1 = false;
bool exit_locked : 1 = false;
bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;
void EnsureGeneralChannelInitialized(System& system) {
if (!general_channel_event) {
@@ -597,22 +569,14 @@ void System::UnstallApplication() {
impl->UnstallApplication();
}
void System::NotifyNVDECChannelOpen(u64 process_id) {
impl->NotifyNVDECChannelOpen(process_id);
}
void System::NotifyNVDECChannelClose(u64 process_id) {
impl->NotifyNVDECChannelClose(process_id);
void System::SetNVDECActive(bool is_nvdec_active) {
impl->SetNVDECActive(is_nvdec_active);
}
bool System::GetNVDECActive() {
return impl->GetNVDECActive();
}
bool System::IsNVDECActiveForProcess(u64 process_id) {
return impl->IsNVDECActiveForProcess(process_id);
}
void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
}
@@ -763,25 +727,7 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
}
u64 System::GetApplicationProcessProgramID() const {
const auto* const process = impl->kernel.ApplicationProcess();
return process != nullptr ? process->GetProgramId() : 0;
}
u64 System::GetProgramIdForProcessId(u64 process_id) const {
auto process = impl->kernel.GetProcessByProcessId(process_id);
return process.IsNull() ? 0 : process->GetProgramId();
}
u64 System::ResolveCallerProgramId(u64 process_id) const {
if (const auto program_id = this->GetProgramIdForProcessId(process_id); program_id != 0) {
return program_id;
}
const auto fallback = this->GetApplicationProcessProgramID();
LOG_WARNING(Core,
"Could not resolve caller process_id={}, falling back to application {:016X}",
process_id, fallback);
return fallback;
return impl->kernel.ApplicationProcess()->GetProgramId();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -964,10 +910,6 @@ void System::ExecuteProgram(std::size_t program_index) {
}
}
const std::string& System::GetCurrentApplicationFilePath() const {
return impl->current_application_filepath;
}
/// @brief Gets a reference to the user channel stack.
/// It is used to transfer data between programs.
std::vector<std::vector<u8>>& System::GetUserChannel() {
@@ -1019,18 +961,6 @@ void System::Exit() {
}
}
void System::RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback) {
impl->application_changed_callback = std::move(callback);
}
void System::NotifyApplicationChanged(u64 program_id) {
//LOG_DEBUG(Core, "Running application changed to {:016X}", program_id);
if (impl->application_changed_callback) {
impl->application_changed_callback(program_id);
}
}
void System::ApplySettings() {
impl->RefreshTime(*this);
+1 -12
View File
@@ -191,10 +191,8 @@ public:
std::unique_lock<std::mutex> StallApplication();
void UnstallApplication();
void NotifyNVDECChannelOpen(u64 process_id);
void NotifyNVDECChannelClose(u64 process_id);
void SetNVDECActive(bool is_nvdec_active);
[[nodiscard]] bool GetNVDECActive();
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
/**
* Initialize the debugger.
@@ -324,10 +322,6 @@ public:
[[nodiscard]] u64 GetApplicationProcessProgramID() const;
[[nodiscard]] u64 GetProgramIdForProcessId(u64 process_id) const;
[[nodiscard]] u64 ResolveCallerProgramId(u64 process_id) const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
@@ -428,7 +422,6 @@ public:
void PushGeneralChannelData(std::vector<u8>&& data);
bool TryPopGeneralChannel(std::vector<u8>& out_data);
[[nodiscard]] Service::Event& GetGeneralChannelEvent();
[[nodiscard]] const std::string& GetCurrentApplicationFilePath() const;
/// Type used for the frontend to designate a callback for System to exit the application.
using ExitCallback = std::function<void()>;
@@ -442,10 +435,6 @@ public:
/// Instructs the frontend to exit the application.
void Exit();
using ApplicationChangedCallback = std::function<void(u64 program_id)>;
void RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback);
void NotifyApplicationChanged(u64 program_id);
/// Applies any changes to settings to this core instance.
void ApplySettings();
+2 -2
View File
@@ -29,7 +29,7 @@ static u8 MasterKeyIdForKeyGeneration(u8 key_generation) {
return std::max<u8>(key_generation, 1) - 1;
}
NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
NCA::NCA(VirtualFile file_, const NCA* base_nca)
: file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile;
@@ -110,7 +110,7 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
}
}
if (is_update && base_nca == nullptr && !allow_missing_base) {
if (is_update && base_nca == nullptr) {
status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
} else {
status = Loader::ResultStatus::Success;
+1 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -66,7 +63,7 @@ inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) {
// After construction, use GetStatus to determine if the file is valid and ready to be used.
class NCA : public ReadOnlyVfsDirectory {
public:
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr, bool allow_missing_base = false);
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr);
~NCA() override;
Loader::ResultStatus GetStatus() const;
@@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_indirect_storage.h"
@@ -100,18 +99,6 @@ Result IndirectStorage::GetEntryList(Entry* out_entries, s32* out_entry_count, s
R_SUCCEED();
}
void IndirectStorage::ReportMissingOriginal(s64 offset, s64 size) {
if (m_reported_missing_original) {
return;
}
m_reported_missing_original = true;
LOG_ERROR(Common_Filesystem,
"Patch storage requests {:#x} bytes at {:#x} from a base storage that is not "
"present; this data will read as garbage",
size, offset);
}
size_t IndirectStorage::Read(u8* buffer, size_t size, size_t offset) const {
// Validate pre-conditions.
ASSERT(this->IsInitialized());
@@ -85,9 +85,6 @@ public:
void SetStorage(s32 idx, VirtualFile storage) {
ASSERT(0 <= idx && idx < StorageCount);
m_data_storage[idx] = storage;
if (idx == 0) {
m_original_missing = storage == nullptr || storage->GetSize() == 0;
}
}
template <typename T>
@@ -133,9 +130,6 @@ protected:
template <bool ContinuousCheck, bool RangeCheck, typename F>
Result OperatePerEntry(s64 offset, s64 size, F func);
// Launching another game makes the original storage inaccessable.
// This is a helper for multi-nca games.
void ReportMissingOriginal(s64 offset, s64 size);
private:
struct ContinuousReadingEntry {
@@ -160,8 +154,6 @@ private:
private:
mutable BucketTree m_table;
std::array<VirtualFile, StorageCount> m_data_storage;
bool m_original_missing{false};
bool m_reported_missing_original{false};
};
template <bool ContinuousCheck, bool RangeCheck, typename F>
@@ -280,10 +272,6 @@ Result IndirectStorage::OperatePerEntry(s64 offset, s64 size, F func) {
if (needs_operate) {
const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset();
if (cur_entry.storage_index == 0 && m_original_missing) {
this->ReportMissingOriginal(cur_offset, cur_size);
}
if constexpr (RangeCheck) {
// Get the current data storage's size.
s64 cur_data_storage_size = m_data_storage[cur_entry.storage_index]->GetSize();
+2 -2
View File
@@ -48,11 +48,11 @@ struct ContentRecord {
std::array<u8, 0x10> nca_id;
std::array<u8, 0x6> size;
ContentRecordType type;
u8 id_offset;
INSERT_PADDING_BYTES(1);
};
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, 0};
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, {}};
struct MetaRecord {
u64_le title_id;
+61 -131
View File
@@ -161,7 +161,7 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
PatchManager::PatchManager(u64 title_id_,
const Service::FileSystem::FileSystemController& fs_controller_,
const ContentProvider& content_provider_)
: title_id{title_id_}, application_id{GetBaseTitleID(title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
PatchManager::~PatchManager() = default;
@@ -169,41 +169,13 @@ u64 PatchManager::GetTitleID() const {
return title_id;
}
u64 PatchManager::GetUpdateTitleIDForContent() const {
const auto program_update_id = GetUpdateTitleID(title_id);
if (program_update_id == GetUpdateTitleID(application_id) || content_provider.HasEntry(program_update_id, ContentRecordType::Program)) {
return program_update_id;
}
return GetUpdateTitleID(application_id);
}
std::vector<VirtualDir> PatchManager::GetModificationLoadRoots() const {
std::vector<VirtualDir> roots;
roots.push_back(fs_controller.GetModificationLoadRoot(title_id));
if (application_id != title_id) {
roots.push_back(fs_controller.GetModificationLoadRoot(application_id));
}
std::erase(roots, nullptr);
return roots;
}
std::vector<VirtualDir> PatchManager::GetSDMCModificationLoadRoots() const {
std::vector<VirtualDir> roots;
roots.push_back(fs_controller.GetSDMCModificationLoadRoot(title_id));
if (application_id != title_id) {
roots.push_back(fs_controller.GetSDMCModificationLoadRoot(application_id));
}
std::erase(roots, nullptr);
return roots;
}
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
if (exefs == nullptr)
return exefs;
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -211,7 +183,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
bool checked_manual = false;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
if (content_union) {
// First, check ExternalContentProvider
@@ -331,21 +303,17 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
// LayeredExeFS
const auto load_dirs = GetModificationLoadRoots();
const auto sdmc_load_dirs = GetSDMCModificationLoadRoots();
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
std::vector<VirtualDir> patch_dirs;
for (const auto& sdmc_load_dir : sdmc_load_dirs) {
patch_dirs.push_back(sdmc_load_dir);
}
for (const auto& load_dir : load_dirs) {
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
if (load_dir != nullptr) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1);
@@ -379,7 +347,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const {
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto nso_build_id = fmt::format("{:0<64}", build_id);
std::vector<VirtualFile> out;
@@ -444,20 +412,15 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso;
}
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
const auto patches = CollectPatches(patch_dirs, build_id);
auto out = nso;
@@ -492,39 +455,29 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false;
}
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
return !CollectPatches(patch_dirs, build_id).empty();
}
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {};
}
const auto& disabled = Settings::values.disabled_addons[application_id];
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(),
[](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
const auto& disabled = Settings::values.disabled_addons[title_id];
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
// <mod dir> / <folder> / cheats / <build id>.txt
std::vector<Core::Memory::CheatEntry> out;
@@ -540,52 +493,39 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
}
// Uncareless user-friendly loading of patches (must start with 'cheat_')
// <mod dir> / <cheat file>.txt
for (const auto& load_dir : load_dirs) {
for (auto const& f : load_dir->GetFiles()) {
auto const name = f->GetName();
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
std::vector<u8> data(f->GetSize());
if (f->Read(data.data(), data.size()) == data.size()) {
const Core::Memory::TextCheatParser parser;
auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
std::copy(res.begin(), res.end(), std::back_inserter(out));
} else {
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
}
for (auto const& f : load_dir->GetFiles()) {
auto const name = f->GetName();
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
std::vector<u8> data(f->GetSize());
if (f->Read(data.data(), data.size()) == data.size()) {
const Core::Memory::TextCheatParser parser;
auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
std::copy(res.begin(), res.end(), std::back_inserter(out));
} else {
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
}
}
}
return out;
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, u64 application_id, ContentRecordType type,
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
const Service::FileSystem::FileSystemController& fs_controller) {
std::vector<VirtualDir> load_dirs{fs_controller.GetModificationLoadRoot(title_id)};
std::vector<VirtualDir> sdmc_load_dirs{fs_controller.GetSDMCModificationLoadRoot(title_id)};
if (application_id != title_id) {
load_dirs.push_back(fs_controller.GetModificationLoadRoot(application_id));
sdmc_load_dirs.push_back(fs_controller.GetSDMCModificationLoadRoot(application_id));
}
std::erase(load_dirs, nullptr);
std::erase(sdmc_load_dirs, nullptr);
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
type != ContentRecordType::HtmlDocument) ||
(load_dirs.empty() && sdmc_load_dirs.empty())) {
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
return;
}
const auto& disabled = Settings::values.disabled_addons[application_id];
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
const auto& disabled = Settings::values.disabled_addons[title_id];
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
patch_dirs.insert(patch_dirs.end(), sdmc_load_dirs.begin(), sdmc_load_dirs.end());
patch_dirs.push_back(sdmc_load_dir);
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
std::vector<VirtualDir> layers_ext;
@@ -657,8 +597,8 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
auto romfs = base_romfs;
// Game Updates
const auto update_tid = GetUpdateTitleIDForContent();
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto update_tid = GetUpdateTitleID(title_id);
const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -765,7 +705,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
// LayeredFS
if (apply_layeredfs) {
ApplyLayeredFS(romfs, title_id, application_id, type, fs_controller);
ApplyLayeredFS(romfs, title_id, type, fs_controller);
}
return romfs;
@@ -777,10 +717,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
std::vector<Patch> out;
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
std::vector<Patch> external_update_patches;
@@ -929,7 +869,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
.version = "",
.type = PatchType::Update,
.program_id = title_id,
.title_id = update_tid,
.title_id = title_id,
.source = PatchSource::Unknown,
.numeric_version = 0};
@@ -955,7 +895,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
// General Mods (LayeredFS and IPS)
for (const auto& mod_dir : GetModificationLoadRoots()) {
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
if (mod_dir != nullptr) {
for (auto const& f : mod_dir->GetFiles())
if (auto const name = f->GetName(); name.starts_with("cheat_")) {
auto const mod_disabled = std::find(disabled.begin(), disabled.end(), name) != disabled.end();
@@ -1022,7 +963,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
// SDMC mod directory (RomFS LayeredFS)
for (const auto& sdmc_mod_dir : GetSDMCModificationLoadRoots()) {
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if (sdmc_mod_dir != nullptr) {
std::string types;
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs")))
AppendCommaIfNotEmpty(types, "LayeredExeFS");
@@ -1057,10 +999,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
dlc_match.reserve(dlc_entries_with_origin.size());
for (const auto& [slot, entry] : dlc_entries_with_origin) {
const auto base_tid = GetBaseTitleID(entry.title_id);
const bool matches_base = base_tid == application_id;
const bool matches_base = base_tid == title_id;
if (!matches_base) {
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
entry.title_id, base_tid, application_id);
entry.title_id, base_tid, title_id);
continue;
}
@@ -1135,22 +1077,16 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
std::optional<u32> PatchManager::GetGameVersion() const {
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
return content_provider.GetEntryVersion(update_tid);
}
if (const auto version = content_provider.GetEntryVersion(title_id); version.has_value()) {
return version;
}
return content_provider.GetEntryVersion(application_id);
return content_provider.GetEntryVersion(title_id);
}
PatchManager::Metadata PatchManager::GetControlMetadata() const {
auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr && application_id != title_id) {
base_control_nca = content_provider.GetEntry(application_id, ContentRecordType::Control);
}
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr) {
return {};
}
@@ -1226,14 +1162,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr)
return metadata;
const auto update_id = FileSys::GetUpdateTitleID(application_id);
const auto application_update_id = FileSys::GetUpdateTitleID(GetBaseTitleID(application_id));
const FileSys::PatchManager pm_update{update_id, system.GetFileSystemController(), system.GetContentProvider()};
metadata = pm_update.GetControlMetadata();
if (metadata.first != nullptr || update_id == application_update_id)
return metadata;
const FileSys::PatchManager pm_application_update{application_update_id, system.GetFileSystemController(), system.GetContentProvider()};
return pm_application_update.GetControlMetadata();
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(application_id), system.GetFileSystemController(), system.GetContentProvider()};
return pm_update.GetControlMetadata();
}
} // namespace FileSys
-5
View File
@@ -10,7 +10,6 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs/vfs_types.h"
@@ -110,14 +109,10 @@ public:
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
private:
[[nodiscard]] u64 GetUpdateTitleIDForContent() const;
[[nodiscard]] std::vector<VirtualDir> GetModificationLoadRoots() const;
[[nodiscard]] std::vector<VirtualDir> GetSDMCModificationLoadRoots() const;
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const;
u64 title_id;
u64 application_id;
const Service::FileSystem::FileSystemController& fs_controller;
const ContentProvider& content_provider;
};
+5 -30
View File
@@ -567,45 +567,20 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
}
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
auto cmnt_iter = map.find(title_id);
u8 id_offset = 0;
const auto cmnt_iter = map.find(title_id);
if (cmnt_iter == map.cend()) {
const auto program_index = title_id & AOC_TITLE_ID_MASK;
if (program_index == 0) {
return std::nullopt;
}
cmnt_iter = map.find(title_id & ~AOC_TITLE_ID_MASK);
if (cmnt_iter == map.cend()) {
return std::nullopt;
}
id_offset = static_cast<u8>(program_index);
return std::nullopt;
}
const auto& cnmt = cmnt_iter->second;
const auto& content_records = cnmt.GetContentRecords();
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
[type, id_offset](const ContentRecord& rec) {
return rec.type == type && rec.id_offset == id_offset;
});
if (iter != content_records.cend()) {
return std::make_optional(iter->nca_id);
}
if (id_offset != 0) {
[type](const ContentRecord& rec) { return rec.type == type; });
if (iter == content_records.cend()) {
return std::nullopt;
}
const auto fallback_iter =
std::find_if(content_records.cbegin(), content_records.cend(),
[type](const ContentRecord& rec) { return rec.type == type; });
if (fallback_iter == content_records.cend()) {
return std::nullopt;
}
return std::make_optional(fallback_iter->nca_id);
return std::make_optional(iter->nca_id);
}
std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
+6 -8
View File
@@ -12,7 +12,6 @@
#include "common/hex_util.h"
#include "common/logging.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
@@ -66,12 +65,10 @@ u64 NSP::GetProgramTitleID() const {
}
auto program_id = expected_program_id;
if (program_id == 0 && !program_status.empty()) {
program_id = std::min_element(program_status.cbegin(), program_status.cend(),
[](const auto& lhs, const auto& rhs) {
return lhs.first < rhs.first;
})
->first;
if (program_id == 0) {
if (!program_status.empty()) {
program_id = program_status.begin()->first;
}
}
program_id = program_id + program_index;
@@ -276,7 +273,8 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
// update NCA.
if ((next_nca->GetTitleId() & AOC_TITLE_ID_MASK) != 0) {
if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
(next_nca->GetTitleId() & 0x800) == 0) {
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
std::move(next_nca);
} else {
+4 -21
View File
@@ -349,18 +349,9 @@ struct KernelCore::Impl {
object_name_global_data.emplace(kernel);
}
void SetApplicationProcess(KernelCore& kernel, KProcess* process) {
if (application_process == process)
return;
KProcess* const previous = application_process;
void MakeApplicationProcess(KernelCore& kernel, KProcess* process) {
application_process = process;
if (application_process != nullptr)
application_process->Open(kernel);
if (previous != nullptr)
previous->Close(kernel);
application_process->Open(kernel);
}
/// Sets the host thread ID for the caller.
@@ -888,8 +879,8 @@ void KernelCore::RemoveProcess(KProcess* process) {
}
}
void KernelCore::SetApplicationProcess(KProcess* process) {
impl->SetApplicationProcess(*this, process);
void KernelCore::MakeApplicationProcess(KProcess* process) {
impl->MakeApplicationProcess(*this, process);
}
KProcess* KernelCore::ApplicationProcess() {
@@ -900,14 +891,6 @@ const KProcess* KernelCore::ApplicationProcess() const {
return impl->application_process;
}
KScopedAutoObject<KProcess> KernelCore::GetProcessByProcessId(u64 process_id) {
std::scoped_lock lk{impl->process_list_lock};
for (auto* const process : impl->process_list)
if (process != nullptr && process->GetProcessId() == process_id)
return {*this, process};
return {*this, nullptr};
}
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() {
std::list<KScopedAutoObject<KProcess>> processes;
std::scoped_lock lk{impl->process_list_lock};
+2 -5
View File
@@ -124,8 +124,8 @@ public:
void AppendNewProcess(KProcess* process);
void RemoveProcess(KProcess* process);
/// Makes the given process the current application process.
void SetApplicationProcess(KProcess* process);
/// Makes the given process the new application process.
void MakeApplicationProcess(KProcess* process);
/// Retrieves a pointer to the application process.
KProcess* ApplicationProcess();
@@ -133,9 +133,6 @@ public:
/// Retrieves a const pointer to the application process.
const KProcess* ApplicationProcess() const;
/// Retrieves the process with the given process ID, or a null object.
KScopedAutoObject<KProcess> GetProcessByProcessId(u64 process_id);
/// Retrieves the list of processes.
std::list<KScopedAutoObject<KProcess>> GetProcessList();
-4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,7 +10,6 @@ namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
constexpr Result ResultApplicationRecordNotFound{ErrorModule::AM, 37};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
+1 -9
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -201,14 +201,6 @@ enum class ProgramSpecifyKind : u32 {
RestartProgram = 2,
};
// Maufeat: Use enums for zindex instead of using random zindex numbers
enum AppletZIndex : s32 {
Background = 0,
Foreground = 1,
ForegroundVisible = 2,
Overlay = 3,
};
struct CommonArguments {
CommonArgumentVersion arguments_version;
CommonArgumentSize size;
+9 -9
View File
@@ -56,22 +56,22 @@ void Applet::UpdateSuspensionStateLocked(bool force_message) {
}
}
void Applet::SetInteractibleLocked(bool pad_interactible, bool touch_interactible) {
if (is_pad_interactible == pad_interactible && is_touch_interactible == touch_interactible) {
void Applet::SetInteractibleLocked(bool interactible) {
if (is_interactible == interactible) {
return;
}
is_pad_interactible = pad_interactible;
is_touch_interactible = touch_interactible;
is_interactible = interactible;
const bool exit_requested = lifecycle_manager.GetExitRequested();
const bool pad_enabled = pad_interactible && !exit_requested;
const bool touch_enabled = touch_interactible && !exit_requested;
const bool input_enabled = interactible && !exit_requested;
LOG_DEBUG(Service_AM, "applet={} pad={} touch={} exit_requested={}",
static_cast<u32>(applet_id), pad_enabled, touch_enabled, exit_requested);
if (applet_id == AppletId::OverlayDisplay || applet_id == AppletId::Application) {
LOG_DEBUG(Service_AM, "called, applet={} interactible={} exit_requested={} input_enabled={} overlay_in_foreground={}",
static_cast<u32>(applet_id), interactible, exit_requested, input_enabled, overlay_in_foreground);
}
hid_registration.EnableAppletToGetInput(pad_enabled, touch_enabled);
hid_registration.EnableAppletToGetInput(input_enabled);
}
void Applet::OnProcessTerminatedLocked() {
+3 -5
View File
@@ -125,11 +125,9 @@ struct Applet {
bool album_image_taken_notification_enabled{};
bool record_volume_muted{};
bool is_activity_runnable{};
bool is_pad_interactible{true};
bool is_touch_interactible{true};
bool is_interactible{true};
bool window_visible{true};
bool overlay_watching_short_home_button{false};
bool overlay_handling_touch_input{false};
bool overlay_in_foreground{false};
// Events
Event overlay_event;
@@ -150,7 +148,7 @@ struct Applet {
// Process state management
void UpdateSuspensionStateLocked(bool force_message);
void SetInteractibleLocked(bool pad_interactible, bool touch_interactible);
void SetInteractibleLocked(bool interactible);
void OnProcessTerminatedLocked();
};
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -6,7 +6,6 @@
#include "core/core.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/container.h"
@@ -34,7 +33,6 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
m_system_shared_buffer_id = 0;
m_system_shared_layer_id = 0;
m_applet_id = applet_id;
m_library_applet_mode = mode;
m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
@@ -74,16 +72,14 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerStackMask(*out_layer_id,
this->GetLayerStackMask());
if (m_applet_id != AppletId::Application) {
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
if (m_applet_id == AppletId::OverlayDisplay) {
(void)m_manager_display_service->SetLayerZIndex(Overlay, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
} else {
(void)m_manager_display_service->SetLayerZIndex(Foreground, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
}
}
@@ -126,12 +122,10 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
// Ensure the overlay layer is visible
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
(void)m_display_service->GetContainer()->SetLayerStackMask(m_system_shared_layer_id,
this->GetLayerStackMask());
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
s32 initial_z = Foreground;
s32 initial_z = 1;
if (m_applet_id == AppletId::OverlayDisplay) {
initial_z = Overlay;
initial_z = -1;
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
}
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
@@ -148,36 +142,6 @@ Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_bu
R_SUCCEED();
}
u32 DisplayLayerManager::GetLayerStackMask() const {
using Nvnflinger::LayerStackBit;
using Nvnflinger::LayerStackId;
constexpr u32 Displayed = LayerStackBit(LayerStackId::Default);
constexpr u32 Screenshot = LayerStackBit(LayerStackId::Screenshot);
constexpr u32 Recording = LayerStackBit(LayerStackId::Recording);
constexpr u32 LastFrame = LayerStackBit(LayerStackId::LastFrame);
constexpr u32 Debug = LayerStackBit(LayerStackId::ApplicationForDebug);
switch (m_applet_id) {
case AppletId::Application:
return Displayed | Screenshot | Recording | LastFrame | Debug;
case AppletId::OverlayDisplay:
return Displayed;
case AppletId::QLaunch:
return Displayed;
default:
break;
}
switch (m_library_applet_mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::AllForegroundInitiallyHidden:
return Displayed | Screenshot | LastFrame;
default:
return Displayed | Screenshot;
}
}
void DisplayLayerManager::SetWindowVisibility(bool visible) {
if (m_visible == visible) {
return;
@@ -221,17 +185,10 @@ void DisplayLayerManager::SetOverlayZIndex(s32 z_index) {
}
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index,
VI::CaptureKind kind) {
s32* out_fbshare_layer_index) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, kind));
}
Result DisplayLayerManager::ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->ClearAppletCaptureBuffer(
fbshare_layer_index, color));
out_was_written, out_fbshare_layer_index));
}
} // namespace Service::AM
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -23,7 +23,6 @@ class KProcess;
namespace Service::VI {
class IApplicationDisplayService;
class IManagerDisplayService;
enum class CaptureKind : u32;
} // namespace Service::VI
namespace Service::AM {
@@ -49,13 +48,9 @@ public:
void SetOverlayZIndex(s32 z_index);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index,
VI::CaptureKind kind);
Result ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
private:
u32 GetLayerStackMask() const;
Kernel::KProcess* m_process{};
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
@@ -64,7 +59,6 @@ private:
u64 m_system_shared_buffer_id{};
u64 m_system_shared_layer_id{};
AppletId m_applet_id{};
LibraryAppletMode m_library_applet_mode{};
bool m_buffer_sharing_enabled{};
bool m_blending_enabled{};
bool m_visible{true};
+6 -11
View File
@@ -36,17 +36,12 @@ HidRegistration::~HidRegistration() {
}
}
void HidRegistration::EnableAppletToGetInput(bool enable_pad, bool enable_touch) {
if (!m_process.IsInitialized())
return;
const auto resource_manager = m_hid_server->GetResourceManager();
const u64 aruid = m_process.GetProcessId();
resource_manager->EnablePadInput(aruid, enable_pad);
resource_manager->EnableTouchScreen(aruid, enable_touch);
resource_manager->SetAruidValidForVibration(aruid, enable_pad);
void HidRegistration::EnableAppletToGetInput(bool enable) {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
enable);
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
}
}
} // namespace Service::AM
+1 -1
View File
@@ -28,7 +28,7 @@ public:
~HidRegistration();
void RegisterCurrentProcess();
void EnableAppletToGetInput(bool enable_pad, bool enable_touch);
void EnableAppletToGetInput(bool enable);
private:
Process& m_process;
+2 -11
View File
@@ -6,7 +6,6 @@
#include <optional>
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -105,16 +104,8 @@ std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
auto base_slot = storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program);
if (!base_slot) {
base_slot = storage.GetSlotForEntry(FileSys::GetBaseTitleID(launch.title_id), FileSys::ContentRecordType::Program);
}
launch.base_game_storage_id = GetStorageIdForFrontendSlot(base_slot);
auto update_slot = storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program);
if (!update_slot) {
update_slot = storage.GetSlotForEntry(FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(launch.title_id)), FileSys::ContentRecordType::Program);
}
launch.update_storage_id = GetStorageIdForFrontendSlot(update_slot);
launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/cmif_serialization.h"
@@ -80,7 +78,7 @@ Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_application_id = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
*out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
R_SUCCEED();
}
@@ -6,10 +6,8 @@
#include <openssl/evp.h>
#include "common/hex_util.h"
#include "common/settings.h"
#include "common/uuid.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
@@ -30,27 +28,6 @@
namespace Service::AM {
namespace {
FileSys::PatchManager::Metadata GetApplicationMetadata(Core::System& system, u64 program_id) {
auto metadata = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, program_id);
if (metadata.first != nullptr) {
return metadata;
}
const auto application_id = FileSys::GetBaseTitleID(program_id);
if (application_id == program_id) {
return metadata;
}
LOG_DEBUG(Service_AM,
"no metadata for program_id={:016X}, falling back to application_id={:016X}",
program_id, application_id);
return FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, application_id);
}
} // Anonymous namespace
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
// clang-format off
@@ -158,7 +135,7 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
attribute.program_id = FileSys::GetBaseTitleID(m_applet->program_id);
attribute.program_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::Account;
@@ -179,7 +156,7 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = GetApplicationMetadata(system, m_applet->program_id);
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
@@ -217,7 +194,7 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
LOG_DEBUG(Service_AM, "called");
const auto res = GetApplicationMetadata(system, m_applet->program_id);
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
if (res.first != nullptr) {
const auto& version = res.first->GetVersionString();
std::memcpy(out_display_version->string.data(), version.data(),
@@ -238,7 +215,7 @@ Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys
static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
type, FileSys::GetBaseTitleID(m_applet->program_id), user_id.AsU128(), {normal_size, journal_size});
type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size});
// The following value is used to indicate the amount of space remaining on failure
// due to running out of space. Since we always succeed, this should be 0.
@@ -252,7 +229,7 @@ Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64>
LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
type, FileSys::GetBaseTitleID(m_applet->program_id), user_id.AsU128());
type, m_applet->program_id, user_id.AsU128());
*out_normal_size = size.normal;
*out_journal_size = size.journal;
@@ -347,7 +324,6 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(stubbed)");
R_UNLESS(out_pseudo_device_id, ResultUnknown);
// This should be hashed with the device specific hash
// for now this will do
@@ -454,21 +430,15 @@ Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value)
// https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart
Result IApplicationFunctions::CreateApplicationAndRequestToStart(u64 application_id) {
LOG_INFO(Service_AM, "called, application_id={:016X} current_program_id={:016X}", application_id, m_applet->program_id);
LOG_INFO(Service_AM, "called, application_id={:016X}", application_id);
if (application_id == 0 ||
FileSys::GetBaseTitleID(application_id) == FileSys::GetBaseTitleID(m_applet->program_id)) {
const auto program_index = application_id == 0
? 0
: application_id - FileSys::GetBaseTitleID(application_id);
// If application_id is 0, relaunch the current application
const u64 target_application_id =
(application_id == 0) ? m_applet->program_id : application_id;
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(program_index);
R_SUCCEED();
}
LOG_ERROR(Service_AM, "Launching a different application ({:016X}) is not implemented!", application_id);
R_THROW(ResultUnknown);
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(target_application_id);
R_SUCCEED();
}
Result IApplicationFunctions::ClearUserChannel() {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -8,7 +8,6 @@
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/display_controller.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/vi/shared_buffer_manager.h"
namespace Service::AM {
@@ -72,16 +71,16 @@ Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_l
}
Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
LOG_DEBUG(Service_AM, "called, unknown0={} fbshare_layer_index={} color={:#x}", unknown0,
fbshare_layer_index, color);
R_RETURN(applet->display_layer_manager.ClearAppletCaptureBuffer(fbshare_layer_index, color));
LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
unknown0, fbshare_layer_index, color);
R_SUCCEED();
}
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastForeground));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
@@ -91,9 +90,9 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::CallerApplet));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
@@ -103,9 +102,9 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastApplication));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/applet.h"
@@ -22,7 +22,7 @@ namespace Service::AM {
{10, nullptr, "StartShutdownSequenceForOverlay"},
{11, nullptr, "StartRebootSequenceForOverlay"},
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"},
{21, nullptr, "SetHandlingTouchScreenInputEnabled"},
{30, nullptr, "SetHealthWarningShowingState"},
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
{40, nullptr, "GetApplicationNintendoLogo"},
@@ -43,12 +43,10 @@ namespace Service::AM {
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
{
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_watching_short_home_button = true;
}
m_applet->overlay_in_foreground = true;
m_applet->home_button_short_pressed_blocked = false;
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate();
}
@@ -58,26 +56,16 @@ namespace Service::AM {
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
{
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_watching_short_home_button = false;
}
m_applet->overlay_in_foreground = false;
m_applet->home_button_short_pressed_blocked = false;
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate();
}
R_SUCCEED();
}
Result IOverlayFunctions::SetHandlingTouchScreenInputEnabled(bool enabled) {
LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_handling_touch_input = enabled;
R_SUCCEED();
}
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
LOG_DEBUG(Service_AM, "called");
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -20,7 +20,6 @@ namespace Service::AM {
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
Result IsHealthWarningRequired(Out<bool> is_required);
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
Result SetHandlingTouchScreenInputEnabled(bool enabled);
Result Unknown70();
private:
+80 -136
View File
@@ -4,11 +4,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
@@ -36,82 +32,46 @@ void WindowSystem::RequestUpdate() {
}
void WindowSystem::Update() {
{
std::scoped_lock lk{m_lock};
std::scoped_lock lk{m_lock};
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
// Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked();
// Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked();
// If the home menu is being locked into the foreground, handle that.
if (!this->LockHomeMenuIntoForegroundLocked()) {
const bool overlay_takes_input = this->DoesOverlayTakeInputLocked();
this->UpdateAppletStateLocked(m_overlay_display, true, overlay_takes_input);
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_takes_input);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_takes_input);
}
// If the home menu is being locked into the foreground, handle that.
if (this->LockHomeMenuIntoForegroundLocked()) {
return;
}
this->NotifyApplicationChangedIfNeeded();
bool overlay_blocks_input = false;
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
overlay_blocks_input = m_overlay_display->overlay_in_foreground;
}
// Recursively update each applet root.
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_blocks_input);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_blocks_input);
this->UpdateAppletStateLocked(m_overlay_display, true, false); // overlay is always updated, never blocked
}
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
{
std::scoped_lock lk{m_lock};
std::scoped_lock lk{m_lock};
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {
m_overlay_display = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
}
this->UpdateCurrentApplicationLocked();
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {
m_overlay_display = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
}
this->NotifyApplicationChangedIfNeeded();
}
void WindowSystem::UpdateCurrentApplicationLocked() {
const Applet* const candidate = m_application != nullptr ? m_application : m_home_menu;
if (candidate == nullptr) {
return;
}
auto* const process = candidate->process->GetHandle();
if (process == nullptr || process == m_system.Kernel().ApplicationProcess()) {
return;
}
LOG_INFO(Service_AM, "Current application is now {:016X}", candidate->program_id);
m_system.Kernel().SetApplicationProcess(process);
Settings::SetCurrentProgramID(candidate->program_id);
m_pending_application_notification = candidate->program_id;
}
void WindowSystem::NotifyApplicationChangedIfNeeded() {
std::optional<u64> program_id;
{
std::scoped_lock lk{m_lock};
program_id = std::exchange(m_pending_application_notification, std::nullopt);
}
if (!program_id.has_value()) {
return;
}
m_system.NotifyApplicationChanged(*program_id);
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
}
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
@@ -209,40 +169,18 @@ void WindowSystem::OnExitRequested() {
}
void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) {
const auto is_blocked = [message](const Applet& applet) {
if (message == AppletMessage::DetectShortPressingHomeButton &&
applet.applet_id == AppletId::OverlayDisplay &&
!applet.overlay_watching_short_home_button) {
return true;
}
switch (message) {
case AppletMessage::DetectShortPressingHomeButton:
return applet.home_button_short_pressed_blocked;
case AppletMessage::DetectLongPressingHomeButton:
return applet.home_button_long_pressed_blocked;
default:
return false;
}
};
const auto send_to = [&](Applet* applet) {
if (!applet) {
return;
}
std::scoped_lock lk{applet->lock};
if (is_blocked(*applet)) {
LOG_DEBUG(Service_AM, "Applet {} is blocking message {}",
static_cast<u32>(applet->applet_id), static_cast<u32>(message));
return;
}
applet->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
};
send_to(m_home_menu);
send_to(m_overlay_display);
send_to(m_application);
if (m_home_menu) {
std::scoped_lock lk_home{m_home_menu->lock};
m_home_menu->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
m_overlay_display->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_application) {
std::scoped_lock lk_application{m_application->lock};
m_application->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_event_observer) {
m_event_observer->RequestUpdate();
}
@@ -254,9 +192,19 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) {
case SystemButtonType::HomeButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton);
break;
case SystemButtonType::HomeButtonLongPressing:
case SystemButtonType::HomeButtonLongPressing: {
// Toggle overlay foreground visibility on long home press
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
m_overlay_display->overlay_in_foreground = !m_overlay_display->overlay_in_foreground;
LOG_INFO(Service_AM, "Overlay long-press toggle: overlay_in_foreground={} window_visible={}", m_overlay_display->overlay_in_foreground, m_overlay_display->window_visible);
}
SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton);
break;
// Force a state update after toggling overlay
if (m_event_observer) {
m_event_observer->RequestUpdate();
}
break; }
case SystemButtonType::CaptureButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton);
break;
@@ -369,8 +317,6 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
m_overlay_display = nullptr;
}
this->UpdateCurrentApplicationLocked();
// Finalize applet.
applet->OnProcessTerminatedLocked();
@@ -443,20 +389,7 @@ void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
applet->lock.lock();
}
bool WindowSystem::IsOverlayOpenLocked(const Applet& overlay) const {
return overlay.window_visible && overlay.overlay_watching_short_home_button;
}
bool WindowSystem::DoesOverlayTakeInputLocked() const {
if (m_overlay_display == nullptr) {
return false;
}
std::scoped_lock lk{m_overlay_display->lock};
return this->IsOverlayOpenLocked(*m_overlay_display);
}
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input) {
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking) {
// With no applet, we don't have anything to do.
if (!applet) {
return;
@@ -487,18 +420,24 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
return false;
}();
const bool is_overlay = applet->applet_id == AppletId::OverlayDisplay;
// Update visibility state.
const bool should_be_visible =
is_overlay ? applet->window_visible : (is_foreground && applet->window_visible);
// Overlay applets should always be visible when window_visible is true, regardless of foreground state
const bool should_be_visible = (applet->applet_id == AppletId::OverlayDisplay)
? applet->window_visible
: (is_foreground && applet->window_visible);
applet->display_layer_manager.SetWindowVisibility(should_be_visible);
const bool needs_hid_input =
is_overlay ? this->IsOverlayOpenLocked(*applet)
: (is_foreground && applet->window_visible && !overlay_takes_input);
applet->SetInteractibleLocked(needs_hid_input, needs_hid_input);
const bool should_be_interactible = (applet->applet_id == AppletId::OverlayDisplay)
? applet->overlay_in_foreground
: (is_foreground && applet->window_visible && !overlay_blocking);
if (applet->applet_id == AppletId::OverlayDisplay || applet->applet_id == AppletId::Application) {
LOG_DEBUG(Service_AM, "UpdateAppletStateLocked: applet={} overlay_in_foreground={} is_foreground={} window_visible={} overlay_blocking={} should_be_interactible={}",
static_cast<u32>(applet->applet_id), applet->overlay_in_foreground, is_foreground, applet->window_visible, overlay_blocking, should_be_interactible);
}
applet->SetInteractibleLocked(should_be_interactible);
// Update focus state and suspension.
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
@@ -514,18 +453,23 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
applet->UpdateSuspensionStateLocked(true);
}
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity.
s32 z_index = Background;
if (is_overlay) {
z_index = Overlay;
} else if (inherited_foreground) {
z_index = is_obscured ? Foreground : ForegroundVisible;
// Z-index logic like in reference C# implementation (tuned for overlay extremes)
s32 z_index = 0;
const bool now_foreground = inherited_foreground;
if (applet->applet_id == AppletId::OverlayDisplay) {
z_index = applet->overlay_in_foreground ? 100000 : -1;
} else if (now_foreground && !is_obscured) {
z_index = 2;
} else if (now_foreground) {
z_index = 1;
} else {
z_index = 0;
}
applet->display_layer_manager.SetOverlayZIndex(z_index);
// Recurse into child applets.
for (const auto& child_applet : applet->child_applets) {
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_takes_input);
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_blocking);
}
}
+1 -8
View File
@@ -9,7 +9,6 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include "common/common_types.h"
#include "core/hle/service/am/am_types.h"
@@ -61,16 +60,11 @@ public:
void OnPowerButtonPressed(ButtonPressDuration type) {}
private:
void UpdateCurrentApplicationLocked();
void NotifyApplicationChangedIfNeeded();
void PruneTerminatedAppletsLocked();
bool RestartAppletProcessLocked(Applet* applet);
bool LockHomeMenuIntoForegroundLocked();
void TerminateChildAppletsLocked(Applet* applet);
bool IsOverlayOpenLocked(const Applet& overlay) const;
bool DoesOverlayTakeInputLocked() const;
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input);
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);
void SendButtonAppletMessageLocked(AppletMessage message);
private:
@@ -94,7 +88,6 @@ private:
// Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{};
std::optional<u64> m_pending_application_notification{};
};
} // namespace Service::AM
@@ -23,7 +23,6 @@
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/am/am_results.h"
#include "core/loader/loader.h"
namespace Service::AOC {
@@ -32,10 +31,6 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return FileSys::GetBaseTitleID(title_id) == base;
}
static u64 GetCallerBaseTitleID(Core::System& system, const ClientProcessId& process_id) {
return FileSys::GetBaseTitleID(system.ResolveCallerProgramId(*process_id));
}
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
const auto& rcu = system.GetContentProvider();
@@ -96,7 +91,7 @@ IAddOnContentManager::~IAddOnContentManager() {
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto current = GetCallerBaseTitleID(system, process_id);
const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -117,7 +112,7 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id.pid);
const auto current = GetCallerBaseTitleID(system, process_id);
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -131,7 +126,8 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
}
}
R_UNLESS(out.size() >= offset, AM::ResultApplicationRecordNotFound);
// TODO(DarkLordZach): Find the correct error code.
R_UNLESS(out.size() >= offset, ResultUnknown);
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end());
@@ -145,7 +141,7 @@ Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto title_id = system.ResolveCallerProgramId(*process_id);
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
+7 -5
View File
@@ -24,8 +24,8 @@ static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
return out;
}
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_)
: ServiceFramework{system_, "IBcatService"}, backend{backend_}, program_id{program_id_},
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
: ServiceFramework{system_, "IBcatService"}, backend{backend_},
progress{{
ProgressServiceBackend{system_, "Normal"},
ProgressServiceBackend{system_, "Directory"},
@@ -70,7 +70,8 @@ Result IBcatService::RequestSyncDeliveryCache(
LOG_DEBUG(Service_BCAT, "called");
auto& progress_backend{GetProgressBackend(SyncType::Normal)};
backend.Synchronize(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
backend.Synchronize(system.Kernel(), {system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
GetProgressBackend(SyncType::Normal));
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
@@ -85,8 +86,9 @@ Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
LOG_DEBUG(Service_BCAT, "called, name={}", name);
auto& progress_backend{GetProgressBackend(SyncType::Directory)};
backend.SynchronizeDirectory(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, progress_backend);
backend.SynchronizeDirectory(system.Kernel(), {system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, progress_backend);
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
system, progress_backend.GetEvent(), progress_backend.GetImpl());
+1 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -22,7 +19,7 @@ class IDeliveryCacheProgressService;
class IBcatService final : public ServiceFramework<IBcatService> {
public:
explicit IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_);
explicit IBcatService(Core::System& system_, BcatBackend& backend_);
~IBcatService() override;
private:
@@ -42,7 +39,6 @@ private:
const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
BcatBackend& backend;
u64 program_id;
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
};
@@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/bcat/bcat_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/bcat/service_creator.h"
@@ -41,8 +37,7 @@ IServiceCreator::~IServiceCreator() = default;
Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
OutInterface<IBcatService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
*out_interface =
std::make_shared<IBcatService>(system, *backend, system.ResolveCallerProgramId(*process_id));
*out_interface = std::make_shared<IBcatService>(system, *backend);
R_SUCCEED();
}
@@ -50,7 +45,7 @@ Result IServiceCreator::CreateDeliveryCacheStorageService(
ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
const auto title_id = system.ResolveCallerProgramId(*process_id);
const auto title_id = system.GetApplicationProcessProgramID();
*out_interface =
std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
R_SUCCEED();
+2 -7
View File
@@ -243,15 +243,10 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
}
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute,
AlbumReportOption report_option,
const ApplicationData& app_data, std::span<const u8> image_data,
u64 aruid) {
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) {
R_UNLESS(!image_data.empty(), ResultUnknown); //TODO: ???
const u64 title_id = system.ResolveCallerProgramId(aruid);
const u64 title_id = system.GetApplicationProcessProgramID();
auto static_service =
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
+1 -2
View File
@@ -95,8 +95,7 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
manager->FlipVerticallyOnWrite(invert_y);
manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
},
layout,
Nvnflinger::LayerStackId::Screenshot);
layout);
}
} // namespace Service::Capture
@@ -14,7 +14,6 @@
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/patch_manager.h"
@@ -340,7 +339,7 @@ Result FileSystemController::RegisterProcess(
registrations.emplace(process_id, Registration{
.program_id = program_id,
.romfs_factory = std::move(romfs_factory),
.save_data_factory = CreateSaveDataFactory(FileSys::GetBaseTitleID(program_id)),
.save_data_factory = CreateSaveDataFactory(program_id),
});
LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
@@ -18,7 +18,6 @@
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h"
@@ -314,7 +313,7 @@ Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSyste
FileSys::ResultInvalidArgument);
if (attribute.program_id == 0) {
attribute.program_id = FileSys::GetBaseTitleID(program_id);
attribute.program_id = program_id;
}
FileSys::VirtualDir dir{};
+1 -1
View File
@@ -1164,7 +1164,7 @@ Result IHidServer::InitializeSevenSixAxisSensor(ClientAppletResourceUserId aruid
GetResourceManager()->GetConsoleSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress(), t_mem_1->GetOwner());
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
R_SUCCEED();
}
+1 -1
View File
@@ -312,7 +312,7 @@ Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode pollin
auto& device = devices[device_index.value()].device;
device->SetPollingMode(polling_mode);
device->SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
R_SUCCEED();
}
+2 -6
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -150,7 +147,7 @@ Result IRS::RunImageTransferProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
@@ -298,8 +295,7 @@ Result IRS::RunImageTransferExProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(),
t_mem->GetOwner());
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
+1 -1
View File
@@ -35,7 +35,7 @@ public:
, process{kernel, process_}
, user_rx{std::move(user_rx_)}
, user_ro{std::move(user_ro_)}
, context{process_->GetMemory()}
, context{system_.ApplicationMemory()}
{
// clang-format off
@@ -9,12 +9,15 @@
#include <optional>
#include <string>
#include "common/stb.h"
#define STBI_ONLY_JPEG 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/language.h"
@@ -333,8 +336,8 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
constexpr s32 data_offset = 0;
if (t_mem != nullptr && t_mem->GetOwner() != nullptr && app_count > 0) {
auto& memory = t_mem->GetOwner()->GetMemory();
if (t_mem != nullptr && app_count > 0) {
auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress();
for (size_t i = 0; i < app_count; ++i) {
@@ -77,7 +77,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
.transform_flags = layer.transform,
.crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending),
.layer_stack_mask = layer.layer_stack_mask,
});
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
@@ -69,7 +69,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x3:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
case 0x8:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, false);
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
case 0x9:
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
case 0xb:
@@ -83,7 +83,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x1a:
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd);
case 0x1b:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, true);
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
case 0x1d:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
default:
@@ -387,19 +387,8 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
return NvResult::Success;
}
Core::Memory::Memory& nvhost_gpu::GetSessionMemory(DeviceFD fd) {
if (const auto it = sessions.find(fd); it != sessions.end())
if (auto* const session = core.GetSession(it->second);
session != nullptr && session->process != nullptr)
return session->process->GetMemory();
LOG_ERROR(Service_NVDRV, "No session for fd={}, falling back to application memory", fd);
return system.ApplicationMemory();
}
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
bool kickoff) {
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
if (params.num_entries > commands.size()) {
UNIMPLEMENTED();
return NvResult::InvalidSize;
@@ -407,7 +396,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
Tegra::CommandList entries(params.num_entries);
if (kickoff) {
this->GetSessionMemory(fd).ReadBlock(params.address, entries.command_lists.data(),
system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
std::memcpy(entries.command_lists.data(), commands.data(),
@@ -16,10 +16,6 @@
#include "core/hle/service/nvdrv/nvdata.h"
#include "video_core/dma_pusher.h"
namespace Core::Memory {
class Memory;
}
namespace Tegra {
namespace Control {
struct ChannelState;
@@ -200,11 +196,8 @@ private:
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
Core::Memory::Memory& GetSessionMemory(DeviceFD fd);
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
bool kickoff = false);
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
std::span<const Tegra::CommandListHeader> commands);
@@ -8,7 +8,6 @@
#include "common/assert.h"
#include "common/logging.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
@@ -72,23 +71,17 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id;
if (const auto* session = core.GetSession(session_id);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelOpen(session->process->GetId());
}
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd);
if (it != sessions.end()) {
if (const auto* session = core.GetSession(it->second);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelClose(session->process->GetId());
}
sessions.erase(it);
}
}
+1 -6
View File
@@ -105,12 +105,7 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>(system);
server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv"));
const auto NvdrvInterfaceFactoryForApplets = [&, module] {
return std::make_shared<NVDRV>(system, module, "nvdrv:a");
};
server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets);
server_manager->RegisterNamedService("nvdrv:a", std::make_shared<NVDRV>(system, module, "nvdrv:a"));
server_manager->RegisterNamedService("nvdrv:s", std::make_shared<NVDRV>(system, module, "nvdrv:s"));
server_manager->RegisterNamedService("nvdrv:t", std::make_shared<NVDRV>(system, module, "nvdrv:t"));
server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
+2 -4
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -15,8 +15,7 @@ struct Layer {
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
s32 consumer_id_)
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false),
layer_stack_mask(DefaultLayerStackMask) {}
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {}
~Layer() {
buffer_item_consumer->Abandon();
}
@@ -27,7 +26,6 @@ struct Layer {
bool visible;
s32 z_index;
bool is_overlay;
u32 layer_stack_mask;
};
struct LayerStack {
@@ -115,7 +115,6 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
.acquire_fence = item.fence,
.layer_stack_mask = layer->layer_stack_mask,
});
}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -26,25 +23,6 @@ enum class LayerBlending : u32 {
Coverage = 0x405,
};
enum class LayerStackId : u32 {
Default = 0,
Lcd = 1,
Screenshot = 2,
Recording = 3,
LastFrame = 4,
Arbitrary = 5,
ApplicationForDebug = 6,
Null = 10,
};
constexpr u32 LayerStackBit(LayerStackId id) {
return 1U << static_cast<u32>(id);
}
constexpr u32 DefaultLayerStackMask =
LayerStackBit(LayerStackId::Default) | LayerStackBit(LayerStackId::Screenshot) |
LayerStackBit(LayerStackId::Recording) | LayerStackBit(LayerStackId::LastFrame);
struct HwcLayer {
u32 buffer_handle;
u32 offset;
@@ -57,7 +35,6 @@ struct HwcLayer {
android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect;
android::Fence acquire_fence;
u32 layer_stack_mask;
};
} // namespace Service::Nvnflinger
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -104,14 +104,6 @@ void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blen
}
}
void SurfaceFlinger::SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask) {
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->layer_stack_mask = layer_stack_mask;
LOG_DEBUG(Service_VI, "Layer {} stack mask set to {:#x}", consumer_binder_id,
layer_stack_mask);
}
}
void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) {
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->is_overlay = is_overlay;
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -48,7 +48,6 @@ public:
void SetLayerVisibility(s32 consumer_binder_id, bool visible);
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay);
void SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask);
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -13,10 +13,8 @@
namespace Service::PCTL {
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_,
u64 program_id_)
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
program_id{program_id_},
service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
unlinked_event{service_context}, request_suspension_event{service_context} {
// clang-format off
@@ -204,6 +202,7 @@ Result IParentalControlService::Initialize() {
// TODO(ogniK): Recovery flag initialization for pctl:r
const auto program_id = system.GetApplicationProcessProgramID();
if (program_id != 0) {
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -16,8 +16,7 @@ namespace Service::PCTL {
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
explicit IParentalControlService(Core::System& system_, Capability capability_,
u64 program_id_);
explicit IParentalControlService(Core::System& system_, Capability capability_);
~IParentalControlService() override;
private:
@@ -85,7 +84,6 @@ private:
RestrictionSettings restriction_settings{};
std::array<char, 8> pin_code{};
Capability capability{};
u64 program_id{};
// TODO: this is raw
PlayTimerSettings raw_play_timer_settings{};
@@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pctl/parental_control_service.h"
#include "core/hle/service/pctl/parental_control_service_factory.h"
@@ -27,17 +23,17 @@ IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
Result IParentalControlServiceFactory::CreateService(
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
*out_service = std::make_shared<IParentalControlService>(
system, capability, system.ResolveCallerProgramId(*process_id));
LOG_DEBUG(Service_PCTL, "called");
// TODO(ogniK): Get application id from process
*out_service = std::make_shared<IParentalControlService>(system, capability);
R_SUCCEED();
}
Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
*out_service = std::make_shared<IParentalControlService>(
system, capability, system.ResolveCallerProgramId(*process_id));
LOG_DEBUG(Service_PCTL, "called");
// TODO(ogniK): Get application id from process
*out_service = std::make_shared<IParentalControlService>(system, capability);
R_SUCCEED();
}
+5 -2
View File
@@ -132,7 +132,8 @@ private:
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
auto process = kernel.GetProcessByProcessId(pid);
auto list = kernel.GetProcessList();
auto process = SearchProcessList(system.Kernel(), list, [pid](auto& p) { return p->GetProcessId() == pid; });
if (process.IsNull()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -185,7 +186,9 @@ private:
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
auto process = kernel.GetProcessByProcessId(process_id);
auto list = kernel.GetProcessList();
auto process = SearchProcessList(system.Kernel(),
list, [process_id](auto& p) { return p->GetProcessId() == process_id; });
if (process.IsNull()) {
IPC::ResponseBuilder rb{ctx, 2};
+2 -2
View File
@@ -76,7 +76,7 @@ private:
Type, process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id);
IPC::ResponseBuilder rb{ctx, 2};
@@ -98,7 +98,7 @@ private:
Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id, user_id);
IPC::ResponseBuilder rb{ctx, 2};
+1 -6
View File
@@ -588,12 +588,7 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
auto ro = std::make_shared<RoContext>();
const auto RoInterfaceFactoryForUser = [&, ro] {
return std::make_shared<RoInterface>(system, "ldr:ro", ro, NrrKind::User);
};
server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser));
server_manager->RegisterNamedService("ldr:ro", std::make_shared<RoInterface>(system, "ldr:ro", ro, NrrKind::User));
server_manager->RegisterNamedService("ro:1", std::make_shared<RoInterface>(system, "ro:1", ro, NrrKind::JitPlugin));
server_manager->RegisterNamedService("ro:dmnt", std::make_shared<IDebugMonitorInterface>(system));
ServerManager::RunServer(std::move(server_manager));
+1 -15
View File
@@ -4,16 +4,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <fmt/ranges.h>
#include <string_view>
#include <thread>
#include "common/assert.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h"
@@ -37,7 +33,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
: SessionRequestHandler(system_.Kernel(), service_name_)
, system{system_}
, service_name{service_name_}
, is_i_storage{std::string_view{service_name_} == "IStorage"}
, handler_invoker{handler_invoker_}
, max_sessions{max_sessions_}
{}
@@ -82,22 +77,13 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
}
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
const auto command = ctx.GetCommand();
auto it = handlers.find(command);
const bool is_cmd_read = command == 0;
auto it = handlers.find(ctx.GetCommand());
FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second;
if (info == nullptr || info->handler_callback == nullptr)
return ReportUnimplementedFunction(ctx, info);
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
handler_invoker(this, info->handler_callback, ctx);
if (is_i_storage && is_cmd_read) {
const auto* const process = ctx.GetThread().GetOwnerProcess();
if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) {
std::this_thread::sleep_for(std::chrono::microseconds{600});
}
}
}
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
-2
View File
@@ -107,8 +107,6 @@ protected:
Core::System& system;
/// Identifier string used to connect to the service.
const char* service_name;
/// Whether this is the IStorage service.
const bool is_i_storage;
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker;
/// Maximum number of concurrent sessions that this service can handle.

Some files were not shown because too many files have changed in this diff Show More