Compare commits

..

1 Commits

Author SHA1 Message Date
PavelBARABANOV e5ce1dc1c9 [cpm]Revert OpenSSL to 3.6.0 2026-08-22 18:22:19 +03:00
208 changed files with 1609 additions and 4160 deletions
+1 -1
View File
@@ -201,7 +201,7 @@
"name": "openssl", "name": "openssl",
"package": "OpenSSL", "package": "OpenSSL",
"repo": "crueter-ci/OpenSSL", "repo": "crueter-ci/OpenSSL",
"version": "4.0.0-11b7b6ea3b" "version": "3.6.0-1cb0d36b39"
}, },
"openssl-cmake": { "openssl-cmake": {
"bundled": true, "bundled": true,
@@ -624,7 +624,6 @@ abstract class SettingsItem(
IntSetting.FSR_SHARPENING_SLIDER, IntSetting.FSR_SHARPENING_SLIDER,
titleId = R.string.fsr_sharpness, titleId = R.string.fsr_sharpness,
descriptionId = R.string.fsr_sharpness_description, descriptionId = R.string.fsr_sharpness_description,
max = 200,
units = "%" 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-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,6 +24,6 @@ object SettingsFile {
fun loadCustomConfig(game: Game) { fun loadCustomConfig(game: Game) {
val fileName = FileUtil.getFilename(Uri.parse(game.path)) 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, fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel, addonViewModel = addonViewModel,
documents = documents, documents = documents,
programId = args.game.applicationId programId = args.game.programId
) )
} }
@@ -347,7 +347,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
try { try {
if (GpuDriverHelper.isAdrenoGpu()) { if (GpuDriverHelper.isAdrenoGpu()) {
val programIdHex = game!!.applicationIdHex val programIdHex = game!!.programIdHex
if (NativeFreedrenoConfig.loadPerGameConfigWithGlobalFallback(programIdHex)) { if (NativeFreedrenoConfig.loadPerGameConfigWithGlobalFallback(programIdHex)) {
Log.info("[EmulationFragment] Loaded per-game Freedreno config for $programIdHex") Log.info("[EmulationFragment] Loaded per-game Freedreno config for $programIdHex")
} else { } else {
@@ -1182,7 +1182,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
container, container,
IntSetting.FSR_SHARPENING_SLIDER, IntSetting.FSR_SHARPENING_SLIDER,
minValue = 0, minValue = 0,
maxValue = 200, maxValue = 100,
units = "%" units = "%"
) )
} }
@@ -59,7 +59,7 @@ class FreedrenoSettingsFragment : Fragment() {
NativeFreedrenoConfig.initializeFreedrenoConfig() NativeFreedrenoConfig.initializeFreedrenoConfig()
if (isPerGameConfig) { if (isPerGameConfig) {
NativeFreedrenoConfig.loadPerGameConfig(game!!.applicationIdHex) NativeFreedrenoConfig.loadPerGameConfig(game!!.programIdHex)
} else { } else {
NativeFreedrenoConfig.reloadFreedrenoConfig() NativeFreedrenoConfig.reloadFreedrenoConfig()
} }
@@ -157,7 +157,7 @@ class FreedrenoSettingsFragment : Fragment() {
binding.buttonSave.setOnClickListener { binding.buttonSave.setOnClickListener {
if (isPerGameConfig) { if (isPerGameConfig) {
NativeFreedrenoConfig.savePerGameConfig(game!!.applicationIdHex) NativeFreedrenoConfig.savePerGameConfig(game!!.programIdHex)
showSnackbar(getString(R.string.freedreno_per_game_saved)) showSnackbar(getString(R.string.freedreno_per_game_saved))
} else { } else {
NativeFreedrenoConfig.saveFreedrenoConfig() NativeFreedrenoConfig.saveFreedrenoConfig()
@@ -455,7 +455,7 @@ class GamePropertiesFragment : Fragment() {
val shaderCacheDir = File( val shaderCacheDir = File(
DirectoryInitialization.userDirectory + DirectoryInitialization.userDirectory +
"/cache/shader/" + args.game.shaderCacheName.lowercase() "/cache/shader/" + args.game.settingsName.lowercase()
) )
if (shaderCacheDir.exists()) { if (shaderCacheDir.exists()) {
add( add(
@@ -600,7 +600,7 @@ class GamePropertiesFragment : Fragment() {
val files = cacheSaveDir.listFiles() val files = cacheSaveDir.listFiles()
var savesFolderFile: File? = null var savesFolderFile: File? = null
if (files != null) { if (files != null) {
val savesFolderName = args.game.applicationIdHex val savesFolderName = args.game.programIdHex
for (file in files) { for (file in files) {
if (file.isDirectory && file.name == savesFolderName) { if (file.isDirectory && file.name == savesFolderName) {
savesFolderFile = file savesFolderFile = file
@@ -232,7 +232,7 @@ class InstallableFragment : Fragment() {
fragmentManager = parentFragmentManager, fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel, addonViewModel = addonViewModel,
documents = documents, documents = documents,
programId = addonViewModel.game?.applicationId programId = addonViewModel.game?.programId
) )
} }
@@ -142,11 +142,10 @@ class AddonViewModel : ViewModel() {
} }
fun onDeleteAddon(patch: Patch) { fun onDeleteAddon(patch: Patch) {
val currentGame = game ?: return
when (PatchType.from(patch.type)) { when (PatchType.from(patch.type)) {
PatchType.Update -> NativeLibrary.removeUpdate(currentGame.programId) PatchType.Update -> NativeLibrary.removeUpdate(patch.programId)
PatchType.DLC -> NativeLibrary.removeDLC(currentGame.applicationId) PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(currentGame.programId, patch.name) PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
} }
refreshAddons(force = true) refreshAddons(force = true)
} }
@@ -166,7 +165,7 @@ class AddonViewModel : ViewModel() {
} }
NativeConfig.setDisabledAddons( NativeConfig.setDisabledAddons(
currentGame.applicationId, currentGame.programId,
currentList.mapNotNull { currentList.mapNotNull {
if (it.enabled) { if (it.enabled) {
null null
@@ -200,6 +199,6 @@ class AddonViewModel : ViewModel() {
} }
private fun gameKey(game: Game): String { 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 ?: return@withContext
val shaderDir = File( val shaderDir = File(
externalFilesDir.absolutePath + externalFilesDir.absolutePath +
"/shader/" + game.shaderCacheName.lowercase() "/shader/" + game.settingsName.lowercase()
) )
if (shaderDir.exists()) { if (shaderDir.exists()) {
shaderDir.deleteRecursively() 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -35,46 +35,23 @@ class Game(
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime" val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${path}_LastPlayed" 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 val settingsName: String
get() { get() {
return if (applicationIdLong == 0L) { val programIdLong = programId.toLong()
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + applicationIdLong.toString(16).uppercase()
}
}
val programIdHex: String
get() {
return if (programIdLong == 0L) { return if (programIdLong == 0L) {
"0" FileUtil.getFilename(Uri.parse(path))
} else { } else {
"0" + programIdLong.toString(16).uppercase() "0" + programIdLong.toString(16).uppercase()
} }
} }
val shaderCacheName: String val programIdHex: String
get() = if (programIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + programIdLong.toString(16).uppercase()
}
val applicationIdHex: String
get() { get() {
return if (applicationIdLong == 0L) { val programIdLong = programId.toLong()
return if (programIdLong == 0L) {
"0" "0"
} else { } else {
"0" + applicationIdLong.toString(16).uppercase() "0" + programIdLong.toString(16).uppercase()
} }
} }
@@ -84,10 +61,10 @@ class Game(
}.zip" }.zip"
val saveDir: String val saveDir: String
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(applicationId) get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(programId)
val addonDir: String val addonDir: String
get() = DirectoryInitialization.userDirectory + "/load/" + applicationIdHex + "/" get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
val launchIntent: Intent val launchIntent: Intent
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -65,7 +65,7 @@ object CustomSettingsHandler {
// Initialize per-game config // Initialize per-game config
try { try {
val fileName = FileUtil.getFilename(Uri.parse(game.path)) 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") Log.info("[CustomSettingsHandler] Successfully applied custom settings")
return game return game
} catch (e: Exception) { } catch (e: Exception) {
@@ -333,20 +333,20 @@ object CustomSettingsHandler {
*/ */
fun findGameByTitleId(titleId: String, context: Context): Game? { fun findGameByTitleId(titleId: String, context: Context): Game? {
Log.info("[CustomSettingsHandler] Searching for game with title ID: $titleId") Log.info("[CustomSettingsHandler] Searching for game with title ID: $titleId")
// Convert the program ID to the application ID used by per-game settings. // Convert hex title ID to decimal for comparison with programId
val applicationIdLong = try { val programIdDecimal = try {
titleId.toLong(16) and -8192L titleId.toLong(16).toString()
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
Log.error("[CustomSettingsHandler] Invalid title ID format: $titleId") Log.error("[CustomSettingsHandler] Invalid title ID format: $titleId")
return null return null
} }
val applicationIdDecimal = applicationIdLong.toString()
// Expected hex format with "0" prefix // 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 // First check cached games for fast lookup
GameHelper.cachedGameList.find { game -> GameHelper.cachedGameList.find { game ->
game.applicationId == applicationIdDecimal || game.applicationIdHex.equals(expectedHex, ignoreCase = true) game.programId == programIdDecimal ||
game.programIdHex.equals(expectedHex, ignoreCase = true)
}?.let { foundGame -> }?.let { foundGame ->
Log.info("[CustomSettingsHandler] Found game in cache: ${foundGame.title}") Log.info("[CustomSettingsHandler] Found game in cache: ${foundGame.title}")
return foundGame return foundGame
@@ -355,7 +355,8 @@ object CustomSettingsHandler {
Log.info("[CustomSettingsHandler] Game not in cache, scanning full library...") Log.info("[CustomSettingsHandler] Game not in cache, scanning full library...")
val allGames = GameHelper.getGames() val allGames = GameHelper.getGames()
val foundGame = allGames.find { game -> 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) { if (foundGame != null) {
Log.info("[CustomSettingsHandler] Found game: ${foundGame.title} at ${foundGame.path}") Log.info("[CustomSettingsHandler] Found game: ${foundGame.title} at ${foundGame.path}")
@@ -31,7 +31,6 @@ object GameHelper {
fun getGames(): List<Game> { fun getGames(): List<Game> {
val games = mutableListOf<Game>() val games = mutableListOf<Game>()
val gamesByProgramId = mutableMapOf<String, Game>()
val context = YuzuApplication.appContext val context = YuzuApplication.appContext
preferences = PreferenceManager.getDefaultSharedPreferences(context) preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -64,7 +63,6 @@ object GameHelper {
addGamesRecursive( addGamesRecursive(
games, games,
gamesByProgramId,
FileUtil.listFiles(gameDirUri), FileUtil.listFiles(gameDirUri),
scanDepth, scanDepth,
mountedContainerUris mountedContainerUris
@@ -138,7 +136,6 @@ object GameHelper {
private fun addGamesRecursive( private fun addGamesRecursive(
games: MutableList<Game>, games: MutableList<Game>,
gamesByProgramId: MutableMap<String, Game>,
files: Array<MinimalDocumentFile>, files: Array<MinimalDocumentFile>,
depth: Int, depth: Int,
mountedContainerUris: MutableSet<String> mountedContainerUris: MutableSet<String>
@@ -151,7 +148,6 @@ object GameHelper {
if (it.isDirectory) { if (it.isDirectory) {
addGamesRecursive( addGamesRecursive(
games, games,
gamesByProgramId,
FileUtil.listFiles(it.uri), FileUtil.listFiles(it.uri),
depth - 1, depth - 1,
mountedContainerUris mountedContainerUris
@@ -160,9 +156,8 @@ object GameHelper {
val extension = FileUtil.getExtension(it.uri).lowercase() val extension = FileUtil.getExtension(it.uri).lowercase()
val filePath = it.uri.toString() val filePath = it.uri.toString()
val mountedContainer = externalContentExtensions.contains(extension) && if (externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath) mountedContainerUris.add(filePath)) {
if (mountedContainer) {
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath) NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
} }
@@ -170,20 +165,6 @@ object GameHelper {
val game = getGame(it.uri, true, false) val game = getGame(it.uri, true, false)
if (game != null) { if (game != null) {
games.add(game) 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-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game 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( class GameIconFetcher(
private val game: Game, private val game: Game,
@@ -43,15 +31,14 @@ class GameIconFetcher(
) : Fetcher { ) : Fetcher {
override suspend fun fetch(): FetchResult { override suspend fun fetch(): FetchResult {
return DrawableResult( return DrawableResult(
drawable = decodeGameIcon(game)!!.toDrawable(options.context.resources), drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources),
isSampled = false, isSampled = false,
dataSource = DataSource.DISK dataSource = DataSource.DISK
) )
} }
private fun decodeGameIcon(game: Game): Bitmap? { private fun decodeGameIcon(uri: String): Bitmap? {
val data = GameMetadata.getIcon(game.path) val data = GameMetadata.getIcon(uri)
gameIconHashes[game.iconCacheKey()] = data.contentHashCode()
return BitmapFactory.decodeByteArray( return BitmapFactory.decodeByteArray(
data, data,
0, 0,
@@ -67,7 +54,7 @@ class GameIconFetcher(
} }
class GameIconKeyer : Keyer<Game> { 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 { object GameIconUtils {
@@ -84,58 +71,14 @@ object GameIconUtils {
.build() .build()
fun loadGameIcon(game: Game, imageView: ImageView) { fun loadGameIcon(game: Game, imageView: ImageView) {
gameIconTargets[imageView] = GameIconTarget(game)
val request = ImageRequest.Builder(YuzuApplication.appContext) val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game) .data(game)
.target(imageView) .target(imageView)
.error(R.drawable.default_icon) .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() .build()
imageLoader.enqueue(request) 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 { suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
val request = ImageRequest.Builder(YuzuApplication.appContext) val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game) .data(game)
+11 -67
View File
@@ -76,7 +76,6 @@ extern "C" {
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h" #include "core/frontend/applets/web_browser.h"
#include "common/android/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/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
@@ -312,23 +311,11 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
ConfigureFilesystemProvider(filepath); ConfigureFilesystemProvider(filepath);
// Load the ROM. // 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{ Service::AM::FrontendAppletParameters params{
.program_id = previous_program_id,
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id), .applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
: Service::AM::LaunchType::ApplicationInitiated, : Service::AM::LaunchType::ApplicationInitiated,
.program_index = static_cast<s32>(program_index), .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); 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.GetCpuManager().OnGpuReady();
m_system.RegisterExitCallback([&] { HaltEmulation(); }); 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 // Register an ExecuteProgram callback such that Core can execute a sub-program
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) { m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
m_next_program_id = m_system.GetApplicationProcessProgramID();
m_next_program_index = program_index_; m_next_program_index = program_index_;
EmulationSession::GetInstance().HaltEmulation(); EmulationSession::GetInstance().HaltEmulation();
}); });
@@ -424,58 +407,20 @@ void EmulationSession::RunEmulation() {
} }
while (true) { while (true) {
std::optional<u64> reload_title;
{ {
[[maybe_unused]] std::unique_lock lock(m_mutex); [[maybe_unused]] std::unique_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800), [&]() { if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
return !m_is_running || m_pending_shader_cache_title.has_value(); [&]() { return !m_is_running; })) {
})) { // Emulation halted.
if (!m_is_running) { break;
break;
}
reload_title = std::exchange(m_pending_shader_cache_title, std::nullopt);
} }
} }
if (reload_title.has_value())
ReloadDiskShaderCache(*reload_title);
} }
// Reset current applet ID. // Reset current applet ID.
m_applet_id = static_cast<int>(Service::AM::AppletId::Application); 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() { Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard; 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, jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId, jstring jprogramId,
jstring jupdatePath) { 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::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( 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& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) { for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) { 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) { if (update_id == program_id) {
return true; 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) { 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); 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, void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(), ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id); program_id);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj, void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID( auto program_id = EmulationSession::GetProgramId(env, jprogramId);
EmulationSession::GetProgramId(env, jprogramId));
ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id); ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId, void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
jstring jname) { jstring jname) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(), ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, Common::Android::GetJString(env, jname)); 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 Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId)); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) { if (program_id == 0) {
return Common::Android::ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
-6
View File
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <optional>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android/applets/software_keyboard.h" #include "common/android/applets/software_keyboard.h"
#include "core/core.h" #include "core/core.h"
@@ -46,7 +44,6 @@ public:
void HaltEmulation(); void HaltEmulation();
void RunEmulation(); void RunEmulation();
void ShutdownEmulation(); void ShutdownEmulation();
void RequestDiskShaderCacheReload(u64 program_id);
const Core::PerfStatsResults& PerfStats(); const Core::PerfStatsResults& PerfStats();
int ShadersBuilding(); int ShadersBuilding();
@@ -68,7 +65,6 @@ private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
static void OnEmulationStopped(Core::SystemResultStatus result); static void OnEmulationStopped(Core::SystemResultStatus result);
static void ChangeProgram(std::size_t program_index); static void ChangeProgram(std::size_t program_index);
void ReloadDiskShaderCache(u64 program_id);
private: private:
// Window management // Window management
@@ -87,7 +83,6 @@ private:
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1}; int m_applet_id{1};
std::optional<u64> m_pending_shader_cache_title;
// GPU driver parameters // GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library; std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
@@ -98,5 +93,4 @@ private:
// Program index for next boot // Program index for next boot
std::atomic<s32> m_next_program_index = -1; 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/fs/path_util.h"
#include "common/logging.h" #include "common/logging.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/file_sys/common_funcs.h"
#include "frontend_common/config.h" #include "frontend_common/config.h"
#include "frontend_common/settings_generator.h" #include "frontend_common/settings_generator.h"
#include "native.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, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv* env, jobject obj,
jstring jprogramId, jstring jprogramId,
jstring jfileName) { 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); auto file_name = Common::Android::GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id); const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config = 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, jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId) { 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]; auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray = jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(), 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, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId, jstring jprogramId,
jobjectArray jdisabledAddons) { 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(); Settings::values.disabled_addons[program_id].clear();
std::vector<std::string> disabled_addons; std::vector<std::string> disabled_addons;
const int size = env->GetArrayLength(jdisabledAddons); const int size = env->GetArrayLength(jdisabledAddons);
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="?attr/colorControlHighlight" />
<item android:state_focused="true" android:color="@android:color/transparent" />
<item android:state_selected="true" android:color="@android:color/transparent" />
<item android:state_hovered="true" android:color="@android:color/transparent" />
<item android:color="@android:color/transparent" />
</selector>
@@ -10,7 +10,6 @@
android:clipChildren="true" android:clipChildren="true"
android:layout_margin="0dp" android:layout_margin="0dp"
app:cardBackgroundColor="@color/eden_card_background" app:cardBackgroundColor="@color/eden_card_background"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="1dp" app:strokeWidth="1dp"
app:strokeColor="@color/eden_border"> app:strokeColor="@color/eden_border">
@@ -11,7 +11,6 @@
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:cardPreventCornerOverlap="true" app:cardPreventCornerOverlap="true"
android:clipChildren="true" android:clipChildren="true"
app:rippleColor="@color/game_card_ripple"
android:layout_margin="4dp"> android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true" android:focusable="true"
android:transitionName="card_game" android:transitionName="card_game"
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start"> android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true" android:focusable="true"
android:transitionName="card_game_compact" android:transitionName="card_game_compact"
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start"> android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@@ -12,7 +12,6 @@
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:cardElevation="0dp" app:cardElevation="0dp"
app:cardBackgroundColor="@android:color/transparent" app:cardBackgroundColor="@android:color/transparent"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="0dp"> app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@@ -1107,6 +1107,7 @@
<string name="theme_mode_light">فاتح</string> <string name="theme_mode_light">فاتح</string>
<string name="theme_mode_dark">داكن</string> <string name="theme_mode_dark">داكن</string>
<string name="multiplier_none">لا شيء</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">خلفيات سوداء</string> <string name="use_black_backgrounds">خلفيات سوداء</string>
@@ -991,6 +991,7 @@ Wirklich fortfahren?</string>
<string name="theme_mode_light">Hell</string> <string name="theme_mode_light">Hell</string>
<string name="theme_mode_dark">Dunkel</string> <string name="theme_mode_dark">Dunkel</string>
<string name="multiplier_none">Keine</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Schwarze Hintergründe</string> <string name="use_black_backgrounds">Schwarze Hintergründe</string>
@@ -1092,6 +1092,7 @@
<string name="theme_mode_light">Claro</string> <string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Oscuro</string> <string name="theme_mode_dark">Oscuro</string>
<string name="multiplier_none">Nada</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Fondos oscuros</string> <string name="use_black_backgrounds">Fondos oscuros</string>
@@ -808,6 +808,9 @@
<string name="multiplier_x4">x4</string> <string name="multiplier_x4">x4</string>
<string name="multiplier_x8">x8</string> <string name="multiplier_x8">x8</string>
<string name="multiplier_x16">x16</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 --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">پس‌زمینه مشکی</string> <string name="use_black_backgrounds">پس‌زمینه مشکی</string>
@@ -1004,6 +1004,7 @@
<string name="theme_mode_light">Lumineux</string> <string name="theme_mode_light">Lumineux</string>
<string name="theme_mode_dark">Sombre</string> <string name="theme_mode_dark">Sombre</string>
<string name="multiplier_none">Aucun</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Arrière-plan noir</string> <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_light">Jasny</string>
<string name="theme_mode_dark">Ciemny</string> <string name="theme_mode_dark">Ciemny</string>
<string name="multiplier_none">Brak</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Czarne tła</string> <string name="use_black_backgrounds">Czarne tła</string>
@@ -891,6 +891,7 @@
<string name="theme_mode_light">Claro</string> <string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Escuro</string> <string name="theme_mode_dark">Escuro</string>
<string name="multiplier_none">Nenhum</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Planos de fundo pretos</string> <string name="use_black_backgrounds">Planos de fundo pretos</string>
@@ -1071,6 +1071,7 @@
<string name="theme_mode_light">Светлая</string> <string name="theme_mode_light">Светлая</string>
<string name="theme_mode_dark">Темная</string> <string name="theme_mode_dark">Темная</string>
<string name="multiplier_none">Отключено</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чёрный фон</string> <string name="use_black_backgrounds">Чёрный фон</string>
@@ -1053,6 +1053,7 @@
<string name="theme_mode_light">Світла</string> <string name="theme_mode_light">Світла</string>
<string name="theme_mode_dark">Темна</string> <string name="theme_mode_dark">Темна</string>
<string name="multiplier_none">Жодного</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чорний фон</string> <string name="use_black_backgrounds">Чорний фон</string>
@@ -1081,6 +1081,7 @@
<string name="theme_mode_light">浅色</string> <string name="theme_mode_light">浅色</string>
<string name="theme_mode_dark">深色</string> <string name="theme_mode_dark">深色</string>
<string name="multiplier_none"></string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">使用黑色背景</string> <string name="use_black_backgrounds">使用黑色背景</string>
@@ -1006,6 +1006,7 @@
<string name="theme_mode_light">淺色</string> <string name="theme_mode_light">淺色</string>
<string name="theme_mode_dark">深色</string> <string name="theme_mode_dark">深色</string>
<string name="multiplier_none"></string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">黑色背景</string> <string name="use_black_backgrounds">黑色背景</string>
+23 -12
View File
@@ -111,38 +111,43 @@
<item>1</item> <item>1</item>
</integer-array> </integer-array>
<!-- VRAM USAGE MODE CHOICES -->
<string-array name="vramUsageMethodNames"> <string-array name="vramUsageMethodNames">
<item>@string/vram_usage_conservative</item> <item>@string/vram_usage_conservative</item>
<item>@string/vram_usage_aggressive</item> <item>@string/vram_usage_aggressive</item>
</string-array> </string-array>
<!-- VRAM USAGE MODE VALUES -->
<integer-array name="vramUsageMethodValues"> <integer-array name="vramUsageMethodValues">
<item>0</item> <item>0</item> <!-- Conservative -->
<item>1</item> <item>1</item> <!-- Aggressive -->
</integer-array> </integer-array>
<!-- ASTC Decoding Method Choices -->
<string-array name="astcDecodingMethodNames"> <string-array name="astcDecodingMethodNames">
<item>@string/accelerate_astc_cpu</item> <item>@string/accelerate_astc_cpu</item>
<item>@string/accelerate_astc_gpu</item> <item>@string/accelerate_astc_gpu</item>
<item>@string/accelerate_astc_async</item> <item>@string/accelerate_astc_async</item>
</string-array> </string-array>
<!-- ASTC Decoding Method Values -->
<integer-array name="astcDecodingMethodValues"> <integer-array name="astcDecodingMethodValues">
<item>0</item> <item>0</item> <!-- CPU -->
<item>1</item> <item>1</item> <!-- GPU -->
<item>2</item> <item>2</item> <!-- CPU Asynchronously -->
</integer-array> </integer-array>
<!-- NVDEC Emulation Choices -->
<string-array name="rendererNvdecNames"> <string-array name="rendererNvdecNames">
<item>@string/nvdec_emulation_none</item> <item>@string/nvdec_emulation_none</item> <!-- Off -->
<item>@string/nvdec_emulation_cpu</item> <item>@string/nvdec_emulation_cpu</item> <!-- Cpu -->
<item>@string/nvdec_emulation_gpu</item> <item>@string/nvdec_emulation_gpu</item> <!-- Gpu -->
</string-array> </string-array>
<!-- NVDEC Emulation Values -->
<integer-array name="rendererNvdecValues"> <integer-array name="rendererNvdecValues">
<item>0</item> <item>3</item> <!-- Off value -->
<item>1</item> <item>1</item> <!-- CPU value -->
<item>2</item> <item>2</item> <!-- GPU value -->
</integer-array> </integer-array>
<string-array name="rendererResolutionNames"> <string-array name="rendererResolutionNames">
@@ -508,6 +513,9 @@
<item>@string/multiplier_x4</item> <item>@string/multiplier_x4</item>
<item>@string/multiplier_x8</item> <item>@string/multiplier_x8</item>
<item>@string/multiplier_x16</item> <item>@string/multiplier_x16</item>
<item>@string/multiplier_x32</item>
<item>@string/multiplier_x64</item>
<item>@string/multiplier_none</item>
</string-array> </string-array>
<integer-array name="anisoValues"> <integer-array name="anisoValues">
<item>0</item> <item>0</item>
@@ -516,6 +524,9 @@
<item>3</item> <item>3</item>
<item>4</item> <item>4</item>
<item>5</item> <item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
</integer-array> </integer-array>
<string-array name="verticalAlignmentEntries"> <string-array name="verticalAlignmentEntries">
@@ -1246,6 +1246,9 @@
<string name="multiplier_x4" translatable="false">x4</string> <string name="multiplier_x4" translatable="false">x4</string>
<string name="multiplier_x8" translatable="false">x8</string> <string name="multiplier_x8" translatable="false">x8</string>
<string name="multiplier_x16" translatable="false">x16</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 --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Black backgrounds</string> <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-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,12 +7,13 @@
namespace AudioCore::ADSP::OpusDecoder { namespace AudioCore::ADSP::OpusDecoder {
namespace { 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) { bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax && return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
static_cast<s32>(stereo_stream_count) >= 0 && stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
stereo_stream_count <= total_stream_count;
} }
} // namespace } // 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-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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[4] = total_stream_count;
shared_memory.host_send_data[5] = stereo_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)); std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
opus_decoder.Send(ADSP::Direction::DSP, opus_decoder.Send(ADSP::Direction::DSP,
+27 -28
View File
@@ -19,23 +19,6 @@
namespace AudioCore::Sink { namespace AudioCore::Sink {
namespace { 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) { SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
int device_count = 0; int device_count = 0;
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count) SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -221,14 +204,20 @@ private:
}; };
SDLSink::SDLSink(std::string_view target_device_name) { SDLSink::SDLSink(std::string_view target_device_name) {
if (InitializeAudio()) { if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (target_device_name != auto_device_name && !target_device_name.empty()) { if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
output_device = target_device_name; LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
} else { return;
output_device.clear();
} }
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; SDLSink::~SDLSink() = default;
@@ -276,10 +265,15 @@ void SDLSink::SetSystemVolume(f32 volume) {
} }
std::vector<std::string> ListSDLSinkDevices(bool capture) { std::vector<std::string> ListSDLSinkDevices(bool capture) {
if (!InitializeAudio())
return {}; //no devices
std::vector<std::string> device_list; 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; int device_count = 0;
SDL_AudioDeviceID* devices = SDL_AudioDeviceID* devices =
capture ? SDL_GetAudioRecordingDevices(&device_count) capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -310,8 +304,13 @@ bool IsSDLSuitable() {
return false; return false;
#else #else
// Check SDL can init // Check SDL can init
if (!InitializeAudio()! if (!SDL_WasInit(SDL_INIT_AUDIO)) {
return false; 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. // 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 { 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 { namespace {
/// @brief Returns the name of the passed log class as a C-string. Subclasses are separated by periods /// @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 :) // Some IDEs prefer <file>:<line> instead, so let's just do that :)
std::string FormatLogMessage(const Entry& entry) noexcept { std::string FormatLogMessage(const Entry& entry) noexcept {
if (!entry.filename) return ""; 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 time_fractional = uint32_t(entry.timestamp.count() % 1000000);
auto const class_name = GetLogClassName(entry.log_class); auto const class_name = GetLogClassName(entry.log_class);
auto const level_name = GetLevelName(entry.log_level); 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> template <typename It>
Level GetLevelByName(const It begin, const It end) { Level GetLevelByName(const It begin, const It end) {
for (u32 i = 0; i < u32(Level::Count); ++i) { 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); instance.SetClassLevel(log_class, level);
return true; 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 /// @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 :) /// 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); SetConsoleTextAttribute(console_handle, color);
auto const df = GetDirectFormatArgs(entry); 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 {} void Flush() noexcept override {}
@@ -211,24 +220,22 @@ struct ColorConsoleBackend final : public Backend {
~ColorConsoleBackend() noexcept override {} ~ColorConsoleBackend() noexcept override {}
void Write(const Entry& entry) noexcept override { void Write(const Entry& entry) noexcept override {
if (enabled) { if (enabled) {
#define ESC "\x1b"
auto const color_str = [&entry]() -> const char* { auto const color_str = [&entry]() -> const char* {
switch (entry.log_level) { switch (entry.log_level) {
case Level::Debug: return "[0;36m"; // Cyan #define CCB_MAKE_COLOR_FMT(X) ESC X CCB_PRINTF_FMT ESC "[0m\n"
case Level::Info: return "[0;37m"; // Bright gray case Level::Debug: return CCB_MAKE_COLOR_FMT("[0;36m"); // Cyan
case Level::Warning: return "[1;33m"; // Bright yellow case Level::Info: return CCB_MAKE_COLOR_FMT("[0;37m"); // Bright gray
case Level::Error: return "[1;31m"; // Bright red case Level::Warning: return CCB_MAKE_COLOR_FMT("[1;33m"); // Bright yellow
case Level::Critical: return "[1;35m"; // Bright magenta case Level::Error: return CCB_MAKE_COLOR_FMT("[1;31m"); // Bright red
default: return "[1;30m"; // Grey 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); auto const df = GetDirectFormatArgs(entry);
// more restrictive, because take for example this simple prelude: 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());
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings: #undef ESC
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);
} }
} }
void Flush() noexcept override {} void Flush() noexcept override {}
@@ -239,7 +246,7 @@ struct ColorConsoleBackend final : public Backend {
#ifndef __OPENORBIS__ #ifndef __OPENORBIS__
/// @brief Backend that writes to a file passed into the constructor /// @brief Backend that writes to a file passed into the constructor
struct FileBackend final : public Backend { 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; auto old_filename = filename;
old_filename += ".old.txt"; old_filename += ".old.txt";
// Existence checks are done within the functions themselves. // Existence checks are done within the functions themselves.
@@ -254,7 +261,7 @@ struct FileBackend final : public Backend {
if (!enabled) if (!enabled)
return; return;
auto message = FormatLogMessage(entry); auto message = FormatLogMessage(entry).append(1, '\n');
#ifndef __ANDROID__ #ifndef __ANDROID__
if (Settings::values.censor_username.GetValue()) { if (Settings::values.censor_username.GetValue()) {
// This must be a static otherwise it would get checked on EVERY // 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 { static std::string username = []() -> std::string {
// in order of precedence // in order of precedence
// LOGNAME usually works on UNIX, USERNAME on Windows // 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", }) for (auto const var : { "LOGNAME", "USERNAME", "USER", })
if (auto const s = ::getenv(var); s != nullptr) if (auto const s = ::getenv(var); s != nullptr)
return std::string{s}; return std::string{s};
@@ -272,7 +280,7 @@ struct FileBackend final : public Backend {
boost::replace_all(message, username, "user"); boost::replace_all(message, username, "user");
} }
#endif #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 // Option to log each line rather than 4k buffers
if (Settings::values.log_flush_line.GetValue()) if (Settings::values.log_flush_line.GetValue())
@@ -300,13 +308,14 @@ private:
bool enabled = true; bool enabled = true;
}; };
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
/// @brief Backend that writes to Visual Studio's output window /// @brief Backend that writes to Visual Studio's output window
struct DebuggerBackend final : public Backend { struct DebuggerBackend final : public Backend {
explicit DebuggerBackend() noexcept = default; explicit DebuggerBackend() noexcept = default;
~DebuggerBackend() noexcept override = default; ~DebuggerBackend() noexcept override = default;
void Write(const Entry& entry) noexcept override { 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 {} void Flush() noexcept override {}
}; };
@@ -329,7 +338,7 @@ struct LogcatBackend : public Backend {
} }
}(); }();
auto const df = GetDirectFormatArgs(entry); 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 {} void Flush() noexcept override {}
}; };
@@ -368,23 +377,7 @@ struct Impl {
#endif #endif
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
}; };
} // Anonymous namespace } // 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;
}
}
// Constructor shall NOT depend upon Settings() or whatever // Constructor shall NOT depend upon Settings() or whatever
// it's ran at global static ctor() time... so BE CAREFUL MFER! // 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) { 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)) { if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
auto const flush = ::Settings::values.log_flush_line.GetValue(); 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) { logging_instance->ForEachBackend([=](Backend& backend) {
backend.Write(Entry{ backend.Write(Entry{
.message = buffer, .message = fmt::vformat(format, args),
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin), .timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
.log_class = log_class, .log_class = log_class,
.log_level = log_level, .log_level = log_level,
+21
View File
@@ -140,4 +140,25 @@ void Stop();
void SetGlobalFilter(const Filter& filter); void SetGlobalFilter(const Filter& filter);
void SetColorConsoleBackendEnabled(bool enabled); 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 } // 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) 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) \ #define LOG_PATH(NAME) \
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME))) LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
LOG_PATH(CacheDir); 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, GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt, Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu); 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(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3); ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120); 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_IMPLEMENTATION 1
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1 #define STB_IMAGE_RESIZE_IMPLEMENTATION 1
#define STB_IMAGE_WRITE_IMPLEMENTATION 1 #define STB_IMAGE_WRITE_IMPLEMENTATION 1
#define STBI_ONLY_JPEG 1
#include "common/stb.h" #include "common/stb.h"
-1
View File
@@ -7,7 +7,6 @@
#pragma once #pragma once
#define STBI_ONLY_JPEG 1 #define STBI_ONLY_JPEG 1
#define STBI_WRITE_NO_STDIO 1
#include <stb_image.h> #include <stb_image.h>
#include <stb_image_resize.h> #include <stb_image_resize.h>
#include <stb_image_write.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_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
break; break;
// Paranoia mode for debugging optimizations // Paranoia mode for debugging optimizations
case Settings::CpuAccuracy::Paranoid: 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.unsafe_optimizations = true;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.fastmem_address_space_bits = 64; config.fastmem_address_space_bits = 64;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
break; break;
// Paranoia mode for debugging optimizations // Paranoia mode for debugging optimizations
case Settings::CpuAccuracy::Paranoid: case Settings::CpuAccuracy::Paranoid:
+9 -79
View File
@@ -4,7 +4,6 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <unordered_map>
#include <utility> #include <utility>
#include "game_settings.h" #include "game_settings.h"
@@ -17,7 +16,6 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "launch_timestamp_cache.h" #include "launch_timestamp_cache.h"
#include "core/core_timing.h" #include "core/core_timing.h"
@@ -250,30 +248,12 @@ struct System::Impl {
} }
} }
void NotifyNVDECChannelOpen(u64 process_id) { void SetNVDECActive(bool is_nvdec_active) {
std::scoped_lock lock{nvdec_active_mutex}; nvdec_active = is_nvdec_active;
++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);
}
} }
bool GetNVDECActive() { bool GetNVDECActive() {
std::scoped_lock lock{nvdec_active_mutex}; return nvdec_active;
return !nvdec_active_channels.empty();
}
bool IsNVDECActiveForProcess(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
return nvdec_active_channels.contains(process_id);
} }
void InitializeDebugger(System& system, u16 port) { 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) { SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) {
InitializeKernel(system); InitializeKernel(system);
if (params.applet_type == Service::AM::AppletType::Application) {
current_application_filepath = filepath;
}
const auto file = GetGameFileFromPath(virtual_filesystem, filepath); const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
// Create the application process // Create the application process
@@ -354,7 +330,7 @@ struct System::Impl {
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id); LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
// Make the process created be the application // Make the process created be the application
kernel.SetApplicationProcess(process->GetHandle()); kernel.MakeApplicationProcess(process->GetHandle());
// Set up the rest of the system. // Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
@@ -397,7 +373,7 @@ struct System::Impl {
LOG_ERROR(Core, "Failed to find program id for ROM"); 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()) { if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info; Network::GameInfo game_info;
game_info.name = name; game_info.name = name;
@@ -491,7 +467,6 @@ struct System::Impl {
Core::SpeedLimiter speed_limiter; Core::SpeedLimiter speed_limiter;
ExecuteProgramCallback execute_program_callback; ExecuteProgramCallback execute_program_callback;
ExitCallback exit_callback; ExitCallback exit_callback;
ApplicationChangedCallback application_changed_callback;
std::optional<Service::Services> services; std::optional<Service::Services> services;
std::optional<Core::Debugger> debugger; std::optional<Core::Debugger> debugger;
@@ -513,8 +488,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<u8, 0x20> build_id{}; std::array<u8, 0x20> build_id{};
std::string current_application_filepath;
/// Service manager /// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager; std::shared_ptr<Service::SM::ServiceManager> service_manager;
/// ContentProviderUnion instance /// ContentProviderUnion instance
@@ -525,8 +498,6 @@ struct System::Impl {
mutable std::mutex suspend_guard; mutable std::mutex suspend_guard;
std::mutex general_channel_mutex; 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_paused{};
std::atomic_bool is_shutting_down{}; std::atomic_bool is_shutting_down{};
std::atomic_bool is_powered_on{}; std::atomic_bool is_powered_on{};
@@ -534,6 +505,7 @@ struct System::Impl {
bool extended_memory_layout : 1 = false; bool extended_memory_layout : 1 = false;
bool exit_locked : 1 = false; bool exit_locked : 1 = false;
bool exit_requested : 1 = false; bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;
void EnsureGeneralChannelInitialized(System& system) { void EnsureGeneralChannelInitialized(System& system) {
if (!general_channel_event) { if (!general_channel_event) {
@@ -597,22 +569,14 @@ void System::UnstallApplication() {
impl->UnstallApplication(); impl->UnstallApplication();
} }
void System::NotifyNVDECChannelOpen(u64 process_id) { void System::SetNVDECActive(bool is_nvdec_active) {
impl->NotifyNVDECChannelOpen(process_id); impl->SetNVDECActive(is_nvdec_active);
}
void System::NotifyNVDECChannelClose(u64 process_id) {
impl->NotifyNVDECChannelClose(process_id);
} }
bool System::GetNVDECActive() { bool System::GetNVDECActive() {
return impl->GetNVDECActive(); return impl->GetNVDECActive();
} }
bool System::IsNVDECActiveForProcess(u64 process_id) {
return impl->IsNVDECActiveForProcess(process_id);
}
void System::InitializeDebugger() { void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
} }
@@ -763,25 +727,7 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
} }
u64 System::GetApplicationProcessProgramID() const { u64 System::GetApplicationProcessProgramID() const {
const auto* const process = impl->kernel.ApplicationProcess(); return impl->kernel.ApplicationProcess()->GetProgramId();
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;
} }
Loader::ResultStatus System::GetGameName(std::string& out) const { 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. /// @brief Gets a reference to the user channel stack.
/// It is used to transfer data between programs. /// It is used to transfer data between programs.
std::vector<std::vector<u8>>& System::GetUserChannel() { 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() { void System::ApplySettings() {
impl->RefreshTime(*this); impl->RefreshTime(*this);
+1 -12
View File
@@ -191,10 +191,8 @@ public:
std::unique_lock<std::mutex> StallApplication(); std::unique_lock<std::mutex> StallApplication();
void UnstallApplication(); void UnstallApplication();
void NotifyNVDECChannelOpen(u64 process_id); void SetNVDECActive(bool is_nvdec_active);
void NotifyNVDECChannelClose(u64 process_id);
[[nodiscard]] bool GetNVDECActive(); [[nodiscard]] bool GetNVDECActive();
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
/** /**
* Initialize the debugger. * Initialize the debugger.
@@ -324,10 +322,6 @@ public:
[[nodiscard]] u64 GetApplicationProcessProgramID() const; [[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 /// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
@@ -428,7 +422,6 @@ public:
void PushGeneralChannelData(std::vector<u8>&& data); void PushGeneralChannelData(std::vector<u8>&& data);
bool TryPopGeneralChannel(std::vector<u8>& out_data); bool TryPopGeneralChannel(std::vector<u8>& out_data);
[[nodiscard]] Service::Event& GetGeneralChannelEvent(); [[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. /// Type used for the frontend to designate a callback for System to exit the application.
using ExitCallback = std::function<void()>; using ExitCallback = std::function<void()>;
@@ -442,10 +435,6 @@ public:
/// Instructs the frontend to exit the application. /// Instructs the frontend to exit the application.
void Exit(); 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. /// Applies any changes to settings to this core instance.
void ApplySettings(); void ApplySettings();
+2 -2
View File
@@ -29,7 +29,7 @@ static u8 MasterKeyIdForKeyGeneration(u8 key_generation) {
return std::max<u8>(key_generation, 1) - 1; 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()} { : file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
if (file == nullptr) { if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile; 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; status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
} else { } else {
status = Loader::ResultStatus::Success; 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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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. // After construction, use GetStatus to determine if the file is valid and ready to be used.
class NCA : public ReadOnlyVfsDirectory { class NCA : public ReadOnlyVfsDirectory {
public: 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; ~NCA() override;
Loader::ResultStatus GetStatus() const; Loader::ResultStatus GetStatus() const;
@@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_indirect_storage.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(); 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 { size_t IndirectStorage::Read(u8* buffer, size_t size, size_t offset) const {
// Validate pre-conditions. // Validate pre-conditions.
ASSERT(this->IsInitialized()); ASSERT(this->IsInitialized());
@@ -85,9 +85,6 @@ public:
void SetStorage(s32 idx, VirtualFile storage) { void SetStorage(s32 idx, VirtualFile storage) {
ASSERT(0 <= idx && idx < StorageCount); ASSERT(0 <= idx && idx < StorageCount);
m_data_storage[idx] = storage; m_data_storage[idx] = storage;
if (idx == 0) {
m_original_missing = storage == nullptr || storage->GetSize() == 0;
}
} }
template <typename T> template <typename T>
@@ -133,9 +130,6 @@ protected:
template <bool ContinuousCheck, bool RangeCheck, typename F> template <bool ContinuousCheck, bool RangeCheck, typename F>
Result OperatePerEntry(s64 offset, s64 size, F func); 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: private:
struct ContinuousReadingEntry { struct ContinuousReadingEntry {
@@ -160,8 +154,6 @@ private:
private: private:
mutable BucketTree m_table; mutable BucketTree m_table;
std::array<VirtualFile, StorageCount> m_data_storage; 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> template <bool ContinuousCheck, bool RangeCheck, typename F>
@@ -280,10 +272,6 @@ Result IndirectStorage::OperatePerEntry(s64 offset, s64 size, F func) {
if (needs_operate) { if (needs_operate) {
const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset(); 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) { if constexpr (RangeCheck) {
// Get the current data storage's size. // Get the current data storage's size.
s64 cur_data_storage_size = m_data_storage[cur_entry.storage_index]->GetSize(); 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, 0x10> nca_id;
std::array<u8, 0x6> size; std::array<u8, 0x6> size;
ContentRecordType type; ContentRecordType type;
u8 id_offset; INSERT_PADDING_BYTES(1);
}; };
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size."); 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 { struct MetaRecord {
u64_le title_id; u64_le title_id;
+61 -131
View File
@@ -161,7 +161,7 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
PatchManager::PatchManager(u64 title_id_, PatchManager::PatchManager(u64 title_id_,
const Service::FileSystem::FileSystemController& fs_controller_, const Service::FileSystem::FileSystemController& fs_controller_,
const ContentProvider& content_provider_) 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; PatchManager::~PatchManager() = default;
@@ -169,41 +169,13 @@ u64 PatchManager::GetTitleID() const {
return title_id; 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 { VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id); LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
if (exefs == nullptr) if (exefs == nullptr)
return exefs; return exefs;
const auto& disabled = Settings::values.disabled_addons[application_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true; bool update_disabled = true;
std::optional<u32> enabled_version; std::optional<u32> enabled_version;
@@ -211,7 +183,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
bool checked_manual = false; bool checked_manual = false;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider); 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) { if (content_union) {
// First, check ExternalContentProvider // First, check ExternalContentProvider
@@ -331,21 +303,17 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
} }
// LayeredExeFS // LayeredExeFS
const auto load_dirs = GetModificationLoadRoots(); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dirs = GetSDMCModificationLoadRoots(); const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
std::vector<VirtualDir> patch_dirs; std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
for (const auto& sdmc_load_dir : sdmc_load_dirs) { if (load_dir != nullptr) {
patch_dirs.push_back(sdmc_load_dir);
}
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories(); const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end()); 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) { std::sort(patch_dirs.begin(), patch_dirs.end(),
return l->GetName() < r->GetName(); [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
});
std::vector<VirtualDir> layers; std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1); 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, std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const { 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); const auto nso_build_id = fmt::format("{:0<64}", build_id);
std::vector<VirtualFile> out; 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); LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dirs = GetModificationLoadRoots(); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dirs.empty()) { if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso; return nso;
} }
std::vector<VirtualDir> patch_dirs; auto patch_dirs = load_dir->GetSubdirectories();
for (const auto& load_dir : load_dirs) { std::sort(patch_dirs.begin(), patch_dirs.end(),
const auto load_patch_dirs = load_dir->GetSubdirectories(); [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
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();
});
const auto patches = CollectPatches(patch_dirs, build_id); const auto patches = CollectPatches(patch_dirs, build_id);
auto out = nso; 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); LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
const auto load_dirs = GetModificationLoadRoots(); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dirs.empty()) { if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false; return false;
} }
std::vector<VirtualDir> patch_dirs; auto patch_dirs = load_dir->GetSubdirectories();
for (const auto& load_dir : load_dirs) { std::sort(patch_dirs.begin(), patch_dirs.end(),
const auto load_patch_dirs = load_dir->GetSubdirectories(); [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
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();
});
return !CollectPatches(patch_dirs, build_id).empty(); return !CollectPatches(patch_dirs, build_id).empty();
} }
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const { std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
const auto load_dirs = GetModificationLoadRoots(); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dirs.empty()) { if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {}; return {};
} }
const auto& disabled = Settings::values.disabled_addons[application_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
std::vector<VirtualDir> patch_dirs; auto patch_dirs = load_dir->GetSubdirectories();
for (const auto& load_dir : load_dirs) { std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
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(); });
// <mod dir> / <folder> / cheats / <build id>.txt // <mod dir> / <folder> / cheats / <build id>.txt
std::vector<Core::Memory::CheatEntry> out; 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_') // Uncareless user-friendly loading of patches (must start with 'cheat_')
// <mod dir> / <cheat file>.txt // <mod dir> / <cheat file>.txt
for (const auto& load_dir : load_dirs) { for (auto const& f : load_dir->GetFiles()) {
for (auto const& f : load_dir->GetFiles()) { auto const name = f->GetName();
auto const name = f->GetName(); if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) { std::vector<u8> data(f->GetSize());
std::vector<u8> data(f->GetSize()); if (f->Read(data.data(), data.size()) == data.size()) {
if (f->Read(data.data(), data.size()) == data.size()) { const Core::Memory::TextCheatParser parser;
const Core::Memory::TextCheatParser parser; auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
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));
std::copy(res.begin(), res.end(), std::back_inserter(out)); } else {
} else { LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
}
} }
} }
} }
return out; 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) { const Service::FileSystem::FileSystemController& fs_controller) {
std::vector<VirtualDir> load_dirs{fs_controller.GetModificationLoadRoot(title_id)}; const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
std::vector<VirtualDir> sdmc_load_dirs{fs_controller.GetSDMCModificationLoadRoot(title_id)}; const auto sdmc_load_dir = 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);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data && if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
type != ContentRecordType::HtmlDocument) || type != ContentRecordType::HtmlDocument) ||
(load_dirs.empty() && sdmc_load_dirs.empty())) { (load_dir == nullptr && sdmc_load_dir == nullptr)) {
return; return;
} }
const auto& disabled = Settings::values.disabled_addons[application_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
std::vector<VirtualDir> patch_dirs; std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
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());
}
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) { 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) { std::sort(patch_dirs.begin(), patch_dirs.end(),
return l->GetName() < r->GetName(); [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
});
std::vector<VirtualDir> layers; std::vector<VirtualDir> layers;
std::vector<VirtualDir> layers_ext; std::vector<VirtualDir> layers_ext;
@@ -657,8 +597,8 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
auto romfs = base_romfs; auto romfs = base_romfs;
// Game Updates // Game Updates
const auto update_tid = GetUpdateTitleIDForContent(); const auto update_tid = GetUpdateTitleID(title_id);
const auto& disabled = Settings::values.disabled_addons[application_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true; bool update_disabled = true;
std::optional<u32> enabled_version; std::optional<u32> enabled_version;
@@ -765,7 +705,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
// LayeredFS // LayeredFS
if (apply_layeredfs) { if (apply_layeredfs) {
ApplyLayeredFS(romfs, title_id, application_id, type, fs_controller); ApplyLayeredFS(romfs, title_id, type, fs_controller);
} }
return romfs; return romfs;
@@ -777,10 +717,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
} }
std::vector<Patch> out; std::vector<Patch> out;
const auto& disabled = Settings::values.disabled_addons[application_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates // Game Updates
const auto update_tid = GetUpdateTitleIDForContent(); const auto update_tid = GetUpdateTitleID(title_id);
std::vector<Patch> external_update_patches; std::vector<Patch> external_update_patches;
@@ -929,7 +869,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
.version = "", .version = "",
.type = PatchType::Update, .type = PatchType::Update,
.program_id = title_id, .program_id = title_id,
.title_id = update_tid, .title_id = title_id,
.source = PatchSource::Unknown, .source = PatchSource::Unknown,
.numeric_version = 0}; .numeric_version = 0};
@@ -955,7 +895,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
} }
// General Mods (LayeredFS and IPS) // 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()) for (auto const& f : mod_dir->GetFiles())
if (auto const name = f->GetName(); name.starts_with("cheat_")) { if (auto const name = f->GetName(); name.starts_with("cheat_")) {
auto const mod_disabled = std::find(disabled.begin(), disabled.end(), name) != disabled.end(); 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) // 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; std::string types;
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs")))
AppendCommaIfNotEmpty(types, "LayeredExeFS"); AppendCommaIfNotEmpty(types, "LayeredExeFS");
@@ -1057,10 +999,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
dlc_match.reserve(dlc_entries_with_origin.size()); dlc_match.reserve(dlc_entries_with_origin.size());
for (const auto& [slot, entry] : dlc_entries_with_origin) { for (const auto& [slot, entry] : dlc_entries_with_origin) {
const auto base_tid = GetBaseTitleID(entry.title_id); 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) { if (!matches_base) {
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}", 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; continue;
} }
@@ -1135,22 +1077,16 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
} }
std::optional<u32> PatchManager::GetGameVersion() 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)) { if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
return content_provider.GetEntryVersion(update_tid); return content_provider.GetEntryVersion(update_tid);
} }
if (const auto version = content_provider.GetEntryVersion(title_id); version.has_value()) { return content_provider.GetEntryVersion(title_id);
return version;
}
return content_provider.GetEntryVersion(application_id);
} }
PatchManager::Metadata PatchManager::GetControlMetadata() const { PatchManager::Metadata PatchManager::GetControlMetadata() const {
auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control); 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);
}
if (base_control_nca == nullptr) { if (base_control_nca == nullptr) {
return {}; return {};
} }
@@ -1226,14 +1162,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto metadata = pm.GetControlMetadata(); auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) if (metadata.first != nullptr)
return metadata; return metadata;
const auto update_id = FileSys::GetUpdateTitleID(application_id); const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(application_id), system.GetFileSystemController(), system.GetContentProvider()};
const auto application_update_id = FileSys::GetUpdateTitleID(GetBaseTitleID(application_id)); return pm_update.GetControlMetadata();
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();
} }
} // namespace FileSys } // namespace FileSys
-5
View File
@@ -10,7 +10,6 @@
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/nca_metadata.h" #include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs/vfs_types.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; [[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
private: 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, [[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const; const std::string& build_id) const;
u64 title_id; u64 title_id;
u64 application_id;
const Service::FileSystem::FileSystemController& fs_controller; const Service::FileSystem::FileSystemController& fs_controller;
const ContentProvider& content_provider; 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) { 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); const auto cmnt_iter = map.find(title_id);
u8 id_offset = 0;
if (cmnt_iter == map.cend()) { if (cmnt_iter == map.cend()) {
const auto program_index = title_id & AOC_TITLE_ID_MASK; return std::nullopt;
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);
} }
const auto& cnmt = cmnt_iter->second; const auto& cnmt = cmnt_iter->second;
const auto& content_records = cnmt.GetContentRecords(); const auto& content_records = cnmt.GetContentRecords();
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(), const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
[type, id_offset](const ContentRecord& rec) { [type](const ContentRecord& rec) { return rec.type == type; });
return rec.type == type && rec.id_offset == id_offset; if (iter == content_records.cend()) {
});
if (iter != content_records.cend()) {
return std::make_optional(iter->nca_id);
}
if (id_offset != 0) {
return std::nullopt; return std::nullopt;
} }
const auto fallback_iter = return std::make_optional(iter->nca_id);
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);
} }
std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id, std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
+6 -8
View File
@@ -12,7 +12,6 @@
#include "common/hex_util.h" #include "common/hex_util.h"
#include "common/logging.h" #include "common/logging.h"
#include "core/crypto/key_manager.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/content_archive.h"
#include "core/file_sys/nca_metadata.h" #include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h" #include "core/file_sys/partition_filesystem.h"
@@ -66,12 +65,10 @@ u64 NSP::GetProgramTitleID() const {
} }
auto program_id = expected_program_id; auto program_id = expected_program_id;
if (program_id == 0 && !program_status.empty()) { if (program_id == 0) {
program_id = std::min_element(program_status.cbegin(), program_status.cend(), if (!program_status.empty()) {
[](const auto& lhs, const auto& rhs) { program_id = program_status.begin()->first;
return lhs.first < rhs.first; }
})
->first;
} }
program_id = program_id + program_index; 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 // 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 // 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
// update NCA. // 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}] = ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
std::move(next_nca); std::move(next_nca);
} else { } else {
+4 -21
View File
@@ -349,18 +349,9 @@ struct KernelCore::Impl {
object_name_global_data.emplace(kernel); object_name_global_data.emplace(kernel);
} }
void SetApplicationProcess(KernelCore& kernel, KProcess* process) { void MakeApplicationProcess(KernelCore& kernel, KProcess* process) {
if (application_process == process)
return;
KProcess* const previous = application_process;
application_process = process; application_process = process;
application_process->Open(kernel);
if (application_process != nullptr)
application_process->Open(kernel);
if (previous != nullptr)
previous->Close(kernel);
} }
/// Sets the host thread ID for the caller. /// Sets the host thread ID for the caller.
@@ -888,8 +879,8 @@ void KernelCore::RemoveProcess(KProcess* process) {
} }
} }
void KernelCore::SetApplicationProcess(KProcess* process) { void KernelCore::MakeApplicationProcess(KProcess* process) {
impl->SetApplicationProcess(*this, process); impl->MakeApplicationProcess(*this, process);
} }
KProcess* KernelCore::ApplicationProcess() { KProcess* KernelCore::ApplicationProcess() {
@@ -900,14 +891,6 @@ const KProcess* KernelCore::ApplicationProcess() const {
return impl->application_process; 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>> KernelCore::GetProcessList() {
std::list<KScopedAutoObject<KProcess>> processes; std::list<KScopedAutoObject<KProcess>> processes;
std::scoped_lock lk{impl->process_list_lock}; std::scoped_lock lk{impl->process_list_lock};
+2 -5
View File
@@ -124,8 +124,8 @@ public:
void AppendNewProcess(KProcess* process); void AppendNewProcess(KProcess* process);
void RemoveProcess(KProcess* process); void RemoveProcess(KProcess* process);
/// Makes the given process the current application process. /// Makes the given process the new application process.
void SetApplicationProcess(KProcess* process); void MakeApplicationProcess(KProcess* process);
/// Retrieves a pointer to the application process. /// Retrieves a pointer to the application process.
KProcess* ApplicationProcess(); KProcess* ApplicationProcess();
@@ -133,9 +133,6 @@ public:
/// Retrieves a const pointer to the application process. /// Retrieves a const pointer to the application process.
const KProcess* ApplicationProcess() const; 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. /// Retrieves the list of processes.
std::list<KScopedAutoObject<KProcess>> GetProcessList(); 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-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,7 +10,6 @@ namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3}; constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22}; constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
constexpr Result ResultApplicationRecordNotFound{ErrorModule::AM, 37};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511}; constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -201,14 +201,6 @@ enum class ProgramSpecifyKind : u32 {
RestartProgram = 2, 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 { struct CommonArguments {
CommonArgumentVersion arguments_version; CommonArgumentVersion arguments_version;
CommonArgumentSize size; 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) { void Applet::SetInteractibleLocked(bool interactible) {
if (is_pad_interactible == pad_interactible && is_touch_interactible == touch_interactible) { if (is_interactible == interactible) {
return; return;
} }
is_pad_interactible = pad_interactible; is_interactible = interactible;
is_touch_interactible = touch_interactible;
const bool exit_requested = lifecycle_manager.GetExitRequested(); const bool exit_requested = lifecycle_manager.GetExitRequested();
const bool pad_enabled = pad_interactible && !exit_requested; const bool input_enabled = interactible && !exit_requested;
const bool touch_enabled = touch_interactible && !exit_requested;
LOG_DEBUG(Service_AM, "applet={} pad={} touch={} exit_requested={}", if (applet_id == AppletId::OverlayDisplay || applet_id == AppletId::Application) {
static_cast<u32>(applet_id), pad_enabled, touch_enabled, exit_requested); 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() { void Applet::OnProcessTerminatedLocked() {
+3 -5
View File
@@ -125,11 +125,9 @@ struct Applet {
bool album_image_taken_notification_enabled{}; bool album_image_taken_notification_enabled{};
bool record_volume_muted{}; bool record_volume_muted{};
bool is_activity_runnable{}; bool is_activity_runnable{};
bool is_pad_interactible{true}; bool is_interactible{true};
bool is_touch_interactible{true};
bool window_visible{true}; bool window_visible{true};
bool overlay_watching_short_home_button{false}; bool overlay_in_foreground{false};
bool overlay_handling_touch_input{false};
// Events // Events
Event overlay_event; Event overlay_event;
@@ -150,7 +148,7 @@ struct Applet {
// Process state management // Process state management
void UpdateSuspensionStateLocked(bool force_message); void UpdateSuspensionStateLocked(bool force_message);
void SetInteractibleLocked(bool pad_interactible, bool touch_interactible); void SetInteractibleLocked(bool interactible);
void OnProcessTerminatedLocked(); 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -6,7 +6,6 @@
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/am/display_layer_manager.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/sm/sm.h"
#include "core/hle/service/vi/application_display_service.h" #include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/container.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_buffer_id = 0;
m_system_shared_layer_id = 0; m_system_shared_layer_id = 0;
m_applet_id = applet_id; m_applet_id = applet_id;
m_library_applet_mode = mode;
m_buffer_sharing_enabled = false; m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground || m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay; 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()})); out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id); 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) { if (m_applet_id != AppletId::Application) {
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id); (void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
if (m_applet_id == AppletId::OverlayDisplay) { 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); (void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
} else { } 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 // Ensure the overlay layer is visible
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id); 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); 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) { if (m_applet_id == AppletId::OverlayDisplay) {
initial_z = Overlay; initial_z = -1;
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true); (void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
} }
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id); 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(); 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) { void DisplayLayerManager::SetWindowVisibility(bool visible) {
if (m_visible == visible) { if (m_visible == visible) {
return; return;
@@ -221,17 +185,10 @@ void DisplayLayerManager::SetOverlayZIndex(s32 z_index) {
} }
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written, Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index, s32* out_fbshare_layer_index) {
VI::CaptureKind kind) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied); R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer( R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, kind)); out_was_written, out_fbshare_layer_index));
}
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));
} }
} // namespace Service::AM } // 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -23,7 +23,6 @@ class KProcess;
namespace Service::VI { namespace Service::VI {
class IApplicationDisplayService; class IApplicationDisplayService;
class IManagerDisplayService; class IManagerDisplayService;
enum class CaptureKind : u32;
} // namespace Service::VI } // namespace Service::VI
namespace Service::AM { namespace Service::AM {
@@ -49,13 +48,9 @@ public:
void SetOverlayZIndex(s32 z_index); void SetOverlayZIndex(s32 z_index);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index, Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
VI::CaptureKind kind);
Result ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color);
private: private:
u32 GetLayerStackMask() const;
Kernel::KProcess* m_process{}; Kernel::KProcess* m_process{};
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{}; std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
std::shared_ptr<VI::IManagerDisplayService> m_manager_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_buffer_id{};
u64 m_system_shared_layer_id{}; u64 m_system_shared_layer_id{};
AppletId m_applet_id{}; AppletId m_applet_id{};
LibraryAppletMode m_library_applet_mode{};
bool m_buffer_sharing_enabled{}; bool m_buffer_sharing_enabled{};
bool m_blending_enabled{}; bool m_blending_enabled{};
bool m_visible{true}; bool m_visible{true};
+6 -11
View File
@@ -36,17 +36,12 @@ HidRegistration::~HidRegistration() {
} }
} }
void HidRegistration::EnableAppletToGetInput(bool enable_pad, bool enable_touch) { void HidRegistration::EnableAppletToGetInput(bool enable) {
if (!m_process.IsInitialized()) if (m_process.IsInitialized()) {
return; m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
enable);
const auto resource_manager = m_hid_server->GetResourceManager(); m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
const u64 aruid = m_process.GetProcessId(); }
resource_manager->EnablePadInput(aruid, enable_pad);
resource_manager->EnableTouchScreen(aruid, enable_touch);
resource_manager->SetAruidValidForVibration(aruid, enable_pad);
} }
} // namespace Service::AM } // namespace Service::AM
+1 -1
View File
@@ -28,7 +28,7 @@ public:
~HidRegistration(); ~HidRegistration();
void RegisterCurrentProcess(); void RegisterCurrentProcess();
void EnableAppletToGetInput(bool enable_pad, bool enable_touch); void EnableAppletToGetInput(bool enable);
private: private:
Process& m_process; Process& m_process;
+2 -11
View File
@@ -6,7 +6,6 @@
#include <optional> #include <optional>
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h" #include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.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 // TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId // current_process_game_card use correct StorageId
auto base_slot = storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program); launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
if (!base_slot) { launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
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);
system.GetARPManager().Register(launch.title_id, launch, out_control); system.GetARPManager().Register(launch.title_id, launch, out_control);
return process; return process;
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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/applet.h"
#include "core/hle/service/am/service/applet_common_functions.h" #include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/cmif_serialization.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) { Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
LOG_WARNING(Service_AM, "(STUBBED) called"); LOG_WARNING(Service_AM, "(STUBBED) called");
*out_application_id = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID()); *out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
R_SUCCEED(); R_SUCCEED();
} }
@@ -6,10 +6,8 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include "common/hex_util.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/uuid.h" #include "common/uuid.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/control_metadata.h" #include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h" #include "core/file_sys/registered_cache.h"
@@ -30,27 +28,6 @@
namespace Service::AM { 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) IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} { : ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
// clang-format off // 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()); LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{}; 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.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::Account; attribute.type = FileSys::SaveDataType::Account;
@@ -179,7 +156,7 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// Default to 0 (all languages supported) // Default to 0 (all languages supported)
u32 supported_languages = 0; 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) { if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages(); supported_languages = res.first->GetSupportedLanguages();
} }
@@ -217,7 +194,7 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) { Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
LOG_DEBUG(Service_AM, "called"); 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) { if (res.first != nullptr) {
const auto& version = res.first->GetVersionString(); const auto& version = res.first->GetVersionString();
std::memcpy(out_display_version->string.data(), version.data(), 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); static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( 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 // 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. // 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()); LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( 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_normal_size = size.normal;
*out_journal_size = size.journal; *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) { Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(stubbed)"); LOG_WARNING(Service_AM, "(stubbed)");
R_UNLESS(out_pseudo_device_id, ResultUnknown);
// This should be hashed with the device specific hash // This should be hashed with the device specific hash
// for now this will do // for now this will do
@@ -454,21 +430,15 @@ Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value)
// https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart // https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart
Result IApplicationFunctions::CreateApplicationAndRequestToStart(u64 application_id) { 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 || // If application_id is 0, relaunch the current application
FileSys::GetBaseTitleID(application_id) == FileSys::GetBaseTitleID(m_applet->program_id)) { const u64 target_application_id =
const auto program_index = application_id == 0 (application_id == 0) ? m_applet->program_id : application_id;
? 0
: application_id - FileSys::GetBaseTitleID(application_id);
system.GetUserChannel() = m_applet->user_channel_launch_parameter; system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(program_index); system.ExecuteProgram(target_application_id);
R_SUCCEED(); R_SUCCEED();
}
LOG_ERROR(Service_AM, "Launching a different application ({:016X}) is not implemented!", application_id);
R_THROW(ResultUnknown);
} }
Result IApplicationFunctions::ClearUserChannel() { 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -8,7 +8,6 @@
#include "core/hle/service/am/applet.h" #include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/display_controller.h" #include "core/hle/service/am/service/display_controller.h"
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/vi/shared_buffer_manager.h"
namespace Service::AM { 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) { Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
LOG_DEBUG(Service_AM, "called, unknown0={} fbshare_layer_index={} color={:#x}", unknown0, LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
fbshare_layer_index, color); unknown0, fbshare_layer_index, color);
R_RETURN(applet->display_layer_manager.ClearAppletCaptureBuffer(fbshare_layer_index, color)); R_SUCCEED();
} }
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called"); LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastForeground)); out_fbshare_layer_index));
} }
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() { Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
@@ -91,9 +90,9 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called"); LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_was_written, out_fbshare_layer_index, VI::CaptureKind::CallerApplet)); out_fbshare_layer_index));
} }
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() { Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
@@ -103,9 +102,9 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called"); LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastApplication)); out_fbshare_layer_index));
} }
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() { 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 // SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/applet.h" #include "core/hle/service/am/applet.h"
@@ -22,7 +22,7 @@ namespace Service::AM {
{10, nullptr, "StartShutdownSequenceForOverlay"}, {10, nullptr, "StartShutdownSequenceForOverlay"},
{11, nullptr, "StartRebootSequenceForOverlay"}, {11, nullptr, "StartRebootSequenceForOverlay"},
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"}, {20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"}, {21, nullptr, "SetHandlingTouchScreenInputEnabled"},
{30, nullptr, "SetHealthWarningShowingState"}, {30, nullptr, "SetHealthWarningShowingState"},
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"}, {31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
{40, nullptr, "GetApplicationNintendoLogo"}, {40, nullptr, "GetApplicationNintendoLogo"},
@@ -43,12 +43,10 @@ namespace Service::AM {
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() { Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called"); LOG_DEBUG(Service_AM, "called");
{ m_applet->overlay_in_foreground = true;
std::scoped_lock lk{m_applet->lock}; m_applet->home_button_short_pressed_blocked = false;
m_applet->overlay_watching_short_home_button = true;
}
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) { if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate(); window_system->RequestUpdate();
} }
@@ -58,26 +56,16 @@ namespace Service::AM {
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() { Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called"); LOG_DEBUG(Service_AM, "called");
{ m_applet->overlay_in_foreground = false;
std::scoped_lock lk{m_applet->lock}; m_applet->home_button_short_pressed_blocked = false;
m_applet->overlay_watching_short_home_button = false;
}
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) { if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate(); window_system->RequestUpdate();
} }
R_SUCCEED(); 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) { Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
LOG_DEBUG(Service_AM, "called"); 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 // SPDX-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
@@ -20,7 +20,6 @@ namespace Service::AM {
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled); Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
Result IsHealthWarningRequired(Out<bool> is_required); Result IsHealthWarningRequired(Out<bool> is_required);
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled); Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
Result SetHandlingTouchScreenInputEnabled(bool enabled);
Result Unknown70(); Result Unknown70();
private: private:
+80 -136
View File
@@ -4,11 +4,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/am/am_results.h" #include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h" #include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_manager.h"
@@ -36,82 +32,46 @@ void WindowSystem::RequestUpdate() {
} }
void WindowSystem::Update() { void WindowSystem::Update() {
{ std::scoped_lock lk{m_lock};
std::scoped_lock lk{m_lock};
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}", LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr); m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
// Loop through all applets and remove terminated applets. // Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked(); this->PruneTerminatedAppletsLocked();
// If the home menu is being locked into the foreground, handle that. // If the home menu is being locked into the foreground, handle that.
if (!this->LockHomeMenuIntoForegroundLocked()) { if (this->LockHomeMenuIntoForegroundLocked()) {
const bool overlay_takes_input = this->DoesOverlayTakeInputLocked(); return;
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);
}
} }
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) { 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) { if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr); ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get(); m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) { } else if (applet->applet_id == AppletId::OverlayDisplay) {
m_overlay_display = applet.get(); m_overlay_display = applet.get();
} else if (is_application) { } else if (is_application) {
ASSERT(m_application == nullptr); ASSERT(m_application == nullptr);
m_application = applet.get(); m_application = applet.get();
}
this->UpdateCurrentApplicationLocked();
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
} }
this->NotifyApplicationChangedIfNeeded(); m_event_observer->TrackAppletProcess(*applet);
} m_applets.emplace(applet->aruid.pid, std::move(applet));
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);
} }
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) { std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
@@ -209,40 +169,18 @@ void WindowSystem::OnExitRequested() {
} }
void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) { void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) {
const auto is_blocked = [message](const Applet& applet) { if (m_home_menu) {
if (message == AppletMessage::DetectShortPressingHomeButton && std::scoped_lock lk_home{m_home_menu->lock};
applet.applet_id == AppletId::OverlayDisplay && m_home_menu->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
!applet.overlay_watching_short_home_button) { }
return true; if (m_overlay_display) {
} std::scoped_lock lk_overlay{m_overlay_display->lock};
m_overlay_display->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
switch (message) { }
case AppletMessage::DetectShortPressingHomeButton: if (m_application) {
return applet.home_button_short_pressed_blocked; std::scoped_lock lk_application{m_application->lock};
case AppletMessage::DetectLongPressingHomeButton: m_application->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
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_event_observer) { if (m_event_observer) {
m_event_observer->RequestUpdate(); m_event_observer->RequestUpdate();
} }
@@ -254,9 +192,19 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) {
case SystemButtonType::HomeButtonShortPressing: case SystemButtonType::HomeButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton); SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton);
break; 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); SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton);
break; // Force a state update after toggling overlay
if (m_event_observer) {
m_event_observer->RequestUpdate();
}
break; }
case SystemButtonType::CaptureButtonShortPressing: case SystemButtonType::CaptureButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton); SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton);
break; break;
@@ -369,8 +317,6 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
m_overlay_display = nullptr; m_overlay_display = nullptr;
} }
this->UpdateCurrentApplicationLocked();
// Finalize applet. // Finalize applet.
applet->OnProcessTerminatedLocked(); applet->OnProcessTerminatedLocked();
@@ -443,20 +389,7 @@ void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
applet->lock.lock(); applet->lock.lock();
} }
bool WindowSystem::IsOverlayOpenLocked(const Applet& overlay) const { void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking) {
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) {
// With no applet, we don't have anything to do. // With no applet, we don't have anything to do.
if (!applet) { if (!applet) {
return; return;
@@ -487,18 +420,24 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
return false; return false;
}(); }();
const bool is_overlay = applet->applet_id == AppletId::OverlayDisplay;
// Update visibility state. // Update visibility state.
const bool should_be_visible = // Overlay applets should always be visible when window_visible is true, regardless of foreground state
is_overlay ? applet->window_visible : (is_foreground && applet->window_visible); 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); 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. // Update focus state and suspension.
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible; 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); applet->UpdateSuspensionStateLocked(true);
} }
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity. // Z-index logic like in reference C# implementation (tuned for overlay extremes)
s32 z_index = Background; s32 z_index = 0;
if (is_overlay) { const bool now_foreground = inherited_foreground;
z_index = Overlay; if (applet->applet_id == AppletId::OverlayDisplay) {
} else if (inherited_foreground) { z_index = applet->overlay_in_foreground ? 100000 : -1;
z_index = is_obscured ? Foreground : ForegroundVisible; } 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); applet->display_layer_manager.SetOverlayZIndex(z_index);
// Recurse into child applets. // Recurse into child applets.
for (const auto& child_applet : applet->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 <map>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/am/am_types.h" #include "core/hle/service/am/am_types.h"
@@ -61,16 +60,11 @@ public:
void OnPowerButtonPressed(ButtonPressDuration type) {} void OnPowerButtonPressed(ButtonPressDuration type) {}
private: private:
void UpdateCurrentApplicationLocked();
void NotifyApplicationChangedIfNeeded();
void PruneTerminatedAppletsLocked(); void PruneTerminatedAppletsLocked();
bool RestartAppletProcessLocked(Applet* applet); bool RestartAppletProcessLocked(Applet* applet);
bool LockHomeMenuIntoForegroundLocked(); bool LockHomeMenuIntoForegroundLocked();
void TerminateChildAppletsLocked(Applet* applet); void TerminateChildAppletsLocked(Applet* applet);
bool IsOverlayOpenLocked(const Applet& overlay) const; void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);
bool DoesOverlayTakeInputLocked() const;
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input);
void SendButtonAppletMessageLocked(AppletMessage message); void SendButtonAppletMessageLocked(AppletMessage message);
private: private:
@@ -94,7 +88,6 @@ private:
// Applet map by aruid. // Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{}; std::map<u64, std::shared_ptr<Applet>> m_applets{};
std::optional<u64> m_pending_application_notification{};
}; };
} // namespace Service::AM } // namespace Service::AM
@@ -23,7 +23,6 @@
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/hle/service/am/am_results.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
namespace Service::AOC { namespace Service::AOC {
@@ -32,10 +31,6 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return FileSys::GetBaseTitleID(title_id) == 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) { static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content; std::vector<u64> add_on_content;
const auto& rcu = system.GetContentProvider(); const auto& rcu = system.GetContentProvider();
@@ -96,7 +91,7 @@ IAddOnContentManager::~IAddOnContentManager() {
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) { Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid); 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]; const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { 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, LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id.pid); process_id.pid);
const auto current = GetCallerBaseTitleID(system, process_id); const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
std::vector<u32> out; std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current]; 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)); *out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end()); std::rotate(out.begin(), out.begin() + offset, out.end());
@@ -145,7 +141,7 @@ Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
ClientProcessId process_id) { ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid); 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(), const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()}; system.GetContentProvider()};
+7 -5
View File
@@ -24,8 +24,8 @@ static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
return out; return out;
} }
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_) IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
: ServiceFramework{system_, "IBcatService"}, backend{backend_}, program_id{program_id_}, : ServiceFramework{system_, "IBcatService"}, backend{backend_},
progress{{ progress{{
ProgressServiceBackend{system_, "Normal"}, ProgressServiceBackend{system_, "Normal"},
ProgressServiceBackend{system_, "Directory"}, ProgressServiceBackend{system_, "Directory"},
@@ -70,7 +70,8 @@ Result IBcatService::RequestSyncDeliveryCache(
LOG_DEBUG(Service_BCAT, "called"); LOG_DEBUG(Service_BCAT, "called");
auto& progress_backend{GetProgressBackend(SyncType::Normal)}; 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)); GetProgressBackend(SyncType::Normal));
*out_interface = std::make_shared<IDeliveryCacheProgressService>( *out_interface = std::make_shared<IDeliveryCacheProgressService>(
@@ -85,8 +86,9 @@ Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
LOG_DEBUG(Service_BCAT, "called, name={}", name); LOG_DEBUG(Service_BCAT, "called, name={}", name);
auto& progress_backend{GetProgressBackend(SyncType::Directory)}; auto& progress_backend{GetProgressBackend(SyncType::Directory)};
backend.SynchronizeDirectory(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())}, backend.SynchronizeDirectory(system.Kernel(), {system.GetApplicationProcessProgramID(),
name, progress_backend); GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, progress_backend);
*out_interface = std::make_shared<IDeliveryCacheProgressService>( *out_interface = std::make_shared<IDeliveryCacheProgressService>(
system, progress_backend.GetEvent(), progress_backend.GetImpl()); 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-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@@ -22,7 +19,7 @@ class IDeliveryCacheProgressService;
class IBcatService final : public ServiceFramework<IBcatService> { class IBcatService final : public ServiceFramework<IBcatService> {
public: public:
explicit IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_); explicit IBcatService(Core::System& system_, BcatBackend& backend_);
~IBcatService() override; ~IBcatService() override;
private: private:
@@ -42,7 +39,6 @@ private:
const ProgressServiceBackend& GetProgressBackend(SyncType type) const; const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
BcatBackend& backend; BcatBackend& backend;
u64 program_id;
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress; 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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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/bcat_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h" #include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/bcat/service_creator.h" #include "core/hle/service/bcat/service_creator.h"
@@ -41,8 +37,7 @@ IServiceCreator::~IServiceCreator() = default;
Result IServiceCreator::CreateBcatService(ClientProcessId process_id, Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
OutInterface<IBcatService> out_interface) { OutInterface<IBcatService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid); LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
*out_interface = *out_interface = std::make_shared<IBcatService>(system, *backend);
std::make_shared<IBcatService>(system, *backend, system.ResolveCallerProgramId(*process_id));
R_SUCCEED(); R_SUCCEED();
} }
@@ -50,7 +45,7 @@ Result IServiceCreator::CreateDeliveryCacheStorageService(
ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) { ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid); 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 = *out_interface =
std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id)); std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
R_SUCCEED(); 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); return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
} }
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) {
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: ??? R_UNLESS(!image_data.empty(), ResultUnknown); //TODO: ???
const u64 title_id = system.ResolveCallerProgramId(aruid); const u64 title_id = system.GetApplicationProcessProgramID();
auto static_service = auto static_service =
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 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->FlipVerticallyOnWrite(invert_y);
manager->SaveScreenShot(entry, attribute, report_option, image_data, {}); manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
}, },
layout, layout);
Nvnflinger::LayerStackId::Screenshot);
} }
} // namespace Service::Capture } // namespace Service::Capture
@@ -14,7 +14,6 @@
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/bis_factory.h" #include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.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/control_metadata.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
@@ -340,7 +339,7 @@ Result FileSystemController::RegisterProcess(
registrations.emplace(process_id, Registration{ registrations.emplace(process_id, Registration{
.program_id = program_id, .program_id = program_id,
.romfs_factory = std::move(romfs_factory), .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); LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
@@ -18,7 +18,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h" #include "core/file_sys/fs_directory.h"
@@ -314,7 +313,7 @@ Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSyste
FileSys::ResultInvalidArgument); FileSys::ResultInvalidArgument);
if (attribute.program_id == 0) { if (attribute.program_id == 0) {
attribute.program_id = FileSys::GetBaseTitleID(program_id); attribute.program_id = program_id;
} }
FileSys::VirtualDir dir{}; FileSys::VirtualDir dir{};
+1 -1
View File
@@ -1164,7 +1164,7 @@ Result IHidServer::InitializeSevenSixAxisSensor(ClientAppletResourceUserId aruid
GetResourceManager()->GetConsoleSixAxis()->Activate(); GetResourceManager()->GetConsoleSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->Activate(); GetResourceManager()->GetSevenSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress(), t_mem_1->GetOwner()); GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
R_SUCCEED(); 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; auto& device = devices[device_index.value()].device;
device->SetPollingMode(polling_mode); device->SetPollingMode(polling_mode);
device->SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner()); device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
R_SUCCEED(); 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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -150,7 +147,7 @@ Result IRS::RunImageTransferProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device); MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle); auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config); 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, npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR); Common::Input::PollingMode::IR);
@@ -298,8 +295,7 @@ Result IRS::RunImageTransferExProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device); MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle); auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config); image_transfer_processor.SetConfig(processor_config);
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(), image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
t_mem->GetOwner());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR); Common::Input::PollingMode::IR);
+1 -1
View File
@@ -35,7 +35,7 @@ public:
, process{kernel, process_} , process{kernel, process_}
, user_rx{std::move(user_rx_)} , user_rx{std::move(user_rx_)}
, user_ro{std::move(user_ro_)} , user_ro{std::move(user_ro_)}
, context{process_->GetMemory()} , context{system_.ApplicationMemory()}
{ {
// clang-format off // clang-format off
@@ -9,12 +9,15 @@
#include <optional> #include <optional>
#include <string> #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 "common/settings.h"
#include "core/file_sys/control_metadata.h" #include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs/vfs.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/kernel/k_transfer_memory.h"
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
@@ -333,8 +336,8 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
constexpr s32 data_offset = 0; constexpr s32 data_offset = 0;
if (t_mem != nullptr && t_mem->GetOwner() != nullptr && app_count > 0) { if (t_mem != nullptr && app_count > 0) {
auto& memory = t_mem->GetOwner()->GetMemory(); auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress(); const auto t_mem_address = t_mem->GetSourceAddress();
for (size_t i = 0; i < app_count; ++i) { 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, .transform_flags = layer.transform,
.crop_rect = layer.crop_rect, .crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending), .blending = ConvertBlending(layer.blending),
.layer_stack_mask = layer.layer_stack_mask,
}); });
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) { 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: case 0x3:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output); return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
case 0x8: case 0x8:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, false); return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
case 0x9: case 0x9:
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output); return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
case 0xb: case 0xb:
@@ -83,7 +83,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x1a: case 0x1a:
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd); return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd);
case 0x1b: case 0x1b:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, true); return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
case 0x1d: case 0x1d:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output); return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
default: default:
@@ -387,19 +387,8 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
return NvResult::Success; 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, NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd, std::span<Tegra::CommandListHeader> commands, bool kickoff) {
bool kickoff) {
if (params.num_entries > commands.size()) { if (params.num_entries > commands.size()) {
UNIMPLEMENTED(); UNIMPLEMENTED();
return NvResult::InvalidSize; return NvResult::InvalidSize;
@@ -407,7 +396,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
Tegra::CommandList entries(params.num_entries); Tegra::CommandList entries(params.num_entries);
if (kickoff) { 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)); params.num_entries * sizeof(Tegra::CommandListHeader));
} else { } else {
std::memcpy(entries.command_lists.data(), commands.data(), std::memcpy(entries.command_lists.data(), commands.data(),
@@ -16,10 +16,6 @@
#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdata.h"
#include "video_core/dma_pusher.h" #include "video_core/dma_pusher.h"
namespace Core::Memory {
class Memory;
}
namespace Tegra { namespace Tegra {
namespace Control { namespace Control {
struct ChannelState; struct ChannelState;
@@ -200,11 +196,8 @@ private:
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries); NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
Core::Memory::Memory& GetSessionMemory(DeviceFD fd);
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd, std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
bool kickoff = false);
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
std::span<const Tegra::CommandListHeader> commands); std::span<const Tegra::CommandListHeader> commands);
@@ -8,7 +8,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging.h" #include "common/logging.h"
#include "core/core.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/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.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) { void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started"); LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id; 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); host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
} }
void nvhost_nvdec::OnClose(DeviceFD fd) { void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec); host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd); auto it = sessions.find(fd);
if (it != sessions.end()) { 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); 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 server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>(system); auto module = std::make_shared<Module>(system);
server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv")); server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv"));
server_manager->RegisterNamedService("nvdrv:a", std::make_shared<NVDRV>(system, module, "nvdrv:a"));
const auto NvdrvInterfaceFactoryForApplets = [&, module] {
return std::make_shared<NVDRV>(system, module, "nvdrv:a");
};
server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets);
server_manager->RegisterNamedService("nvdrv:s", std::make_shared<NVDRV>(system, module, "nvdrv:s")); 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("nvdrv:t", std::make_shared<NVDRV>(system, module, "nvdrv:t"));
server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -15,8 +15,7 @@ struct Layer {
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_, explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
s32 consumer_id_) s32 consumer_id_)
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(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), blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {}
layer_stack_mask(DefaultLayerStackMask) {}
~Layer() { ~Layer() {
buffer_item_consumer->Abandon(); buffer_item_consumer->Abandon();
} }
@@ -27,7 +26,6 @@ struct Layer {
bool visible; bool visible;
s32 z_index; s32 z_index;
bool is_overlay; bool is_overlay;
u32 layer_stack_mask;
}; };
struct LayerStack { struct LayerStack {
@@ -115,7 +115,6 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
.transform = static_cast<android::BufferTransformFlags>(item.transform), .transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop, .crop_rect = item.crop,
.acquire_fence = item.fence, .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-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@@ -26,25 +23,6 @@ enum class LayerBlending : u32 {
Coverage = 0x405, 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 { struct HwcLayer {
u32 buffer_handle; u32 buffer_handle;
u32 offset; u32 offset;
@@ -57,7 +35,6 @@ struct HwcLayer {
android::BufferTransformFlags transform; android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect; Common::Rectangle<int> crop_rect;
android::Fence acquire_fence; android::Fence acquire_fence;
u32 layer_stack_mask;
}; };
} // namespace Service::Nvnflinger } // 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // 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) { void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) {
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) { if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->is_overlay = is_overlay; 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -48,7 +48,6 @@ public:
void SetLayerVisibility(s32 consumer_binder_id, bool visible); void SetLayerVisibility(s32 consumer_binder_id, bool visible);
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending); void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay); 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); 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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -13,10 +13,8 @@
namespace Service::PCTL { namespace Service::PCTL {
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_, IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
u64 program_id_)
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_}, : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
program_id{program_id_},
service_context{system_, "IParentalControlService"}, synchronization_event{service_context}, service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
unlinked_event{service_context}, request_suspension_event{service_context} { unlinked_event{service_context}, request_suspension_event{service_context} {
// clang-format off // clang-format off
@@ -204,6 +202,7 @@ Result IParentalControlService::Initialize() {
// TODO(ogniK): Recovery flag initialization for pctl:r // TODO(ogniK): Recovery flag initialization for pctl:r
const auto program_id = system.GetApplicationProcessProgramID();
if (program_id != 0) { if (program_id != 0) {
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
system.GetContentProvider()}; system.GetContentProvider()};

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