Compare commits

..

1 Commits

Author SHA1 Message Date
CamilleLaVey 110af5d4ae [vulkan, qcom] Removal of color write enable feature on QCOM driver 2026-08-25 17:03:07 -04:00
144 changed files with 638 additions and 2003 deletions
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,6 +24,6 @@ object SettingsFile {
fun loadCustomConfig(game: Game) {
val fileName = FileUtil.getFilename(Uri.parse(game.path))
NativeConfig.initializePerGameConfig(game.applicationId, fileName)
NativeConfig.initializePerGameConfig(game.programId, fileName)
}
}
@@ -189,7 +189,7 @@ class AddonsFragment : Fragment() {
fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel,
documents = documents,
programId = args.game.applicationId
programId = args.game.programId
)
}
@@ -347,7 +347,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
try {
if (GpuDriverHelper.isAdrenoGpu()) {
val programIdHex = game!!.applicationIdHex
val programIdHex = game!!.programIdHex
if (NativeFreedrenoConfig.loadPerGameConfigWithGlobalFallback(programIdHex)) {
Log.info("[EmulationFragment] Loaded per-game Freedreno config for $programIdHex")
} else {
@@ -59,7 +59,7 @@ class FreedrenoSettingsFragment : Fragment() {
NativeFreedrenoConfig.initializeFreedrenoConfig()
if (isPerGameConfig) {
NativeFreedrenoConfig.loadPerGameConfig(game!!.applicationIdHex)
NativeFreedrenoConfig.loadPerGameConfig(game!!.programIdHex)
} else {
NativeFreedrenoConfig.reloadFreedrenoConfig()
}
@@ -157,7 +157,7 @@ class FreedrenoSettingsFragment : Fragment() {
binding.buttonSave.setOnClickListener {
if (isPerGameConfig) {
NativeFreedrenoConfig.savePerGameConfig(game!!.applicationIdHex)
NativeFreedrenoConfig.savePerGameConfig(game!!.programIdHex)
showSnackbar(getString(R.string.freedreno_per_game_saved))
} else {
NativeFreedrenoConfig.saveFreedrenoConfig()
@@ -455,7 +455,7 @@ class GamePropertiesFragment : Fragment() {
val shaderCacheDir = File(
DirectoryInitialization.userDirectory +
"/cache/shader/" + args.game.shaderCacheName.lowercase()
"/cache/shader/" + args.game.settingsName.lowercase()
)
if (shaderCacheDir.exists()) {
add(
@@ -600,7 +600,7 @@ class GamePropertiesFragment : Fragment() {
val files = cacheSaveDir.listFiles()
var savesFolderFile: File? = null
if (files != null) {
val savesFolderName = args.game.applicationIdHex
val savesFolderName = args.game.programIdHex
for (file in files) {
if (file.isDirectory && file.name == savesFolderName) {
savesFolderFile = file
@@ -232,7 +232,7 @@ class InstallableFragment : Fragment() {
fragmentManager = parentFragmentManager,
addonViewModel = addonViewModel,
documents = documents,
programId = addonViewModel.game?.applicationId
programId = addonViewModel.game?.programId
)
}
@@ -142,11 +142,10 @@ class AddonViewModel : ViewModel() {
}
fun onDeleteAddon(patch: Patch) {
val currentGame = game ?: return
when (PatchType.from(patch.type)) {
PatchType.Update -> NativeLibrary.removeUpdate(currentGame.programId)
PatchType.DLC -> NativeLibrary.removeDLC(currentGame.applicationId)
PatchType.Mod -> NativeLibrary.removeMod(currentGame.programId, patch.name)
PatchType.Update -> NativeLibrary.removeUpdate(patch.programId)
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
refreshAddons(force = true)
}
@@ -166,7 +165,7 @@ class AddonViewModel : ViewModel() {
}
NativeConfig.setDisabledAddons(
currentGame.applicationId,
currentGame.programId,
currentList.mapNotNull {
if (it.enabled) {
null
@@ -200,6 +199,6 @@ class AddonViewModel : ViewModel() {
}
private fun gameKey(game: Game): String {
return "${game.applicationId}|${game.path}"
return "${game.programId}|${game.path}"
}
}
@@ -150,7 +150,7 @@ class DriverViewModel : ViewModel() {
?: return@withContext
val shaderDir = File(
externalFilesDir.absolutePath +
"/shader/" + game.shaderCacheName.lowercase()
"/shader/" + game.settingsName.lowercase()
)
if (shaderDir.exists()) {
shaderDir.deleteRecursively()
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -35,46 +35,23 @@ class Game(
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${path}_LastPlayed"
private val programIdLong: Long
get() = programId.toLongOrNull() ?: 0L
private val applicationIdLong: Long
get() = programIdLong and -8192L
val applicationId: String
get() = applicationIdLong.toString()
val settingsName: String
get() {
return if (applicationIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + applicationIdLong.toString(16).uppercase()
}
}
val programIdHex: String
get() {
val programIdLong = programId.toLong()
return if (programIdLong == 0L) {
"0"
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + programIdLong.toString(16).uppercase()
}
}
val shaderCacheName: String
get() = if (programIdLong == 0L) {
FileUtil.getFilename(Uri.parse(path))
} else {
"0" + programIdLong.toString(16).uppercase()
}
val applicationIdHex: String
val programIdHex: String
get() {
return if (applicationIdLong == 0L) {
val programIdLong = programId.toLong()
return if (programIdLong == 0L) {
"0"
} else {
"0" + applicationIdLong.toString(16).uppercase()
"0" + programIdLong.toString(16).uppercase()
}
}
@@ -84,10 +61,10 @@ class Game(
}.zip"
val saveDir: String
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(applicationId)
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(programId)
val addonDir: String
get() = DirectoryInitialization.userDirectory + "/load/" + applicationIdHex + "/"
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
val launchIntent: Intent
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -65,7 +65,7 @@ object CustomSettingsHandler {
// Initialize per-game config
try {
val fileName = FileUtil.getFilename(Uri.parse(game.path))
NativeConfig.initializePerGameConfig(game.applicationId, fileName)
NativeConfig.initializePerGameConfig(game.programId, fileName)
Log.info("[CustomSettingsHandler] Successfully applied custom settings")
return game
} catch (e: Exception) {
@@ -333,20 +333,20 @@ object CustomSettingsHandler {
*/
fun findGameByTitleId(titleId: String, context: Context): Game? {
Log.info("[CustomSettingsHandler] Searching for game with title ID: $titleId")
// Convert the program ID to the application ID used by per-game settings.
val applicationIdLong = try {
titleId.toLong(16) and -8192L
// Convert hex title ID to decimal for comparison with programId
val programIdDecimal = try {
titleId.toLong(16).toString()
} catch (e: NumberFormatException) {
Log.error("[CustomSettingsHandler] Invalid title ID format: $titleId")
return null
}
val applicationIdDecimal = applicationIdLong.toString()
// Expected hex format with "0" prefix
val expectedHex = "0${applicationIdLong.toString(16).uppercase()}"
val expectedHex = "0${titleId.uppercase()}"
// First check cached games for fast lookup
GameHelper.cachedGameList.find { game ->
game.applicationId == applicationIdDecimal || game.applicationIdHex.equals(expectedHex, ignoreCase = true)
game.programId == programIdDecimal ||
game.programIdHex.equals(expectedHex, ignoreCase = true)
}?.let { foundGame ->
Log.info("[CustomSettingsHandler] Found game in cache: ${foundGame.title}")
return foundGame
@@ -355,7 +355,8 @@ object CustomSettingsHandler {
Log.info("[CustomSettingsHandler] Game not in cache, scanning full library...")
val allGames = GameHelper.getGames()
val foundGame = allGames.find { game ->
game.applicationId == applicationIdDecimal || game.applicationIdHex.equals(expectedHex, ignoreCase = true)
game.programId == programIdDecimal ||
game.programIdHex.equals(expectedHex, ignoreCase = true)
}
if (foundGame != null) {
Log.info("[CustomSettingsHandler] Found game: ${foundGame.title} at ${foundGame.path}")
@@ -170,12 +170,12 @@ object GameHelper {
val game = getGame(it.uri, true, false)
if (game != null) {
games.add(game)
if (game.applicationId != "0") {
gamesByProgramId[game.applicationId] = game
if (game.programId != "0") {
gamesByProgramId[game.programId] = game
}
} else if (mountedContainer) {
GameMetadata.getProgramId(filePath).toLongOrNull()?.let { programId ->
gamesByProgramId[(programId and -8192L).toString()]
gamesByProgramId[(programId and 0x800L.inv()).toString()]
}?.let { existingGame ->
NativeLibrary.getPatchesForFile(existingGame.path, existingGame.programId)
existingGame.version = GameMetadata.getVersion(
+11 -67
View File
@@ -76,7 +76,6 @@ extern "C" {
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "common/android/applets/web_browser.h"
#include "core/file_sys/common_funcs.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -312,23 +311,11 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
ConfigureFilesystemProvider(filepath);
// Load the ROM.
const u64 previous_program_id =
program_index != 0 && m_next_program_id.load() >
static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)
? m_next_program_id.load()
: 0;
Service::AM::FrontendAppletParameters params{
.program_id = previous_program_id,
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
: Service::AM::LaunchType::ApplicationInitiated,
.program_index = static_cast<s32>(program_index),
.previous_program_index =
previous_program_id != 0
? static_cast<s32>(previous_program_id -
FileSys::GetBaseTitleID(previous_program_id))
: -1,
};
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
@@ -341,12 +328,8 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
m_system.GetCpuManager().OnGpuReady();
m_system.RegisterExitCallback([&] { HaltEmulation(); });
m_system.RegisterApplicationChangedCallback(
[&](u64 changed_program_id) { RequestDiskShaderCacheReload(changed_program_id); });
// Register an ExecuteProgram callback such that Core can execute a sub-program
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
m_next_program_id = m_system.GetApplicationProcessProgramID();
m_next_program_index = program_index_;
EmulationSession::GetInstance().HaltEmulation();
});
@@ -424,58 +407,20 @@ void EmulationSession::RunEmulation() {
}
while (true) {
std::optional<u64> reload_title;
{
[[maybe_unused]] std::unique_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800), [&]() {
return !m_is_running || m_pending_shader_cache_title.has_value();
})) {
if (!m_is_running) {
break;
}
reload_title = std::exchange(m_pending_shader_cache_title, std::nullopt);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
[&]() { return !m_is_running; })) {
// Emulation halted.
break;
}
}
if (reload_title.has_value())
ReloadDiskShaderCache(*reload_title);
}
// Reset current applet ID.
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
}
void EmulationSession::RequestDiskShaderCacheReload(u64 program_id) {
{
std::scoped_lock lock(m_mutex);
m_pending_shader_cache_title = program_id;
}
m_cv.notify_one();
}
void EmulationSession::ReloadDiskShaderCache(u64 program_id) {
if (!Settings::values.use_disk_shader_cache.GetValue())
return;
LOG_INFO(Frontend, "Reloading disk shader cache for {:016X}", program_id);
const bool was_paused = m_is_paused;
m_system.Pause();
m_system.GPU().WaitForIdle();
m_system.GPU().ObtainContext();
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
m_system.Renderer().ReadRasterizer()->LoadDiskResources(program_id, std::stop_token{},
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
m_system.GPU().ReleaseContext();
if (!was_paused)
m_system.Run();
}
Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard;
}
@@ -788,7 +733,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId,
jstring jupdatePath) {
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
@@ -796,7 +741,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
if (update_id == program_id) {
return true;
}
@@ -1491,7 +1436,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclas
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_gameRequiresFirmware(JNIEnv* env, jclass clazz, jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
return FirmwareManager::GameRequiresFirmware(program_id);
}
@@ -1575,21 +1520,20 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(
EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
jstring jname) {
const auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, Common::Android::GetJString(env, jname));
}
@@ -1636,7 +1580,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) {
return Common::Android::ToJString(env, "");
}
-6
View File
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <optional>
#include <android/native_window_jni.h>
#include "common/android/applets/software_keyboard.h"
#include "core/core.h"
@@ -46,7 +44,6 @@ public:
void HaltEmulation();
void RunEmulation();
void ShutdownEmulation();
void RequestDiskShaderCacheReload(u64 program_id);
const Core::PerfStatsResults& PerfStats();
int ShadersBuilding();
@@ -68,7 +65,6 @@ private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
static void OnEmulationStopped(Core::SystemResultStatus result);
static void ChangeProgram(std::size_t program_index);
void ReloadDiskShaderCache(u64 program_id);
private:
// Window management
@@ -87,7 +83,6 @@ private:
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1};
std::optional<u64> m_pending_shader_cache_title;
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
@@ -98,5 +93,4 @@ private:
// Program index for next boot
std::atomic<s32> m_next_program_index = -1;
std::atomic<u64> m_next_program_id = 0;
};
@@ -12,7 +12,6 @@
#include "common/fs/path_util.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/file_sys/common_funcs.h"
#include "frontend_common/config.h"
#include "frontend_common/settings_generator.h"
#include "native.h"
@@ -57,7 +56,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jo
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv* env, jobject obj,
jstring jprogramId,
jstring jfileName) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto file_name = Common::Android::GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config =
@@ -323,7 +322,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(),
@@ -338,7 +337,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId,
jobjectArray jdisabledAddons) {
const auto program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
Settings::values.disabled_addons[program_id].clear();
std::vector<std::string> disabled_addons;
const int size = env->GetArrayLength(jdisabledAddons);
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,12 +7,13 @@
namespace AudioCore::ADSP::OpusDecoder {
namespace {
constexpr u32 OpusStreamCountMax = 255;
bool IsValidChannelCount(u32 channel_count) {
return channel_count == 1 || channel_count == 2;
}
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax &&
static_cast<s32>(stereo_stream_count) >= 0 &&
stereo_stream_count <= total_stream_count;
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
}
} // namespace
+1 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -108,7 +105,7 @@ Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 chan
shared_memory.host_send_data[4] = total_stream_count;
shared_memory.host_send_data[5] = stereo_stream_count;
ASSERT(channel_count <= shared_memory.channel_mapping.size());
ASSERT(channel_count <= MaxChannels);
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
opus_decoder.Send(ADSP::Direction::DSP,
+27 -28
View File
@@ -19,23 +19,6 @@
namespace AudioCore::Sink {
namespace {
[[nodiscard]] bool InitializeAudio() {
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
// See https://github.com/PCSX2/pcsx2/pull/12312
// "SDL and cubeb backends previously resulted in different names for the output which
// caused them be identified as different applications by the OS."
//
// Keep in sync with cubeb_sink.cpp name.
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return false;
}
}
return true;
}
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
int device_count = 0;
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -221,14 +204,20 @@ private:
};
SDLSink::SDLSink(std::string_view target_device_name) {
if (InitializeAudio()) {
if (target_device_name != auto_device_name && !target_device_name.empty()) {
output_device = target_device_name;
} else {
output_device.clear();
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return;
}
device_channels = 2;
}
if (target_device_name != auto_device_name && !target_device_name.empty()) {
output_device = target_device_name;
} else {
output_device.clear();
}
device_channels = 2;
}
SDLSink::~SDLSink() = default;
@@ -276,10 +265,15 @@ void SDLSink::SetSystemVolume(f32 volume) {
}
std::vector<std::string> ListSDLSinkDevices(bool capture) {
if (!InitializeAudio())
return {}; //no devices
std::vector<std::string> device_list;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return {};
}
}
int device_count = 0;
SDL_AudioDeviceID* devices =
capture ? SDL_GetAudioRecordingDevices(&device_count)
@@ -310,8 +304,13 @@ bool IsSDLSuitable() {
return false;
#else
// Check SDL can init
if (!InitializeAudio()!
return false;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
SDL_GetError());
return false;
}
}
// We can set any latency frequency we want with SDL, so no need to check that.
+4 -4
View File
@@ -224,7 +224,7 @@ struct ColorConsoleBackend final : public Backend {
auto const df = GetDirectFormatArgs(entry);
// more restrictive, because take for example this simple prelude:
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
char buffer[256];
char buffer[128];
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);
@@ -425,14 +425,14 @@ void SetColorConsoleBackendEnabled(bool enabled) {
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
auto const flush = ::Settings::values.log_flush_line.GetValue();
char buffer[BUFSIZ];
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
buffer[(std::min)(result.size, sizeof(buffer) - 1)] = '\0';
buffer[result.size] = '\0';
auto const flush = ::Settings::values.log_flush_line.GetValue();
logging_instance->ForEachBackend([=](Backend& backend) {
backend.Write(Entry{
.message = buffer,
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
.message_len = (std::min)(sizeof(buffer) - 1, result.size),
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
.log_class = log_class,
.log_level = log_level,
+4 -2
View File
@@ -132,9 +132,11 @@ void LogSettings() {
}
}
}
LOG_INFO(Config, "Eden Configuration:");
std::string settings_str{};
for (auto const& e : settings_list)
LOG_INFO(Config, "{}", e);
settings_str += e;
LOG_INFO(Config, "Eden Configuration:\n{}", settings_str);
#define LOG_PATH(NAME) \
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
LOG_PATH(CacheDir);
+2
View File
@@ -7,4 +7,6 @@
#define STB_IMAGE_IMPLEMENTATION 1
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#define STBI_ONLY_JPEG 1
#include "common/stb.h"
-1
View File
@@ -7,7 +7,6 @@
#pragma once
#define STBI_ONLY_JPEG 1
#define STBI_WRITE_NO_STDIO 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
+9 -79
View File
@@ -4,7 +4,6 @@
#include <array>
#include <atomic>
#include <memory>
#include <unordered_map>
#include <utility>
#include "game_settings.h"
@@ -17,7 +16,6 @@
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "launch_timestamp_cache.h"
#include "core/core_timing.h"
@@ -250,30 +248,12 @@ struct System::Impl {
}
}
void NotifyNVDECChannelOpen(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
++nvdec_active_channels[process_id];
}
void NotifyNVDECChannelClose(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
const auto it = nvdec_active_channels.find(process_id);
if (it == nvdec_active_channels.end()) {
return;
}
if (--it->second == 0) {
nvdec_active_channels.erase(it);
}
void SetNVDECActive(bool is_nvdec_active) {
nvdec_active = is_nvdec_active;
}
bool GetNVDECActive() {
std::scoped_lock lock{nvdec_active_mutex};
return !nvdec_active_channels.empty();
}
bool IsNVDECActiveForProcess(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
return nvdec_active_channels.contains(process_id);
return nvdec_active;
}
void InitializeDebugger(System& system, u16 port) {
@@ -315,10 +295,6 @@ struct System::Impl {
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) {
InitializeKernel(system);
if (params.applet_type == Service::AM::AppletType::Application) {
current_application_filepath = filepath;
}
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
// Create the application process
@@ -354,7 +330,7 @@ struct System::Impl {
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
// Make the process created be the application
kernel.SetApplicationProcess(process->GetHandle());
kernel.MakeApplicationProcess(process->GetHandle());
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
@@ -397,7 +373,7 @@ struct System::Impl {
LOG_ERROR(Core, "Failed to find program id for ROM");
}
GameSettings::LoadOverrides(FileSys::GetBaseTitleID(program_id), gpu_core->Renderer());
GameSettings::LoadOverrides(program_id, gpu_core->Renderer());
if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info;
game_info.name = name;
@@ -491,7 +467,6 @@ struct System::Impl {
Core::SpeedLimiter speed_limiter;
ExecuteProgramCallback execute_program_callback;
ExitCallback exit_callback;
ApplicationChangedCallback application_changed_callback;
std::optional<Service::Services> services;
std::optional<Core::Debugger> debugger;
@@ -513,8 +488,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<u8, 0x20> build_id{};
std::string current_application_filepath;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
/// ContentProviderUnion instance
@@ -525,8 +498,6 @@ struct System::Impl {
mutable std::mutex suspend_guard;
std::mutex general_channel_mutex;
std::mutex nvdec_active_mutex;
std::unordered_map<u64, u32> nvdec_active_channels;
std::atomic_bool is_paused{};
std::atomic_bool is_shutting_down{};
std::atomic_bool is_powered_on{};
@@ -534,6 +505,7 @@ struct System::Impl {
bool extended_memory_layout : 1 = false;
bool exit_locked : 1 = false;
bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;
void EnsureGeneralChannelInitialized(System& system) {
if (!general_channel_event) {
@@ -597,22 +569,14 @@ void System::UnstallApplication() {
impl->UnstallApplication();
}
void System::NotifyNVDECChannelOpen(u64 process_id) {
impl->NotifyNVDECChannelOpen(process_id);
}
void System::NotifyNVDECChannelClose(u64 process_id) {
impl->NotifyNVDECChannelClose(process_id);
void System::SetNVDECActive(bool is_nvdec_active) {
impl->SetNVDECActive(is_nvdec_active);
}
bool System::GetNVDECActive() {
return impl->GetNVDECActive();
}
bool System::IsNVDECActiveForProcess(u64 process_id) {
return impl->IsNVDECActiveForProcess(process_id);
}
void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
}
@@ -763,25 +727,7 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
}
u64 System::GetApplicationProcessProgramID() const {
const auto* const process = impl->kernel.ApplicationProcess();
return process != nullptr ? process->GetProgramId() : 0;
}
u64 System::GetProgramIdForProcessId(u64 process_id) const {
auto process = impl->kernel.GetProcessByProcessId(process_id);
return process.IsNull() ? 0 : process->GetProgramId();
}
u64 System::ResolveCallerProgramId(u64 process_id) const {
if (const auto program_id = this->GetProgramIdForProcessId(process_id); program_id != 0) {
return program_id;
}
const auto fallback = this->GetApplicationProcessProgramID();
LOG_WARNING(Core,
"Could not resolve caller process_id={}, falling back to application {:016X}",
process_id, fallback);
return fallback;
return impl->kernel.ApplicationProcess()->GetProgramId();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -964,10 +910,6 @@ void System::ExecuteProgram(std::size_t program_index) {
}
}
const std::string& System::GetCurrentApplicationFilePath() const {
return impl->current_application_filepath;
}
/// @brief Gets a reference to the user channel stack.
/// It is used to transfer data between programs.
std::vector<std::vector<u8>>& System::GetUserChannel() {
@@ -1019,18 +961,6 @@ void System::Exit() {
}
}
void System::RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback) {
impl->application_changed_callback = std::move(callback);
}
void System::NotifyApplicationChanged(u64 program_id) {
//LOG_DEBUG(Core, "Running application changed to {:016X}", program_id);
if (impl->application_changed_callback) {
impl->application_changed_callback(program_id);
}
}
void System::ApplySettings() {
impl->RefreshTime(*this);
+1 -12
View File
@@ -191,10 +191,8 @@ public:
std::unique_lock<std::mutex> StallApplication();
void UnstallApplication();
void NotifyNVDECChannelOpen(u64 process_id);
void NotifyNVDECChannelClose(u64 process_id);
void SetNVDECActive(bool is_nvdec_active);
[[nodiscard]] bool GetNVDECActive();
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
/**
* Initialize the debugger.
@@ -324,10 +322,6 @@ public:
[[nodiscard]] u64 GetApplicationProcessProgramID() const;
[[nodiscard]] u64 GetProgramIdForProcessId(u64 process_id) const;
[[nodiscard]] u64 ResolveCallerProgramId(u64 process_id) const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
@@ -428,7 +422,6 @@ public:
void PushGeneralChannelData(std::vector<u8>&& data);
bool TryPopGeneralChannel(std::vector<u8>& out_data);
[[nodiscard]] Service::Event& GetGeneralChannelEvent();
[[nodiscard]] const std::string& GetCurrentApplicationFilePath() const;
/// Type used for the frontend to designate a callback for System to exit the application.
using ExitCallback = std::function<void()>;
@@ -442,10 +435,6 @@ public:
/// Instructs the frontend to exit the application.
void Exit();
using ApplicationChangedCallback = std::function<void(u64 program_id)>;
void RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback);
void NotifyApplicationChanged(u64 program_id);
/// Applies any changes to settings to this core instance.
void ApplySettings();
+2 -2
View File
@@ -29,7 +29,7 @@ static u8 MasterKeyIdForKeyGeneration(u8 key_generation) {
return std::max<u8>(key_generation, 1) - 1;
}
NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
NCA::NCA(VirtualFile file_, const NCA* base_nca)
: file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile;
@@ -110,7 +110,7 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
}
}
if (is_update && base_nca == nullptr && !allow_missing_base) {
if (is_update && base_nca == nullptr) {
status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
} else {
status = Loader::ResultStatus::Success;
+1 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -66,7 +63,7 @@ inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) {
// After construction, use GetStatus to determine if the file is valid and ready to be used.
class NCA : public ReadOnlyVfsDirectory {
public:
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr, bool allow_missing_base = false);
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr);
~NCA() override;
Loader::ResultStatus GetStatus() const;
@@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_indirect_storage.h"
@@ -100,18 +99,6 @@ Result IndirectStorage::GetEntryList(Entry* out_entries, s32* out_entry_count, s
R_SUCCEED();
}
void IndirectStorage::ReportMissingOriginal(s64 offset, s64 size) {
if (m_reported_missing_original) {
return;
}
m_reported_missing_original = true;
LOG_ERROR(Common_Filesystem,
"Patch storage requests {:#x} bytes at {:#x} from a base storage that is not "
"present; this data will read as garbage",
size, offset);
}
size_t IndirectStorage::Read(u8* buffer, size_t size, size_t offset) const {
// Validate pre-conditions.
ASSERT(this->IsInitialized());
@@ -85,9 +85,6 @@ public:
void SetStorage(s32 idx, VirtualFile storage) {
ASSERT(0 <= idx && idx < StorageCount);
m_data_storage[idx] = storage;
if (idx == 0) {
m_original_missing = storage == nullptr || storage->GetSize() == 0;
}
}
template <typename T>
@@ -133,9 +130,6 @@ protected:
template <bool ContinuousCheck, bool RangeCheck, typename F>
Result OperatePerEntry(s64 offset, s64 size, F func);
// Launching another game makes the original storage inaccessable.
// This is a helper for multi-nca games.
void ReportMissingOriginal(s64 offset, s64 size);
private:
struct ContinuousReadingEntry {
@@ -160,8 +154,6 @@ private:
private:
mutable BucketTree m_table;
std::array<VirtualFile, StorageCount> m_data_storage;
bool m_original_missing{false};
bool m_reported_missing_original{false};
};
template <bool ContinuousCheck, bool RangeCheck, typename F>
@@ -280,10 +272,6 @@ Result IndirectStorage::OperatePerEntry(s64 offset, s64 size, F func) {
if (needs_operate) {
const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset();
if (cur_entry.storage_index == 0 && m_original_missing) {
this->ReportMissingOriginal(cur_offset, cur_size);
}
if constexpr (RangeCheck) {
// Get the current data storage's size.
s64 cur_data_storage_size = m_data_storage[cur_entry.storage_index]->GetSize();
+2 -2
View File
@@ -48,11 +48,11 @@ struct ContentRecord {
std::array<u8, 0x10> nca_id;
std::array<u8, 0x6> size;
ContentRecordType type;
u8 id_offset;
INSERT_PADDING_BYTES(1);
};
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, 0};
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, {}};
struct MetaRecord {
u64_le title_id;
+61 -131
View File
@@ -161,7 +161,7 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
PatchManager::PatchManager(u64 title_id_,
const Service::FileSystem::FileSystemController& fs_controller_,
const ContentProvider& content_provider_)
: title_id{title_id_}, application_id{GetBaseTitleID(title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
PatchManager::~PatchManager() = default;
@@ -169,41 +169,13 @@ u64 PatchManager::GetTitleID() const {
return title_id;
}
u64 PatchManager::GetUpdateTitleIDForContent() const {
const auto program_update_id = GetUpdateTitleID(title_id);
if (program_update_id == GetUpdateTitleID(application_id) || content_provider.HasEntry(program_update_id, ContentRecordType::Program)) {
return program_update_id;
}
return GetUpdateTitleID(application_id);
}
std::vector<VirtualDir> PatchManager::GetModificationLoadRoots() const {
std::vector<VirtualDir> roots;
roots.push_back(fs_controller.GetModificationLoadRoot(title_id));
if (application_id != title_id) {
roots.push_back(fs_controller.GetModificationLoadRoot(application_id));
}
std::erase(roots, nullptr);
return roots;
}
std::vector<VirtualDir> PatchManager::GetSDMCModificationLoadRoots() const {
std::vector<VirtualDir> roots;
roots.push_back(fs_controller.GetSDMCModificationLoadRoot(title_id));
if (application_id != title_id) {
roots.push_back(fs_controller.GetSDMCModificationLoadRoot(application_id));
}
std::erase(roots, nullptr);
return roots;
}
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
if (exefs == nullptr)
return exefs;
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -211,7 +183,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
bool checked_manual = false;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
if (content_union) {
// First, check ExternalContentProvider
@@ -331,21 +303,17 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
// LayeredExeFS
const auto load_dirs = GetModificationLoadRoots();
const auto sdmc_load_dirs = GetSDMCModificationLoadRoots();
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
std::vector<VirtualDir> patch_dirs;
for (const auto& sdmc_load_dir : sdmc_load_dirs) {
patch_dirs.push_back(sdmc_load_dir);
}
for (const auto& load_dir : load_dirs) {
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
if (load_dir != nullptr) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1);
@@ -379,7 +347,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const {
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto nso_build_id = fmt::format("{:0<64}", build_id);
std::vector<VirtualFile> out;
@@ -444,20 +412,15 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso;
}
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
const auto patches = CollectPatches(patch_dirs, build_id);
auto out = nso;
@@ -492,39 +455,29 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false;
}
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
return !CollectPatches(patch_dirs, build_id).empty();
}
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
const auto load_dirs = GetModificationLoadRoots();
if (load_dirs.empty()) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {};
}
const auto& disabled = Settings::values.disabled_addons[application_id];
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(),
[](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
const auto& disabled = Settings::values.disabled_addons[title_id];
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
// <mod dir> / <folder> / cheats / <build id>.txt
std::vector<Core::Memory::CheatEntry> out;
@@ -540,52 +493,39 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
}
// Uncareless user-friendly loading of patches (must start with 'cheat_')
// <mod dir> / <cheat file>.txt
for (const auto& load_dir : load_dirs) {
for (auto const& f : load_dir->GetFiles()) {
auto const name = f->GetName();
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
std::vector<u8> data(f->GetSize());
if (f->Read(data.data(), data.size()) == data.size()) {
const Core::Memory::TextCheatParser parser;
auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
std::copy(res.begin(), res.end(), std::back_inserter(out));
} else {
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
}
for (auto const& f : load_dir->GetFiles()) {
auto const name = f->GetName();
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
std::vector<u8> data(f->GetSize());
if (f->Read(data.data(), data.size()) == data.size()) {
const Core::Memory::TextCheatParser parser;
auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
std::copy(res.begin(), res.end(), std::back_inserter(out));
} else {
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
}
}
}
return out;
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, u64 application_id, ContentRecordType type,
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
const Service::FileSystem::FileSystemController& fs_controller) {
std::vector<VirtualDir> load_dirs{fs_controller.GetModificationLoadRoot(title_id)};
std::vector<VirtualDir> sdmc_load_dirs{fs_controller.GetSDMCModificationLoadRoot(title_id)};
if (application_id != title_id) {
load_dirs.push_back(fs_controller.GetModificationLoadRoot(application_id));
sdmc_load_dirs.push_back(fs_controller.GetSDMCModificationLoadRoot(application_id));
}
std::erase(load_dirs, nullptr);
std::erase(sdmc_load_dirs, nullptr);
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
type != ContentRecordType::HtmlDocument) ||
(load_dirs.empty() && sdmc_load_dirs.empty())) {
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
return;
}
const auto& disabled = Settings::values.disabled_addons[application_id];
std::vector<VirtualDir> patch_dirs;
for (const auto& load_dir : load_dirs) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
const auto& disabled = Settings::values.disabled_addons[title_id];
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
patch_dirs.insert(patch_dirs.end(), sdmc_load_dirs.begin(), sdmc_load_dirs.end());
patch_dirs.push_back(sdmc_load_dir);
}
std::stable_sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) {
return l->GetName() < r->GetName();
});
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
std::vector<VirtualDir> layers_ext;
@@ -657,8 +597,8 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
auto romfs = base_romfs;
// Game Updates
const auto update_tid = GetUpdateTitleIDForContent();
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto update_tid = GetUpdateTitleID(title_id);
const auto& disabled = Settings::values.disabled_addons[title_id];
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -765,7 +705,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
// LayeredFS
if (apply_layeredfs) {
ApplyLayeredFS(romfs, title_id, application_id, type, fs_controller);
ApplyLayeredFS(romfs, title_id, type, fs_controller);
}
return romfs;
@@ -777,10 +717,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
std::vector<Patch> out;
const auto& disabled = Settings::values.disabled_addons[application_id];
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
std::vector<Patch> external_update_patches;
@@ -929,7 +869,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
.version = "",
.type = PatchType::Update,
.program_id = title_id,
.title_id = update_tid,
.title_id = title_id,
.source = PatchSource::Unknown,
.numeric_version = 0};
@@ -955,7 +895,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
// General Mods (LayeredFS and IPS)
for (const auto& mod_dir : GetModificationLoadRoots()) {
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
if (mod_dir != nullptr) {
for (auto const& f : mod_dir->GetFiles())
if (auto const name = f->GetName(); name.starts_with("cheat_")) {
auto const mod_disabled = std::find(disabled.begin(), disabled.end(), name) != disabled.end();
@@ -1022,7 +963,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
// SDMC mod directory (RomFS LayeredFS)
for (const auto& sdmc_mod_dir : GetSDMCModificationLoadRoots()) {
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if (sdmc_mod_dir != nullptr) {
std::string types;
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs")))
AppendCommaIfNotEmpty(types, "LayeredExeFS");
@@ -1057,10 +999,10 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
dlc_match.reserve(dlc_entries_with_origin.size());
for (const auto& [slot, entry] : dlc_entries_with_origin) {
const auto base_tid = GetBaseTitleID(entry.title_id);
const bool matches_base = base_tid == application_id;
const bool matches_base = base_tid == title_id;
if (!matches_base) {
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
entry.title_id, base_tid, application_id);
entry.title_id, base_tid, title_id);
continue;
}
@@ -1135,22 +1077,16 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
std::optional<u32> PatchManager::GetGameVersion() const {
const auto update_tid = GetUpdateTitleIDForContent();
const auto update_tid = GetUpdateTitleID(title_id);
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
return content_provider.GetEntryVersion(update_tid);
}
if (const auto version = content_provider.GetEntryVersion(title_id); version.has_value()) {
return version;
}
return content_provider.GetEntryVersion(application_id);
return content_provider.GetEntryVersion(title_id);
}
PatchManager::Metadata PatchManager::GetControlMetadata() const {
auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr && application_id != title_id) {
base_control_nca = content_provider.GetEntry(application_id, ContentRecordType::Control);
}
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr) {
return {};
}
@@ -1226,14 +1162,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr)
return metadata;
const auto update_id = FileSys::GetUpdateTitleID(application_id);
const auto application_update_id = FileSys::GetUpdateTitleID(GetBaseTitleID(application_id));
const FileSys::PatchManager pm_update{update_id, system.GetFileSystemController(), system.GetContentProvider()};
metadata = pm_update.GetControlMetadata();
if (metadata.first != nullptr || update_id == application_update_id)
return metadata;
const FileSys::PatchManager pm_application_update{application_update_id, system.GetFileSystemController(), system.GetContentProvider()};
return pm_application_update.GetControlMetadata();
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(application_id), system.GetFileSystemController(), system.GetContentProvider()};
return pm_update.GetControlMetadata();
}
} // namespace FileSys
-5
View File
@@ -10,7 +10,6 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs/vfs_types.h"
@@ -110,14 +109,10 @@ public:
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
private:
[[nodiscard]] u64 GetUpdateTitleIDForContent() const;
[[nodiscard]] std::vector<VirtualDir> GetModificationLoadRoots() const;
[[nodiscard]] std::vector<VirtualDir> GetSDMCModificationLoadRoots() const;
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const;
u64 title_id;
u64 application_id;
const Service::FileSystem::FileSystemController& fs_controller;
const ContentProvider& content_provider;
};
+5 -30
View File
@@ -567,45 +567,20 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
}
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
auto cmnt_iter = map.find(title_id);
u8 id_offset = 0;
const auto cmnt_iter = map.find(title_id);
if (cmnt_iter == map.cend()) {
const auto program_index = title_id & AOC_TITLE_ID_MASK;
if (program_index == 0) {
return std::nullopt;
}
cmnt_iter = map.find(title_id & ~AOC_TITLE_ID_MASK);
if (cmnt_iter == map.cend()) {
return std::nullopt;
}
id_offset = static_cast<u8>(program_index);
return std::nullopt;
}
const auto& cnmt = cmnt_iter->second;
const auto& content_records = cnmt.GetContentRecords();
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
[type, id_offset](const ContentRecord& rec) {
return rec.type == type && rec.id_offset == id_offset;
});
if (iter != content_records.cend()) {
return std::make_optional(iter->nca_id);
}
if (id_offset != 0) {
[type](const ContentRecord& rec) { return rec.type == type; });
if (iter == content_records.cend()) {
return std::nullopt;
}
const auto fallback_iter =
std::find_if(content_records.cbegin(), content_records.cend(),
[type](const ContentRecord& rec) { return rec.type == type; });
if (fallback_iter == content_records.cend()) {
return std::nullopt;
}
return std::make_optional(fallback_iter->nca_id);
return std::make_optional(iter->nca_id);
}
std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
+6 -8
View File
@@ -12,7 +12,6 @@
#include "common/hex_util.h"
#include "common/logging.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
@@ -66,12 +65,10 @@ u64 NSP::GetProgramTitleID() const {
}
auto program_id = expected_program_id;
if (program_id == 0 && !program_status.empty()) {
program_id = std::min_element(program_status.cbegin(), program_status.cend(),
[](const auto& lhs, const auto& rhs) {
return lhs.first < rhs.first;
})
->first;
if (program_id == 0) {
if (!program_status.empty()) {
program_id = program_status.begin()->first;
}
}
program_id = program_id + program_index;
@@ -276,7 +273,8 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
// update NCA.
if ((next_nca->GetTitleId() & AOC_TITLE_ID_MASK) != 0) {
if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
(next_nca->GetTitleId() & 0x800) == 0) {
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
std::move(next_nca);
} else {
+4 -21
View File
@@ -349,18 +349,9 @@ struct KernelCore::Impl {
object_name_global_data.emplace(kernel);
}
void SetApplicationProcess(KernelCore& kernel, KProcess* process) {
if (application_process == process)
return;
KProcess* const previous = application_process;
void MakeApplicationProcess(KernelCore& kernel, KProcess* process) {
application_process = process;
if (application_process != nullptr)
application_process->Open(kernel);
if (previous != nullptr)
previous->Close(kernel);
application_process->Open(kernel);
}
/// Sets the host thread ID for the caller.
@@ -888,8 +879,8 @@ void KernelCore::RemoveProcess(KProcess* process) {
}
}
void KernelCore::SetApplicationProcess(KProcess* process) {
impl->SetApplicationProcess(*this, process);
void KernelCore::MakeApplicationProcess(KProcess* process) {
impl->MakeApplicationProcess(*this, process);
}
KProcess* KernelCore::ApplicationProcess() {
@@ -900,14 +891,6 @@ const KProcess* KernelCore::ApplicationProcess() const {
return impl->application_process;
}
KScopedAutoObject<KProcess> KernelCore::GetProcessByProcessId(u64 process_id) {
std::scoped_lock lk{impl->process_list_lock};
for (auto* const process : impl->process_list)
if (process != nullptr && process->GetProcessId() == process_id)
return {*this, process};
return {*this, nullptr};
}
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() {
std::list<KScopedAutoObject<KProcess>> processes;
std::scoped_lock lk{impl->process_list_lock};
+2 -5
View File
@@ -124,8 +124,8 @@ public:
void AppendNewProcess(KProcess* process);
void RemoveProcess(KProcess* process);
/// Makes the given process the current application process.
void SetApplicationProcess(KProcess* process);
/// Makes the given process the new application process.
void MakeApplicationProcess(KProcess* process);
/// Retrieves a pointer to the application process.
KProcess* ApplicationProcess();
@@ -133,9 +133,6 @@ public:
/// Retrieves a const pointer to the application process.
const KProcess* ApplicationProcess() const;
/// Retrieves the process with the given process ID, or a null object.
KScopedAutoObject<KProcess> GetProcessByProcessId(u64 process_id);
/// Retrieves the list of processes.
std::list<KScopedAutoObject<KProcess>> GetProcessList();
-4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,7 +10,6 @@ namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
constexpr Result ResultApplicationRecordNotFound{ErrorModule::AM, 37};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
+1 -9
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -201,14 +201,6 @@ enum class ProgramSpecifyKind : u32 {
RestartProgram = 2,
};
// Maufeat: Use enums for zindex instead of using random zindex numbers
enum AppletZIndex : s32 {
Background = 0,
Foreground = 1,
ForegroundVisible = 2,
Overlay = 3,
};
struct CommonArguments {
CommonArgumentVersion arguments_version;
CommonArgumentSize size;
+9 -9
View File
@@ -56,22 +56,22 @@ void Applet::UpdateSuspensionStateLocked(bool force_message) {
}
}
void Applet::SetInteractibleLocked(bool pad_interactible, bool touch_interactible) {
if (is_pad_interactible == pad_interactible && is_touch_interactible == touch_interactible) {
void Applet::SetInteractibleLocked(bool interactible) {
if (is_interactible == interactible) {
return;
}
is_pad_interactible = pad_interactible;
is_touch_interactible = touch_interactible;
is_interactible = interactible;
const bool exit_requested = lifecycle_manager.GetExitRequested();
const bool pad_enabled = pad_interactible && !exit_requested;
const bool touch_enabled = touch_interactible && !exit_requested;
const bool input_enabled = interactible && !exit_requested;
LOG_DEBUG(Service_AM, "applet={} pad={} touch={} exit_requested={}",
static_cast<u32>(applet_id), pad_enabled, touch_enabled, exit_requested);
if (applet_id == AppletId::OverlayDisplay || applet_id == AppletId::Application) {
LOG_DEBUG(Service_AM, "called, applet={} interactible={} exit_requested={} input_enabled={} overlay_in_foreground={}",
static_cast<u32>(applet_id), interactible, exit_requested, input_enabled, overlay_in_foreground);
}
hid_registration.EnableAppletToGetInput(pad_enabled, touch_enabled);
hid_registration.EnableAppletToGetInput(input_enabled);
}
void Applet::OnProcessTerminatedLocked() {
+3 -5
View File
@@ -125,11 +125,9 @@ struct Applet {
bool album_image_taken_notification_enabled{};
bool record_volume_muted{};
bool is_activity_runnable{};
bool is_pad_interactible{true};
bool is_touch_interactible{true};
bool is_interactible{true};
bool window_visible{true};
bool overlay_watching_short_home_button{false};
bool overlay_handling_touch_input{false};
bool overlay_in_foreground{false};
// Events
Event overlay_event;
@@ -150,7 +148,7 @@ struct Applet {
// Process state management
void UpdateSuspensionStateLocked(bool force_message);
void SetInteractibleLocked(bool pad_interactible, bool touch_interactible);
void SetInteractibleLocked(bool interactible);
void OnProcessTerminatedLocked();
};
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -6,7 +6,6 @@
#include "core/core.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/container.h"
@@ -34,7 +33,6 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
m_system_shared_buffer_id = 0;
m_system_shared_layer_id = 0;
m_applet_id = applet_id;
m_library_applet_mode = mode;
m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
@@ -74,16 +72,14 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerStackMask(*out_layer_id,
this->GetLayerStackMask());
if (m_applet_id != AppletId::Application) {
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
if (m_applet_id == AppletId::OverlayDisplay) {
(void)m_manager_display_service->SetLayerZIndex(Overlay, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
} else {
(void)m_manager_display_service->SetLayerZIndex(Foreground, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
}
}
@@ -126,12 +122,10 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
// Ensure the overlay layer is visible
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
(void)m_display_service->GetContainer()->SetLayerStackMask(m_system_shared_layer_id,
this->GetLayerStackMask());
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
s32 initial_z = Foreground;
s32 initial_z = 1;
if (m_applet_id == AppletId::OverlayDisplay) {
initial_z = Overlay;
initial_z = -1;
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
}
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
@@ -148,36 +142,6 @@ Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_bu
R_SUCCEED();
}
u32 DisplayLayerManager::GetLayerStackMask() const {
using Nvnflinger::LayerStackBit;
using Nvnflinger::LayerStackId;
constexpr u32 Displayed = LayerStackBit(LayerStackId::Default);
constexpr u32 Screenshot = LayerStackBit(LayerStackId::Screenshot);
constexpr u32 Recording = LayerStackBit(LayerStackId::Recording);
constexpr u32 LastFrame = LayerStackBit(LayerStackId::LastFrame);
constexpr u32 Debug = LayerStackBit(LayerStackId::ApplicationForDebug);
switch (m_applet_id) {
case AppletId::Application:
return Displayed | Screenshot | Recording | LastFrame | Debug;
case AppletId::OverlayDisplay:
return Displayed;
case AppletId::QLaunch:
return Displayed;
default:
break;
}
switch (m_library_applet_mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::AllForegroundInitiallyHidden:
return Displayed | Screenshot | LastFrame;
default:
return Displayed | Screenshot;
}
}
void DisplayLayerManager::SetWindowVisibility(bool visible) {
if (m_visible == visible) {
return;
@@ -221,17 +185,10 @@ void DisplayLayerManager::SetOverlayZIndex(s32 z_index) {
}
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index,
VI::CaptureKind kind) {
s32* out_fbshare_layer_index) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, kind));
}
Result DisplayLayerManager::ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->ClearAppletCaptureBuffer(
fbshare_layer_index, color));
out_was_written, out_fbshare_layer_index));
}
} // namespace Service::AM
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -23,7 +23,6 @@ class KProcess;
namespace Service::VI {
class IApplicationDisplayService;
class IManagerDisplayService;
enum class CaptureKind : u32;
} // namespace Service::VI
namespace Service::AM {
@@ -49,13 +48,9 @@ public:
void SetOverlayZIndex(s32 z_index);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index,
VI::CaptureKind kind);
Result ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
private:
u32 GetLayerStackMask() const;
Kernel::KProcess* m_process{};
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
@@ -64,7 +59,6 @@ private:
u64 m_system_shared_buffer_id{};
u64 m_system_shared_layer_id{};
AppletId m_applet_id{};
LibraryAppletMode m_library_applet_mode{};
bool m_buffer_sharing_enabled{};
bool m_blending_enabled{};
bool m_visible{true};
+6 -11
View File
@@ -36,17 +36,12 @@ HidRegistration::~HidRegistration() {
}
}
void HidRegistration::EnableAppletToGetInput(bool enable_pad, bool enable_touch) {
if (!m_process.IsInitialized())
return;
const auto resource_manager = m_hid_server->GetResourceManager();
const u64 aruid = m_process.GetProcessId();
resource_manager->EnablePadInput(aruid, enable_pad);
resource_manager->EnableTouchScreen(aruid, enable_touch);
resource_manager->SetAruidValidForVibration(aruid, enable_pad);
void HidRegistration::EnableAppletToGetInput(bool enable) {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
enable);
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
}
}
} // namespace Service::AM
+1 -1
View File
@@ -28,7 +28,7 @@ public:
~HidRegistration();
void RegisterCurrentProcess();
void EnableAppletToGetInput(bool enable_pad, bool enable_touch);
void EnableAppletToGetInput(bool enable);
private:
Process& m_process;
+2 -11
View File
@@ -6,7 +6,6 @@
#include <optional>
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -105,16 +104,8 @@ std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
auto base_slot = storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program);
if (!base_slot) {
base_slot = storage.GetSlotForEntry(FileSys::GetBaseTitleID(launch.title_id), FileSys::ContentRecordType::Program);
}
launch.base_game_storage_id = GetStorageIdForFrontendSlot(base_slot);
auto update_slot = storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program);
if (!update_slot) {
update_slot = storage.GetSlotForEntry(FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(launch.title_id)), FileSys::ContentRecordType::Program);
}
launch.update_storage_id = GetStorageIdForFrontendSlot(update_slot);
launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/cmif_serialization.h"
@@ -80,7 +78,7 @@ Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_application_id = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
*out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
R_SUCCEED();
}
@@ -6,10 +6,8 @@
#include <openssl/evp.h>
#include "common/hex_util.h"
#include "common/settings.h"
#include "common/uuid.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
@@ -30,27 +28,6 @@
namespace Service::AM {
namespace {
FileSys::PatchManager::Metadata GetApplicationMetadata(Core::System& system, u64 program_id) {
auto metadata = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, program_id);
if (metadata.first != nullptr) {
return metadata;
}
const auto application_id = FileSys::GetBaseTitleID(program_id);
if (application_id == program_id) {
return metadata;
}
LOG_DEBUG(Service_AM,
"no metadata for program_id={:016X}, falling back to application_id={:016X}",
program_id, application_id);
return FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, application_id);
}
} // Anonymous namespace
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
// clang-format off
@@ -158,7 +135,7 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
attribute.program_id = FileSys::GetBaseTitleID(m_applet->program_id);
attribute.program_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::Account;
@@ -179,7 +156,7 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = GetApplicationMetadata(system, m_applet->program_id);
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
@@ -217,7 +194,7 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
LOG_DEBUG(Service_AM, "called");
const auto res = GetApplicationMetadata(system, m_applet->program_id);
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
if (res.first != nullptr) {
const auto& version = res.first->GetVersionString();
std::memcpy(out_display_version->string.data(), version.data(),
@@ -238,7 +215,7 @@ Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys
static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
type, FileSys::GetBaseTitleID(m_applet->program_id), user_id.AsU128(), {normal_size, journal_size});
type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size});
// The following value is used to indicate the amount of space remaining on failure
// due to running out of space. Since we always succeed, this should be 0.
@@ -252,7 +229,7 @@ Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64>
LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
type, FileSys::GetBaseTitleID(m_applet->program_id), user_id.AsU128());
type, m_applet->program_id, user_id.AsU128());
*out_normal_size = size.normal;
*out_journal_size = size.journal;
@@ -347,7 +324,6 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(stubbed)");
R_UNLESS(out_pseudo_device_id, ResultUnknown);
// This should be hashed with the device specific hash
// for now this will do
@@ -454,21 +430,15 @@ Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value)
// https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart
Result IApplicationFunctions::CreateApplicationAndRequestToStart(u64 application_id) {
LOG_INFO(Service_AM, "called, application_id={:016X} current_program_id={:016X}", application_id, m_applet->program_id);
LOG_INFO(Service_AM, "called, application_id={:016X}", application_id);
if (application_id == 0 ||
FileSys::GetBaseTitleID(application_id) == FileSys::GetBaseTitleID(m_applet->program_id)) {
const auto program_index = application_id == 0
? 0
: application_id - FileSys::GetBaseTitleID(application_id);
// If application_id is 0, relaunch the current application
const u64 target_application_id =
(application_id == 0) ? m_applet->program_id : application_id;
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(program_index);
R_SUCCEED();
}
LOG_ERROR(Service_AM, "Launching a different application ({:016X}) is not implemented!", application_id);
R_THROW(ResultUnknown);
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(target_application_id);
R_SUCCEED();
}
Result IApplicationFunctions::ClearUserChannel() {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -8,7 +8,6 @@
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/display_controller.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/vi/shared_buffer_manager.h"
namespace Service::AM {
@@ -72,16 +71,16 @@ Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_l
}
Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
LOG_DEBUG(Service_AM, "called, unknown0={} fbshare_layer_index={} color={:#x}", unknown0,
fbshare_layer_index, color);
R_RETURN(applet->display_layer_manager.ClearAppletCaptureBuffer(fbshare_layer_index, color));
LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
unknown0, fbshare_layer_index, color);
R_SUCCEED();
}
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastForeground));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
@@ -91,9 +90,9 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::CallerApplet));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
@@ -103,9 +102,9 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastApplication));
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/applet.h"
@@ -22,7 +22,7 @@ namespace Service::AM {
{10, nullptr, "StartShutdownSequenceForOverlay"},
{11, nullptr, "StartRebootSequenceForOverlay"},
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"},
{21, nullptr, "SetHandlingTouchScreenInputEnabled"},
{30, nullptr, "SetHealthWarningShowingState"},
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
{40, nullptr, "GetApplicationNintendoLogo"},
@@ -43,12 +43,10 @@ namespace Service::AM {
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
{
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_watching_short_home_button = true;
}
m_applet->overlay_in_foreground = true;
m_applet->home_button_short_pressed_blocked = false;
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate();
}
@@ -58,26 +56,16 @@ namespace Service::AM {
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
{
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_watching_short_home_button = false;
}
m_applet->overlay_in_foreground = false;
m_applet->home_button_short_pressed_blocked = false;
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
window_system->RequestUpdate();
}
R_SUCCEED();
}
Result IOverlayFunctions::SetHandlingTouchScreenInputEnabled(bool enabled) {
LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->overlay_handling_touch_input = enabled;
R_SUCCEED();
}
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
LOG_DEBUG(Service_AM, "called");
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -20,7 +20,6 @@ namespace Service::AM {
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
Result IsHealthWarningRequired(Out<bool> is_required);
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
Result SetHandlingTouchScreenInputEnabled(bool enabled);
Result Unknown70();
private:
+80 -136
View File
@@ -4,11 +4,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
@@ -36,82 +32,46 @@ void WindowSystem::RequestUpdate() {
}
void WindowSystem::Update() {
{
std::scoped_lock lk{m_lock};
std::scoped_lock lk{m_lock};
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
// Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked();
// Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked();
// If the home menu is being locked into the foreground, handle that.
if (!this->LockHomeMenuIntoForegroundLocked()) {
const bool overlay_takes_input = this->DoesOverlayTakeInputLocked();
this->UpdateAppletStateLocked(m_overlay_display, true, overlay_takes_input);
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_takes_input);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_takes_input);
}
// If the home menu is being locked into the foreground, handle that.
if (this->LockHomeMenuIntoForegroundLocked()) {
return;
}
this->NotifyApplicationChangedIfNeeded();
bool overlay_blocks_input = false;
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
overlay_blocks_input = m_overlay_display->overlay_in_foreground;
}
// Recursively update each applet root.
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_blocks_input);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_blocks_input);
this->UpdateAppletStateLocked(m_overlay_display, true, false); // overlay is always updated, never blocked
}
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
{
std::scoped_lock lk{m_lock};
std::scoped_lock lk{m_lock};
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {
m_overlay_display = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
}
this->UpdateCurrentApplicationLocked();
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {
m_overlay_display = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
}
this->NotifyApplicationChangedIfNeeded();
}
void WindowSystem::UpdateCurrentApplicationLocked() {
const Applet* const candidate = m_application != nullptr ? m_application : m_home_menu;
if (candidate == nullptr) {
return;
}
auto* const process = candidate->process->GetHandle();
if (process == nullptr || process == m_system.Kernel().ApplicationProcess()) {
return;
}
LOG_INFO(Service_AM, "Current application is now {:016X}", candidate->program_id);
m_system.Kernel().SetApplicationProcess(process);
Settings::SetCurrentProgramID(candidate->program_id);
m_pending_application_notification = candidate->program_id;
}
void WindowSystem::NotifyApplicationChangedIfNeeded() {
std::optional<u64> program_id;
{
std::scoped_lock lk{m_lock};
program_id = std::exchange(m_pending_application_notification, std::nullopt);
}
if (!program_id.has_value()) {
return;
}
m_system.NotifyApplicationChanged(*program_id);
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
}
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
@@ -209,40 +169,18 @@ void WindowSystem::OnExitRequested() {
}
void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) {
const auto is_blocked = [message](const Applet& applet) {
if (message == AppletMessage::DetectShortPressingHomeButton &&
applet.applet_id == AppletId::OverlayDisplay &&
!applet.overlay_watching_short_home_button) {
return true;
}
switch (message) {
case AppletMessage::DetectShortPressingHomeButton:
return applet.home_button_short_pressed_blocked;
case AppletMessage::DetectLongPressingHomeButton:
return applet.home_button_long_pressed_blocked;
default:
return false;
}
};
const auto send_to = [&](Applet* applet) {
if (!applet) {
return;
}
std::scoped_lock lk{applet->lock};
if (is_blocked(*applet)) {
LOG_DEBUG(Service_AM, "Applet {} is blocking message {}",
static_cast<u32>(applet->applet_id), static_cast<u32>(message));
return;
}
applet->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
};
send_to(m_home_menu);
send_to(m_overlay_display);
send_to(m_application);
if (m_home_menu) {
std::scoped_lock lk_home{m_home_menu->lock};
m_home_menu->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
m_overlay_display->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_application) {
std::scoped_lock lk_application{m_application->lock};
m_application->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
}
if (m_event_observer) {
m_event_observer->RequestUpdate();
}
@@ -254,9 +192,19 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) {
case SystemButtonType::HomeButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton);
break;
case SystemButtonType::HomeButtonLongPressing:
case SystemButtonType::HomeButtonLongPressing: {
// Toggle overlay foreground visibility on long home press
if (m_overlay_display) {
std::scoped_lock lk_overlay{m_overlay_display->lock};
m_overlay_display->overlay_in_foreground = !m_overlay_display->overlay_in_foreground;
LOG_INFO(Service_AM, "Overlay long-press toggle: overlay_in_foreground={} window_visible={}", m_overlay_display->overlay_in_foreground, m_overlay_display->window_visible);
}
SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton);
break;
// Force a state update after toggling overlay
if (m_event_observer) {
m_event_observer->RequestUpdate();
}
break; }
case SystemButtonType::CaptureButtonShortPressing:
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton);
break;
@@ -369,8 +317,6 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
m_overlay_display = nullptr;
}
this->UpdateCurrentApplicationLocked();
// Finalize applet.
applet->OnProcessTerminatedLocked();
@@ -443,20 +389,7 @@ void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
applet->lock.lock();
}
bool WindowSystem::IsOverlayOpenLocked(const Applet& overlay) const {
return overlay.window_visible && overlay.overlay_watching_short_home_button;
}
bool WindowSystem::DoesOverlayTakeInputLocked() const {
if (m_overlay_display == nullptr) {
return false;
}
std::scoped_lock lk{m_overlay_display->lock};
return this->IsOverlayOpenLocked(*m_overlay_display);
}
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input) {
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking) {
// With no applet, we don't have anything to do.
if (!applet) {
return;
@@ -487,18 +420,24 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
return false;
}();
const bool is_overlay = applet->applet_id == AppletId::OverlayDisplay;
// Update visibility state.
const bool should_be_visible =
is_overlay ? applet->window_visible : (is_foreground && applet->window_visible);
// Overlay applets should always be visible when window_visible is true, regardless of foreground state
const bool should_be_visible = (applet->applet_id == AppletId::OverlayDisplay)
? applet->window_visible
: (is_foreground && applet->window_visible);
applet->display_layer_manager.SetWindowVisibility(should_be_visible);
const bool needs_hid_input =
is_overlay ? this->IsOverlayOpenLocked(*applet)
: (is_foreground && applet->window_visible && !overlay_takes_input);
applet->SetInteractibleLocked(needs_hid_input, needs_hid_input);
const bool should_be_interactible = (applet->applet_id == AppletId::OverlayDisplay)
? applet->overlay_in_foreground
: (is_foreground && applet->window_visible && !overlay_blocking);
if (applet->applet_id == AppletId::OverlayDisplay || applet->applet_id == AppletId::Application) {
LOG_DEBUG(Service_AM, "UpdateAppletStateLocked: applet={} overlay_in_foreground={} is_foreground={} window_visible={} overlay_blocking={} should_be_interactible={}",
static_cast<u32>(applet->applet_id), applet->overlay_in_foreground, is_foreground, applet->window_visible, overlay_blocking, should_be_interactible);
}
applet->SetInteractibleLocked(should_be_interactible);
// Update focus state and suspension.
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
@@ -514,18 +453,23 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
applet->UpdateSuspensionStateLocked(true);
}
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity.
s32 z_index = Background;
if (is_overlay) {
z_index = Overlay;
} else if (inherited_foreground) {
z_index = is_obscured ? Foreground : ForegroundVisible;
// Z-index logic like in reference C# implementation (tuned for overlay extremes)
s32 z_index = 0;
const bool now_foreground = inherited_foreground;
if (applet->applet_id == AppletId::OverlayDisplay) {
z_index = applet->overlay_in_foreground ? 100000 : -1;
} else if (now_foreground && !is_obscured) {
z_index = 2;
} else if (now_foreground) {
z_index = 1;
} else {
z_index = 0;
}
applet->display_layer_manager.SetOverlayZIndex(z_index);
// Recurse into child applets.
for (const auto& child_applet : applet->child_applets) {
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_takes_input);
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_blocking);
}
}
+1 -8
View File
@@ -9,7 +9,6 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include "common/common_types.h"
#include "core/hle/service/am/am_types.h"
@@ -61,16 +60,11 @@ public:
void OnPowerButtonPressed(ButtonPressDuration type) {}
private:
void UpdateCurrentApplicationLocked();
void NotifyApplicationChangedIfNeeded();
void PruneTerminatedAppletsLocked();
bool RestartAppletProcessLocked(Applet* applet);
bool LockHomeMenuIntoForegroundLocked();
void TerminateChildAppletsLocked(Applet* applet);
bool IsOverlayOpenLocked(const Applet& overlay) const;
bool DoesOverlayTakeInputLocked() const;
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input);
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);
void SendButtonAppletMessageLocked(AppletMessage message);
private:
@@ -94,7 +88,6 @@ private:
// Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{};
std::optional<u64> m_pending_application_notification{};
};
} // namespace Service::AM
@@ -23,7 +23,6 @@
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/am/am_results.h"
#include "core/loader/loader.h"
namespace Service::AOC {
@@ -32,10 +31,6 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return FileSys::GetBaseTitleID(title_id) == base;
}
static u64 GetCallerBaseTitleID(Core::System& system, const ClientProcessId& process_id) {
return FileSys::GetBaseTitleID(system.ResolveCallerProgramId(*process_id));
}
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
const auto& rcu = system.GetContentProvider();
@@ -96,7 +91,7 @@ IAddOnContentManager::~IAddOnContentManager() {
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto current = GetCallerBaseTitleID(system, process_id);
const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -117,7 +112,7 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id.pid);
const auto current = GetCallerBaseTitleID(system, process_id);
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -131,7 +126,8 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
}
}
R_UNLESS(out.size() >= offset, AM::ResultApplicationRecordNotFound);
// TODO(DarkLordZach): Find the correct error code.
R_UNLESS(out.size() >= offset, ResultUnknown);
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end());
@@ -145,7 +141,7 @@ Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto title_id = system.ResolveCallerProgramId(*process_id);
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
+7 -5
View File
@@ -24,8 +24,8 @@ static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
return out;
}
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_)
: ServiceFramework{system_, "IBcatService"}, backend{backend_}, program_id{program_id_},
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
: ServiceFramework{system_, "IBcatService"}, backend{backend_},
progress{{
ProgressServiceBackend{system_, "Normal"},
ProgressServiceBackend{system_, "Directory"},
@@ -70,7 +70,8 @@ Result IBcatService::RequestSyncDeliveryCache(
LOG_DEBUG(Service_BCAT, "called");
auto& progress_backend{GetProgressBackend(SyncType::Normal)};
backend.Synchronize(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
backend.Synchronize(system.Kernel(), {system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
GetProgressBackend(SyncType::Normal));
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
@@ -85,8 +86,9 @@ Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
LOG_DEBUG(Service_BCAT, "called, name={}", name);
auto& progress_backend{GetProgressBackend(SyncType::Directory)};
backend.SynchronizeDirectory(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, progress_backend);
backend.SynchronizeDirectory(system.Kernel(), {system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, progress_backend);
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
system, progress_backend.GetEvent(), progress_backend.GetImpl());
+1 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -22,7 +19,7 @@ class IDeliveryCacheProgressService;
class IBcatService final : public ServiceFramework<IBcatService> {
public:
explicit IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_);
explicit IBcatService(Core::System& system_, BcatBackend& backend_);
~IBcatService() override;
private:
@@ -42,7 +39,6 @@ private:
const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
BcatBackend& backend;
u64 program_id;
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
};
@@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/bcat/bcat_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/bcat/service_creator.h"
@@ -41,8 +37,7 @@ IServiceCreator::~IServiceCreator() = default;
Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
OutInterface<IBcatService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
*out_interface =
std::make_shared<IBcatService>(system, *backend, system.ResolveCallerProgramId(*process_id));
*out_interface = std::make_shared<IBcatService>(system, *backend);
R_SUCCEED();
}
@@ -50,7 +45,7 @@ Result IServiceCreator::CreateDeliveryCacheStorageService(
ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
const auto title_id = system.ResolveCallerProgramId(*process_id);
const auto title_id = system.GetApplicationProcessProgramID();
*out_interface =
std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
R_SUCCEED();
+2 -7
View File
@@ -243,15 +243,10 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
}
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute,
AlbumReportOption report_option,
const ApplicationData& app_data, std::span<const u8> image_data,
u64 aruid) {
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) {
R_UNLESS(!image_data.empty(), ResultUnknown); //TODO: ???
const u64 title_id = system.ResolveCallerProgramId(aruid);
const u64 title_id = system.GetApplicationProcessProgramID();
auto static_service =
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
+1 -2
View File
@@ -95,8 +95,7 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
manager->FlipVerticallyOnWrite(invert_y);
manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
},
layout,
Nvnflinger::LayerStackId::Screenshot);
layout);
}
} // namespace Service::Capture
@@ -14,7 +14,6 @@
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/patch_manager.h"
@@ -340,7 +339,7 @@ Result FileSystemController::RegisterProcess(
registrations.emplace(process_id, Registration{
.program_id = program_id,
.romfs_factory = std::move(romfs_factory),
.save_data_factory = CreateSaveDataFactory(FileSys::GetBaseTitleID(program_id)),
.save_data_factory = CreateSaveDataFactory(program_id),
});
LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
@@ -18,7 +18,6 @@
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h"
@@ -314,7 +313,7 @@ Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSyste
FileSys::ResultInvalidArgument);
if (attribute.program_id == 0) {
attribute.program_id = FileSys::GetBaseTitleID(program_id);
attribute.program_id = program_id;
}
FileSys::VirtualDir dir{};
+1 -1
View File
@@ -1164,7 +1164,7 @@ Result IHidServer::InitializeSevenSixAxisSensor(ClientAppletResourceUserId aruid
GetResourceManager()->GetConsoleSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->Activate();
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress(), t_mem_1->GetOwner());
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
R_SUCCEED();
}
+1 -1
View File
@@ -312,7 +312,7 @@ Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode pollin
auto& device = devices[device_index.value()].device;
device->SetPollingMode(polling_mode);
device->SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
R_SUCCEED();
}
+2 -6
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -150,7 +147,7 @@ Result IRS::RunImageTransferProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
@@ -298,8 +295,7 @@ Result IRS::RunImageTransferExProcessor(
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(),
t_mem->GetOwner());
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
+1 -1
View File
@@ -35,7 +35,7 @@ public:
, process{kernel, process_}
, user_rx{std::move(user_rx_)}
, user_ro{std::move(user_ro_)}
, context{process_->GetMemory()}
, context{system_.ApplicationMemory()}
{
// clang-format off
@@ -9,12 +9,15 @@
#include <optional>
#include <string>
#include "common/stb.h"
#define STBI_ONLY_JPEG 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/language.h"
@@ -333,8 +336,8 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
constexpr s32 data_offset = 0;
if (t_mem != nullptr && t_mem->GetOwner() != nullptr && app_count > 0) {
auto& memory = t_mem->GetOwner()->GetMemory();
if (t_mem != nullptr && app_count > 0) {
auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress();
for (size_t i = 0; i < app_count; ++i) {
@@ -77,7 +77,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
.transform_flags = layer.transform,
.crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending),
.layer_stack_mask = layer.layer_stack_mask,
});
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
@@ -69,7 +69,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x3:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
case 0x8:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, false);
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
case 0x9:
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
case 0xb:
@@ -83,7 +83,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x1a:
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd);
case 0x1b:
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, true);
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
case 0x1d:
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
default:
@@ -387,19 +387,8 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
return NvResult::Success;
}
Core::Memory::Memory& nvhost_gpu::GetSessionMemory(DeviceFD fd) {
if (const auto it = sessions.find(fd); it != sessions.end())
if (auto* const session = core.GetSession(it->second);
session != nullptr && session->process != nullptr)
return session->process->GetMemory();
LOG_ERROR(Service_NVDRV, "No session for fd={}, falling back to application memory", fd);
return system.ApplicationMemory();
}
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
bool kickoff) {
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
if (params.num_entries > commands.size()) {
UNIMPLEMENTED();
return NvResult::InvalidSize;
@@ -407,7 +396,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
Tegra::CommandList entries(params.num_entries);
if (kickoff) {
this->GetSessionMemory(fd).ReadBlock(params.address, entries.command_lists.data(),
system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
std::memcpy(entries.command_lists.data(), commands.data(),
@@ -16,10 +16,6 @@
#include "core/hle/service/nvdrv/nvdata.h"
#include "video_core/dma_pusher.h"
namespace Core::Memory {
class Memory;
}
namespace Tegra {
namespace Control {
struct ChannelState;
@@ -200,11 +196,8 @@ private:
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
Core::Memory::Memory& GetSessionMemory(DeviceFD fd);
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
bool kickoff = false);
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
std::span<const Tegra::CommandListHeader> commands);
@@ -8,7 +8,6 @@
#include "common/assert.h"
#include "common/logging.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
@@ -72,23 +71,17 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id;
if (const auto* session = core.GetSession(session_id);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelOpen(session->process->GetId());
}
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd);
if (it != sessions.end()) {
if (const auto* session = core.GetSession(it->second);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelClose(session->process->GetId());
}
sessions.erase(it);
}
}
+2 -4
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -15,8 +15,7 @@ struct Layer {
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
s32 consumer_id_)
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false),
layer_stack_mask(DefaultLayerStackMask) {}
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {}
~Layer() {
buffer_item_consumer->Abandon();
}
@@ -27,7 +26,6 @@ struct Layer {
bool visible;
s32 z_index;
bool is_overlay;
u32 layer_stack_mask;
};
struct LayerStack {
@@ -115,7 +115,6 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
.acquire_fence = item.fence,
.layer_stack_mask = layer->layer_stack_mask,
});
}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -26,25 +23,6 @@ enum class LayerBlending : u32 {
Coverage = 0x405,
};
enum class LayerStackId : u32 {
Default = 0,
Lcd = 1,
Screenshot = 2,
Recording = 3,
LastFrame = 4,
Arbitrary = 5,
ApplicationForDebug = 6,
Null = 10,
};
constexpr u32 LayerStackBit(LayerStackId id) {
return 1U << static_cast<u32>(id);
}
constexpr u32 DefaultLayerStackMask =
LayerStackBit(LayerStackId::Default) | LayerStackBit(LayerStackId::Screenshot) |
LayerStackBit(LayerStackId::Recording) | LayerStackBit(LayerStackId::LastFrame);
struct HwcLayer {
u32 buffer_handle;
u32 offset;
@@ -57,7 +35,6 @@ struct HwcLayer {
android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect;
android::Fence acquire_fence;
u32 layer_stack_mask;
};
} // namespace Service::Nvnflinger
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -104,14 +104,6 @@ void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blen
}
}
void SurfaceFlinger::SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask) {
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->layer_stack_mask = layer_stack_mask;
LOG_DEBUG(Service_VI, "Layer {} stack mask set to {:#x}", consumer_binder_id,
layer_stack_mask);
}
}
void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) {
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->is_overlay = is_overlay;
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -48,7 +48,6 @@ public:
void SetLayerVisibility(s32 consumer_binder_id, bool visible);
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay);
void SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask);
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -13,10 +13,8 @@
namespace Service::PCTL {
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_,
u64 program_id_)
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
program_id{program_id_},
service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
unlinked_event{service_context}, request_suspension_event{service_context} {
// clang-format off
@@ -204,6 +202,7 @@ Result IParentalControlService::Initialize() {
// TODO(ogniK): Recovery flag initialization for pctl:r
const auto program_id = system.GetApplicationProcessProgramID();
if (program_id != 0) {
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -16,8 +16,7 @@ namespace Service::PCTL {
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
explicit IParentalControlService(Core::System& system_, Capability capability_,
u64 program_id_);
explicit IParentalControlService(Core::System& system_, Capability capability_);
~IParentalControlService() override;
private:
@@ -85,7 +84,6 @@ private:
RestrictionSettings restriction_settings{};
std::array<char, 8> pin_code{};
Capability capability{};
u64 program_id{};
// TODO: this is raw
PlayTimerSettings raw_play_timer_settings{};
@@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pctl/parental_control_service.h"
#include "core/hle/service/pctl/parental_control_service_factory.h"
@@ -27,17 +23,17 @@ IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
Result IParentalControlServiceFactory::CreateService(
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
*out_service = std::make_shared<IParentalControlService>(
system, capability, system.ResolveCallerProgramId(*process_id));
LOG_DEBUG(Service_PCTL, "called");
// TODO(ogniK): Get application id from process
*out_service = std::make_shared<IParentalControlService>(system, capability);
R_SUCCEED();
}
Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
*out_service = std::make_shared<IParentalControlService>(
system, capability, system.ResolveCallerProgramId(*process_id));
LOG_DEBUG(Service_PCTL, "called");
// TODO(ogniK): Get application id from process
*out_service = std::make_shared<IParentalControlService>(system, capability);
R_SUCCEED();
}
+5 -2
View File
@@ -132,7 +132,8 @@ private:
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
auto process = kernel.GetProcessByProcessId(pid);
auto list = kernel.GetProcessList();
auto process = SearchProcessList(system.Kernel(), list, [pid](auto& p) { return p->GetProcessId() == pid; });
if (process.IsNull()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -185,7 +186,9 @@ private:
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
auto process = kernel.GetProcessByProcessId(process_id);
auto list = kernel.GetProcessList();
auto process = SearchProcessList(system.Kernel(),
list, [process_id](auto& p) { return p->GetProcessId() == process_id; });
if (process.IsNull()) {
IPC::ResponseBuilder rb{ctx, 2};
+2 -2
View File
@@ -76,7 +76,7 @@ private:
Type, process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id);
IPC::ResponseBuilder rb{ctx, 2};
@@ -98,7 +98,7 @@ private:
Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id, user_id);
IPC::ResponseBuilder rb{ctx, 2};
+1 -15
View File
@@ -4,16 +4,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <fmt/ranges.h>
#include <string_view>
#include <thread>
#include "common/assert.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h"
@@ -37,7 +33,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
: SessionRequestHandler(system_.Kernel(), service_name_)
, system{system_}
, service_name{service_name_}
, is_i_storage{std::string_view{service_name_} == "IStorage"}
, handler_invoker{handler_invoker_}
, max_sessions{max_sessions_}
{}
@@ -82,22 +77,13 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
}
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
const auto command = ctx.GetCommand();
auto it = handlers.find(command);
const bool is_cmd_read = command == 0;
auto it = handlers.find(ctx.GetCommand());
FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second;
if (info == nullptr || info->handler_callback == nullptr)
return ReportUnimplementedFunction(ctx, info);
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
handler_invoker(this, info->handler_callback, ctx);
if (is_i_storage && is_cmd_read) {
const auto* const process = ctx.GetThread().GetOwnerProcess();
if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) {
std::this_thread::sleep_for(std::chrono::microseconds{600});
}
}
}
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
-2
View File
@@ -107,8 +107,6 @@ protected:
Core::System& system;
/// Identifier string used to connect to the service.
const char* service_name;
/// Whether this is the IStorage service.
const bool is_i_storage;
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker;
/// Maximum number of concurrent sessions that this service can handle.
+1 -11
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -166,16 +166,6 @@ Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) {
R_RETURN(VI::ResultNotFound);
}
Result Container::SetLayerStackMask(u64 layer_id, u32 layer_stack_mask) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
m_surface_flinger->SetLayerStackMask(layer->GetConsumerBinderId(), layer_stack_mask);
R_SUCCEED();
}
Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) {
std::scoped_lock lk{m_lock};
+1 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -68,7 +68,6 @@ public:
Result SetLayerZIndex(u64 layer_id, s32 z_index);
Result GetLayerZIndex(u64 layer_id, s32* out_z_index);
Result SetLayerIsOverlay(u64 layer_id, bool is_overlay);
Result SetLayerStackMask(u64 layer_id, u32 layer_stack_mask);
void LinkVsyncEvent(u64 display_id, Event* event);
void UnlinkVsyncEvent(u64 display_id, Event* event);
+82 -235
View File
@@ -4,15 +4,9 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <random>
#include "common/assert.h"
#include "common/logging.h"
#include "common/scratch_buffer.h"
#include "core/core.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
@@ -53,7 +47,7 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0x00000000;
*start = 0xFF0000FF;
}
}
@@ -174,14 +168,7 @@ constexpr u32 SharedBufferBlockLinearWidth = 1280;
constexpr u32 SharedBufferBlockLinearHeight = 768;
constexpr u32 SharedBufferBlockLinearStride =
SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
constexpr u32 SharedBufferNumCaptureSlots = 3;
constexpr u32 SharedBufferSlotsPerSession = 2;
constexpr u32 SharedBufferMaxSessions = 2;
constexpr u32 SharedBufferNumSlots =
SharedBufferNumCaptureSlots + SharedBufferSlotsPerSession * SharedBufferMaxSessions;
static_assert(SharedBufferNumSlots <= 16, "Shared buffer pool exceeds the maximum texture count");
constexpr u32 SharedBufferNumSlots = 7;
constexpr u32 SharedBufferWidth = 1280;
constexpr u32 SharedBufferHeight = 720;
@@ -205,52 +192,7 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
return layout;
}();
constexpr u32 GetCaptureSlot(CaptureKind kind) {
return static_cast<u32>(kind);
}
static_assert(static_cast<u32>(CaptureKind::CallerApplet) + 1 == SharedBufferNumCaptureSlots,
"Capture slot count does not match CaptureKind");
constexpr u32 GetPresentationSlot(u32 slot_base, u32 index) {
return SharedBufferNumCaptureSlots + slot_base + index;
}
constexpr u32 ColorOpaqueBlackRgba32 = 0xFF000000;
template <typename F>
void ForEachPoolChunk(Core::System& system, Kernel::KPageGroup& page_group, u64 offset, u64 size,
F&& writer) {
Common::ScratchBuffer<u32> scratch;
const u64 range_end = offset + size;
u64 pool_pos = 0;
for (auto& block : page_group) {
const u64 block_begin = pool_pos;
const u64 block_end = block_begin + block.GetSize();
pool_pos = block_end;
if (block_end <= offset) {
continue;
}
if (block_begin >= range_end) {
break;
}
const u64 chunk_begin = (std::max)(block_begin, offset);
const u64 chunk_end = (std::min)(block_end, range_end);
const u64 chunk_size = chunk_end - chunk_begin;
u8* const dst =
system.DeviceMemory().GetPointer<u8>(block.GetAddress()) + (chunk_begin - block_begin);
writer(dst, chunk_begin - offset, chunk_size);
system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(
dst, scratch, [&](DAddr addr) { system.GPU().InvalidateRegion(addr, chunk_size); });
}
}
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 producer_slot, u32 pool_slot, u32 handle) {
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
auto buffer = std::make_shared<android::NvGraphicBuffer>();
buffer->width = SharedBufferWidth;
buffer->height = SharedBufferHeight;
@@ -258,8 +200,8 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 producer_slot
buffer->format = SharedBufferBlockLinearFormat;
buffer->external_format = SharedBufferBlockLinearFormat;
buffer->buffer_id = handle;
buffer->offset = pool_slot * SharedBufferSlotSize;
ASSERT(producer.SetPreallocatedBuffer(producer_slot, buffer) == android::Status::NoError);
buffer->offset = slot * SharedBufferSlotSize;
ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
}
} // namespace
@@ -273,91 +215,59 @@ SharedBufferManager::~SharedBufferManager() = default;
Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
u64* out_layer_handle, u64 display_id,
bool enable_blending) {
{
std::scoped_lock lk{m_guard};
std::scoped_lock lk{m_guard};
// Ensure we haven't already created.
const u64 aruid = owner_process->GetProcessId();
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
// Ensure we haven't already created.
const u64 aruid = owner_process->GetProcessId();
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
// Allocate memory for the shared buffer if needed.
if (!m_buffer_page_group) {
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
SharedBufferSize));
// Allocate memory for the shared buffer if needed.
if (!m_buffer_page_group) {
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
SharedBufferSize));
// Record buffer id.
m_buffer_id = m_next_buffer_id++;
// Record buffer id.
m_buffer_id = m_next_buffer_id++;
// Record display id.
m_display_id = display_id;
for (u32 slot = 0; slot < SharedBufferNumCaptureSlots; slot++) {
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{slot} * SharedBufferSlotSize,
SharedBufferSlotSize, [](u8* dst, u64, u64 length) {
std::fill_n(reinterpret_cast<u32*>(dst), length / sizeof(u32),
ColorOpaqueBlackRgba32);
});
}
}
// Claim a presentation slot range.
u32 slot_base = 0;
std::array<bool, SharedBufferMaxSessions> in_use{};
for (const auto& [existing_aruid, existing] : m_sessions) {
const u32 index = existing.presentation_slot_base / SharedBufferSlotsPerSession;
if (index < in_use.size())
in_use[index] = true;
}
u32 index = 0;
while (index < in_use.size() && in_use[index])
index++;
if (index >= in_use.size()) {
LOG_ERROR(Service_VI, "Out of shared buffer presentation slots ({} sessions)", SharedBufferMaxSessions);
R_THROW(VI::ResultOperationFailed);
}
slot_base = index * SharedBufferSlotsPerSession;
// Map into process.
Common::ProcessAddress map_address{};
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
owner_process, m_system));
// Create new session.
auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
auto& session = it->second;
session.presentation_slot_base = slot_base;
auto& container = m_nvdrv->GetContainer();
session.session_id = container.OpenSession(owner_process);
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
// Create an nvmap handle for the buffer and assign the memory to it.
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
session.nvmap_fd, map_address, SharedBufferSize));
// Create and open a layer for the display.
s32 producer_binder_id;
R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
std::addressof(session.layer_id), display_id));
// Configure blending and z-index
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
// Get the producer and set preallocated buffers.
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
for (u32 i = 0; i < SharedBufferSlotsPerSession; i++)
MakeGraphicBuffer(*producer, i, GetPresentationSlot(session.presentation_slot_base, i), session.buffer_nvmap_handle);
// Assign outputs.
*out_buffer_id = m_buffer_id;
*out_layer_handle = session.layer_id;
// Record display id.
m_display_id = display_id;
}
// Map into process.
Common::ProcessAddress map_address{};
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
owner_process, m_system));
// Create new session.
auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
auto& session = it->second;
auto& container = m_nvdrv->GetContainer();
session.session_id = container.OpenSession(owner_process);
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
// Create an nvmap handle for the buffer and assign the memory to it.
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
session.nvmap_fd, map_address, SharedBufferSize));
// Create and open a layer for the display.
s32 producer_binder_id;
R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
std::addressof(session.layer_id), display_id));
// Configure blending and z-index
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
// Get the producer and set preallocated buffers.
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
// Assign outputs.
*out_buffer_id = m_buffer_id;
*out_layer_handle = session.layer_id;
// We succeeded.
R_SUCCEED();
}
@@ -426,51 +336,14 @@ Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
VI::ResultOperationFailed);
out_slot_indexes.fill(-1);
{
std::scoped_lock lk{m_guard};
const auto* const session = this->FindSessionByLayerIdLocked(layer_id);
if (session == nullptr) {
producer->CancelBuffer(slot, *out_fence);
// LOG_DEBUG(Service_VI, "No Session found");
R_THROW(VI::ResultNotFound);
}
for (u32 i = 0; i < SharedBufferSlotsPerSession; i++)
out_slot_indexes[i] =
static_cast<s32>(GetPresentationSlot(session->presentation_slot_base, i));
*out_target_slot = static_cast<s64>(
GetPresentationSlot(session->presentation_slot_base, static_cast<u32>(slot)));
}
// Assign remaining outputs.
*out_target_slot = slot;
out_slot_indexes = {0, 1, -1, -1};
// We succeeded.
R_SUCCEED();
}
Result SharedBufferManager::GetProducerSlotLocked(s32* out_producer_slot, u64 layer_id,
s64 pool_slot) const {
const auto* const session = this->FindSessionByLayerIdLocked(layer_id);
R_UNLESS(session != nullptr, VI::ResultNotFound);
const s64 base = GetPresentationSlot(session->presentation_slot_base, 0);
const s64 producer_slot = pool_slot - base;
R_UNLESS(producer_slot >= 0 && producer_slot < SharedBufferSlotsPerSession,
VI::ResultOperationFailed);
*out_producer_slot = static_cast<s32>(producer_slot);
R_SUCCEED();
}
const SharedBufferSession* SharedBufferManager::FindSessionByLayerIdLocked(u64 layer_id) const {
for (const auto& [aruid, session] : m_sessions)
if (session.layer_id == layer_id)
return std::addressof(session);
return nullptr;
}
Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
Common::Rectangle<s32> crop_region,
u32 transform, s32 swap_interval, u64 layer_id,
@@ -479,20 +352,14 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
s32 producer_slot;
{
std::scoped_lock lk{m_guard};
R_TRY(this->GetProducerSlotLocked(std::addressof(producer_slot), layer_id, slot));
}
// Request to queue the buffer.
std::shared_ptr<android::GraphicBuffer> buffer;
R_UNLESS(producer->RequestBuffer(producer_slot, std::addressof(buffer)) ==
R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
android::Status::NoError,
VI::ResultOperationFailed);
ON_RESULT_FAILURE {
producer->CancelBuffer(producer_slot, fence);
producer->CancelBuffer(static_cast<s32>(slot), fence);
};
// Queue the buffer to the producer.
@@ -502,10 +369,12 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
input.fence = fence;
input.transform = static_cast<android::NativeWindowTransform>(transform);
input.swap_interval = swap_interval;
R_UNLESS(producer->QueueBuffer(producer_slot, input, std::addressof(output)) ==
R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
android::Status::NoError,
VI::ResultOperationFailed);
(void)m_container.SetLayerZIndex(layer_id, 100000);
// We succeeded.
R_SUCCEED();
}
@@ -515,14 +384,8 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
s32 producer_slot;
{
std::scoped_lock lk{m_guard};
R_TRY(this->GetProducerSlotLocked(std::addressof(producer_slot), layer_id, slot));
}
// Cancel.
producer->CancelBuffer(producer_slot, android::Fence::NoFence());
producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
// We succeeded.
R_SUCCEED();
@@ -541,47 +404,31 @@ Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadabl
R_SUCCEED();
}
Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index, CaptureKind kind) {
std::scoped_lock lk{m_guard};
R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound);
Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
Common::ScratchBuffer<u32> scratch;
const std::vector<u8> capture = m_system.GPU().GetAppletCaptureBuffer();
const u32 slot = GetCaptureSlot(kind);
// TODO: this could be optimized
s64 e = -1280 * 768 * 4;
for (auto& block : *m_buffer_page_group) {
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
if (capture.size() < SharedBufferSlotSize) {
//LOG_WARNING(Service_VI, "Capture buffer is {} bytes, expected at least {}; not writing",
// capture.size(), SharedBufferSlotSize);
*out_was_written = false;
*out_layer_index = static_cast<s32>(slot);
R_SUCCEED();
for (; start < end; start++) {
*start = 0;
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
*start = capture_buffer[e];
}
e++;
}
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, end - start);
});
}
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{slot} * SharedBufferSlotSize,
SharedBufferSlotSize,
[&](u8* dst, u64 src_offset, u64 length) {
std::memcpy(dst, capture.data() + src_offset, length);
});
*out_was_written = true;
*out_layer_index = static_cast<s32>(slot);
R_SUCCEED();
}
Result SharedBufferManager::ClearAppletCaptureBuffer(s32 layer_index, u32 color) {
std::scoped_lock lk{m_guard};
R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound);
if (layer_index < 0 || layer_index >= static_cast<s32>(SharedBufferNumCaptureSlots)) {
LOG_WARNING(Service_VI, "Couldnt clear non-capture slot {}", layer_index);
R_SUCCEED();
}
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{static_cast<u32>(layer_index)} * SharedBufferSlotSize,
SharedBufferSlotSize, [&](u8* dst, u64 src_offset, u64 length) {
ASSERT(src_offset % sizeof(u32) == 0 && length % sizeof(u32) == 0);
std::fill_n(reinterpret_cast<u32*>(dst), length / sizeof(u32), color);
});
*out_layer_index = 1;
R_SUCCEED();
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -48,12 +48,6 @@ static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout h
struct SharedBufferSession;
enum class CaptureKind : u32 {
LastApplication,
LastForeground,
CallerApplet,
};
class SharedBufferManager final {
public:
explicit SharedBufferManager(Core::System& system, Container& container,
@@ -74,15 +68,9 @@ public:
Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index, CaptureKind kind);
Result ClearAppletCaptureBuffer(s32 layer_index, u32 color);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
private:
const SharedBufferSession* FindSessionByLayerIdLocked(u64 layer_id) const;
/// Converts a pool slot index, which is what the guest works in, back to the buffer queues slot index
Result GetProducerSlotLocked(s32* out_producer_slot, u64 layer_id, s64 pool_slot) const;
u64 m_next_buffer_id = 1;
u64 m_display_id = 0;
u64 m_buffer_id = 0;
@@ -101,7 +89,6 @@ struct SharedBufferSession {
Nvidia::NvCore::SessionId session_id = {};
u64 layer_id = {};
u32 buffer_nvmap_handle = 0;
u32 presentation_slot_base = 0;
};
} // namespace Service::VI
-48
View File
@@ -17,8 +17,6 @@
#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/k_process.h"
#include "core/loader/deconstructed_rom_directory.h"
@@ -43,47 +41,6 @@ std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
return std::nullopt;
}
struct IndexedProgram {
FileSys::VirtualFile file;
u64 program_id;
bool update_only;
};
std::optional<IndexedProgram> ResolveIndexedProgram(Core::System& system, u64 program_id,
std::size_t program_index) {
if (program_index == 0 || program_id == 0) {
return std::nullopt;
}
const auto target_id = FileSys::GetBaseTitleIDWithProgramIndex(program_id, program_index);
const auto& provider = system.GetContentProvider();
if (auto base = provider.GetEntryRaw(target_id, FileSys::ContentRecordType::Program)) {
LOG_INFO(Loader, "Program index {} resolved to {:016X}", program_index, target_id);
return IndexedProgram{std::move(base), target_id, false};
}
const auto update_id = FileSys::GetUpdateTitleID(target_id);
if (auto update = provider.GetEntryRaw(update_id, FileSys::ContentRecordType::Program)) {
LOG_INFO(Loader, "Program index {} has no base program, loading it from update {:016X}",
program_index, update_id);
return IndexedProgram{std::move(update), target_id, true};
}
const auto application_update_id =
FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(target_id));
if (application_update_id != update_id) {
if (auto update = provider.GetEntryRaw(application_update_id, FileSys::ContentRecordType::Program)) {
LOG_INFO(Loader, "Program index {} has no base program, loading it from application update {:016X}", program_index, application_update_id);
return IndexedProgram{std::move(update), target_id, true};
}
}
LOG_WARNING(Loader, "No program NCA for {:016X} (index {}), falling back to the container",
target_id, program_index);
return std::nullopt;
}
std::shared_ptr<FileSys::NSP> OpenContainerAsNsp(FileSys::VirtualFile file, FileType type,
u64 program_id = 0,
std::size_t program_index = 0) {
@@ -364,11 +321,6 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile
return nullptr;
}
if (const auto indexed = ResolveIndexedProgram(system, program_id, program_index)) {
return std::make_unique<AppLoader_NCA>(
indexed->file, indexed->update_only ? indexed->program_id : 0);
}
FileType type = IdentifyFile(file);
const FileType filename_type = GuessFromFilename(file->GetName());
+7 -49
View File
@@ -11,11 +11,8 @@
#include "common/hex_util.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/k_process.h"
@@ -36,14 +33,8 @@ static u32 CalculatePointerBufferSize(size_t heap_size) {
}
}
AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_, u64 update_only_program_id_)
: AppLoader(std::move(file_)),
nca(std::make_unique<FileSys::NCA>(file, nullptr, update_only_program_id_ != 0)),
update_only_program_id(update_only_program_id_) {}
u64 AppLoader_NCA::GetProgramId() const {
return update_only_program_id != 0 ? update_only_program_id : nca->GetTitleId();
}
AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
: AppLoader(std::move(file_)), nca(std::make_unique<FileSys::NCA>(file)) {}
AppLoader_NCA::~AppLoader_NCA() = default;
@@ -77,13 +68,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
LOG_INFO(Loader, "No ExeFS found in NCA, looking for ExeFS from update");
const auto& installed = system.GetContentProvider();
const auto program_update_id = FileSys::GetUpdateTitleID(nca->GetTitleId());
auto update_nca = installed.GetEntry(program_update_id, FileSys::ContentRecordType::Program);
if (update_nca == nullptr) {
update_nca = installed.GetEntry(
FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(nca->GetTitleId())),
FileSys::ContentRecordType::Program);
}
const auto update_nca = installed.GetEntry(FileSys::GetUpdateTitleID(nca->GetTitleId()),
FileSys::ContentRecordType::Program);
if (update_nca) {
exefs = update_nca->GetExeFS();
@@ -124,21 +110,11 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
}
LOG_INFO(Loader, "Set pointer buffer size to {:#x} bytes for ProgramID {:#018x} (Heap size: {:#x})",
process.GetPointerBufferSize(), GetProgramId(), heap_size);
auto metadata =
FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, this->GetProgramId());
if (metadata.first != nullptr) {
nacp = std::move(metadata.first);
LOG_INFO(Loader, "Control data for {:016X}: name=\"{}\" supported_languages={:08X}",
this->GetProgramId(), nacp->GetApplicationName(), nacp->GetSupportedLanguages());
} else {
LOG_WARNING(Loader, "No control data found for program {:016X}", this->GetProgramId());
}
process.GetPointerBufferSize(), nca->GetTitleId(), heap_size);
// Register the process in the file system controller
system.GetFileSystemController().RegisterProcess(
process.GetProcessId(), GetProgramId(),
process.GetProcessId(), nca->GetTitleId(),
std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
system.GetFileSystemController()));
@@ -246,25 +222,7 @@ ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
return ResultStatus::ErrorNotInitialized;
}
out_program_id = GetProgramId();
return ResultStatus::Success;
}
ResultStatus AppLoader_NCA::ReadControlData(FileSys::NACP& out_control) {
if (nacp == nullptr) {
return ResultStatus::ErrorNoControl;
}
out_control = *nacp;
return ResultStatus::Success;
}
ResultStatus AppLoader_NCA::ReadTitle(std::string& out_title) {
if (nacp == nullptr) {
return ResultStatus::ErrorNoControl;
}
out_title = nacp->GetApplicationName();
out_program_id = nca->GetTitleId();
return ResultStatus::Success;
}
+1 -11
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -14,7 +11,6 @@ class System;
}
namespace FileSys {
class NACP;
class NCA;
}
@@ -25,7 +21,7 @@ class AppLoader_DeconstructedRomDirectory;
/// Loads an NCA file
class AppLoader_NCA final : public AppLoader {
public:
explicit AppLoader_NCA(FileSys::VirtualFile file_, u64 update_only_program_id = 0);
explicit AppLoader_NCA(FileSys::VirtualFile file_);
~AppLoader_NCA() override;
/**
@@ -47,20 +43,14 @@ public:
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadControlData(FileSys::NACP& out_control) override;
ResultStatus ReadTitle(std::string& out_title) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
ResultStatus ReadNSOModules(Modules& modules) override;
u64 GetProgramId() const;
private:
std::unique_ptr<FileSys::NCA> nca;
u64 update_only_program_id{};
std::unique_ptr<FileSys::NACP> nacp;
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
};
+1 -4
View File
@@ -209,10 +209,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
// Apply cheats if they exist and the program has a valid title ID
if (pm) {
// TODO(Maufeat): Check if there is a better way to check
if (name == "main")
system.SetApplicationProcessBuildID(nso_header.build_id);
system.SetApplicationProcessBuildID(nso_header.build_id);
const auto cheats = pm->CreateCheatList(nso_header.build_id);
if (!cheats.empty()) {
system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);
+4 -10
View File
@@ -8,7 +8,6 @@
#include "common/common_types.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
@@ -38,13 +37,13 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS(), false);
} else {
const auto control_nca =
nsp->GetNCA(FileSys::GetBaseTitleID(nsp->GetProgramTitleID()), FileSys::ContentRecordType::Control);
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
return;
}
std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
const FileSys::PatchManager pm{FileSys::GetBaseTitleID(nsp->GetProgramTitleID()), fsc, content_provider};
const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider};
return pm.ParseControlNCA(*control_nca);
}();
@@ -186,13 +185,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorNoPackedUpdate;
}
const auto program_update_id = FileSys::GetUpdateTitleID(nsp->GetProgramTitleID());
auto read = nsp->GetNCAFile(program_update_id, FileSys::ContentRecordType::Program);
if (read == nullptr) {
read = nsp->GetNCAFile(
FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(nsp->GetProgramTitleID())),
FileSys::ContentRecordType::Program);
}
const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()),
FileSys::ContentRecordType::Program);
if (read == nullptr) {
return ResultStatus::ErrorNoPackedUpdate;
+2 -8
View File
@@ -9,7 +9,6 @@
#include "common/common_types.h"
#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -138,13 +137,8 @@ ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorXCIMissingProgramNCA;
}
const auto program_update_id = FileSys::GetUpdateTitleID(program_id);
auto read = xci->GetSecurePartitionNSP()->GetNCAFile(program_update_id, FileSys::ContentRecordType::Program);
if (read == nullptr) {
read = xci->GetSecurePartitionNSP()->GetNCAFile(
FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(program_id)),
FileSys::ContentRecordType::Program);
}
const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
if (read == nullptr) {
return ResultStatus::ErrorNoPackedUpdate;
}
+9 -28
View File
@@ -51,41 +51,24 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
StandardVmCallbacks::~StandardVmCallbacks() = default;
Kernel::KProcess* StandardVmCallbacks::GetProcess() const {
if (cached_process != nullptr && cached_process_id == metadata.process_id) {
return cached_process;
}
auto process = system.Kernel().GetProcessByProcessId(metadata.process_id);
cached_process = process.IsNull() ? nullptr : process.GetPointerUnsafe();
cached_process_id = metadata.process_id;
return cached_process;
}
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
auto* const process = this->GetProcess();
// Return zero on invalid address
if (process == nullptr || !IsAddressInRange(address) ||
!process->GetMemory().IsValidVirtualAddress(address)) {
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
std::memset(data, 0, size);
return;
}
process->GetMemory().ReadBlock(address, data, size);
system.ApplicationMemory().ReadBlock(address, data, size);
}
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
auto* const process = this->GetProcess();
// Skip invalid memory write address
if (process == nullptr || !IsAddressInRange(address) ||
!process->GetMemory().IsValidVirtualAddress(address)) {
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
return;
}
if (process->GetMemory().WriteBlock(address, data, size)) {
Core::InvalidateInstructionCacheRange(process, address, size);
if (system.ApplicationMemory().WriteBlock(address, data, size)) {
Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), address, size);
}
}
@@ -108,16 +91,14 @@ u64 StandardVmCallbacks::HidKeysDown() {
}
void StandardVmCallbacks::PauseProcess() {
auto* const process = this->GetProcess();
if (process != nullptr && !process->IsSuspended()) {
process->SetActivity(system.Kernel(), Kernel::Svc::ProcessActivity::Paused);
if (!system.ApplicationProcess()->IsSuspended()) {
system.ApplicationProcess()->SetActivity(system.Kernel(), Kernel::Svc::ProcessActivity::Paused);
}
}
void StandardVmCallbacks::ResumeProcess() {
auto* const process = this->GetProcess();
if (process != nullptr && process->IsSuspended()) {
process->SetActivity(system.Kernel(), Kernel::Svc::ProcessActivity::Runnable);
if (system.ApplicationProcess()->IsSuspended()) {
system.ApplicationProcess()->SetActivity(system.Kernel(), Kernel::Svc::ProcessActivity::Runnable);
}
}
-11
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,10 +15,6 @@ namespace Core {
class System;
}
namespace Kernel {
class KProcess;
}
namespace Core::Timing {
class CoreTiming;
struct EventType;
@@ -45,12 +38,8 @@ public:
private:
bool IsAddressInRange(VAddr address) const;
Kernel::KProcess* GetProcess() const;
const CheatProcessMetadata& metadata;
Core::System& system;
mutable Kernel::KProcess* cached_process{};
mutable u64 cached_process_id{};
};
// Intermediary class that parses a text file or other disk format for storing cheats into a
+1 -1
View File
@@ -239,7 +239,7 @@ void Reporter::SaveUnimplementedFunctionReport(Service::HLERequestContext& ctx,
const auto title_id = system.GetApplicationProcessProgramID();
auto out = GetFullDataAuto(timestamp, title_id, system);
auto function_out = GetHLERequestContextData(ctx, ctx.GetMemory());
auto function_out = GetHLERequestContextData(ctx, system.ApplicationMemory());
function_out["command_id"] = command_id;
function_out["function_name"] = name;
function_out["service_name"] = service_name;
@@ -22,7 +22,6 @@
#include <sys/mman.h>
#include "common/assert.h"
#include "common/logging.h"
#include "common/common_types.h"
#include "dynarmic/backend/exception_handler.h"
#include "dynarmic/common/context.h"
@@ -54,21 +53,23 @@ class SigHandler {
return e.first <= offset && e.first + e.second.size > offset;
});
}
static void SigAction(int sig, siginfo_t* info, void* raw_context);
bool supports_fast_mem = true;
void* signal_stack_memory = nullptr;
ankerl::unordered_dense::map<u64, CodeBlockInfo> code_block_infos;
std::shared_mutex code_block_infos_mutex;
struct sigaction old_sa_segv;
struct sigaction old_sa_bus;
std::unique_ptr<uint8_t[]> signal_stack_memory;
bool supports_fast_mem = true;
std::size_t signal_stack_size;
public:
SigHandler() noexcept {
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
signal_stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
stack_t signal_stack{};
signal_stack.ss_sp = signal_stack_memory.get();
signal_stack.ss_size = stack_size;
signal_stack.ss_sp = signal_stack_memory;
signal_stack.ss_size = signal_stack_size;
signal_stack.ss_flags = 0;
if (sigaltstack(&signal_stack, nullptr) != 0) {
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
@@ -86,7 +87,7 @@ public:
supports_fast_mem = false;
return;
}
#if defined(__APPLE__)
#ifdef __APPLE__
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
supports_fast_mem = false;
@@ -95,6 +96,10 @@ public:
#endif
}
~SigHandler() noexcept {
munmap(signal_stack_memory, signal_stack_size);
}
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {
std::unique_lock guard(code_block_infos_mutex);
code_block_infos.insert_or_assign(offset, cbi);
@@ -104,17 +109,14 @@ public:
code_block_infos.erase(offset);
}
[[nodiscard]] inline bool SupportsFastmem() const noexcept {
return supports_fast_mem;
}
static void RegisterHandler();
static void SigAction(int sig, siginfo_t* info, void* raw_context);
bool SupportsFastmem() const noexcept { return supports_fast_mem; }
};
std::mutex handler_lock;
std::optional<SigHandler> sig_handler;
void SigHandler::RegisterHandler() {
void RegisterHandler() {
std::lock_guard<std::mutex> guard(handler_lock);
if (!sig_handler) {
sig_handler.emplace();
}
@@ -123,27 +125,51 @@ void SigHandler::RegisterHandler() {
void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
DEBUG_ASSERT(sig == SIGSEGV || sig == SIGBUS);
CTX_DECLARE(raw_context);
#if defined(ARCHITECTURE_x86_64)
{
std::shared_lock guard(sig_handler->code_block_infos_mutex);
if (auto const iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->second.cb(CTX_PC);
#if defined(ARCHITECTURE_x86_64)
CTX_SP -= sizeof(u64);
*std::bit_cast<u64*>(CTX_SP) = fc.ret_rip;
CTX_PC = fc.call_rip;
#elif defined(ARCHITECTURE_arm64)
CTX_PC = fc.call_pc;
#elif defined(ARCHITECTURE_riscv64)
CTX_PC = fc.call_sepc;
#elif defined(ARCHITECTURE_loongarch64)
CTX_PC = fc.call_pc;
#else
ASSERT(false);
#endif
return;
}
}
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
fmt::print(stderr, "Unhandled {} at rip {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
#elif defined(ARCHITECTURE_arm64)
{
std::shared_lock guard(sig_handler->code_block_infos_mutex);
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->second.cb(CTX_PC);
CTX_PC = fc.call_pc;
return;
}
}
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
#elif defined(ARCHITECTURE_riscv64)
{
std::shared_lock guard(sig_handler->code_block_infos_mutex);
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_SEPC); iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->second.cb(CTX_SEPC);
CTX_SEPC = fc.call_sepc;
return;
}
}
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_SEPC);
#elif defined(ARCHITECTURE_loongarch64)
{
std::shared_lock guard(sig_handler->code_block_infos_mutex);
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->second.cb(CTX_PC);
CTX_PC = fc.call_pc;
return;
}
}
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
#else
# error "Invalid architecture"
#endif
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
if (retry_sa->sa_flags & SA_SIGINFO) {
@@ -164,10 +190,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
struct ExceptionHandler::Impl final {
Impl(u64 offset_, u64 size_)
: offset(offset_)
, size(size_)
{
SigHandler::RegisterHandler();
: offset(offset_)
, size(size_) {
RegisterHandler();
}
void SetCallback(std::function<FakeCall(u64)> cb) {
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <variant>
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
#include "dynarmic/backend/loongarch64/a32_jitstate.h"
@@ -96,8 +95,7 @@ EmittedBlockInfo EmitLoongArch64(lagoon_assembler_t& as, IR::Block block, const
// TODO: Emit Terminal
const auto term = block.GetTerminal();
const IR::Term::LeafTerminal* leaft_term = std::get_if<IR::Term::LeafTerminal>(&term);
const IR::Term::LinkBlock* link_block_term = std::get_if<IR::Term::LinkBlock>(leaft_term);
const IR::Term::LinkBlock* link_block_term = boost::get<IR::Term::LinkBlock>(&term);
ASSERT(link_block_term);
la_load_immediate64(&as, Xscratch0, link_block_term->next.Value());
la_st_w(&as, Xscratch0, Xstate, static_cast<int32_t>(offsetof(A32JitState, regs) + sizeof(u32) * 15));
+3 -3
View File
@@ -136,14 +136,14 @@
# endif
#elif defined(ARCHITECTURE_riscv64)
# if defined(__FreeBSD__)
# define CTX_PC (mctx.mc_gpregs.gp_sepc)
# define CTX_SEPC (mctx.mc_gpregs.gp_sepc)
# define CTX_SP (mctx.mc_gpregs.gp_sp)
# elif defined(__linux__)
# define CTX_PC (mctx.__gregs[REG_PC])
# define CTX_SEPC (mctx.__gregs[REG_PC])
# define CTX_SP (mctx.__gregs[REG_SP])
# elif defined(__OpenBSD__)
// https://github.com/openbsd/src/blob/master/sys/arch/riscv64/include/signal.h
# define CTX_PC (ucontext->sc_sepc)
# define CTX_SEPC (ucontext->sc_sepc)
# define CTX_SP (ucontext->sc_sp)
# else
# error "unknown platform"
+11 -31
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
@@ -56,14 +56,13 @@ inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_contro
*/
inline size_t RemoveAllDLC(Core::System& system, const u64 program_id) {
size_t count{};
const auto application_id = FileSys::GetBaseTitleID(program_id);
const auto& fs_controller = system.GetFileSystemController();
const auto dlc_entries = system.GetContentProvider().ListEntriesFilter(
FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::vector<u64> program_dlc_entries;
for (const auto& entry : dlc_entries) {
if (FileSys::GetBaseTitleID(entry.title_id) == application_id) {
if (FileSys::GetBaseTitleID(entry.title_id) == program_id) {
program_dlc_entries.push_back(entry.title_id);
}
}
@@ -84,17 +83,9 @@ inline size_t RemoveAllDLC(Core::System& system, const u64 program_id) {
*/
inline bool RemoveUpdate(const Service::FileSystem::FileSystemController& fs_controller,
const u64 program_id) {
const auto remove_update = [&fs_controller](u64 update_id) {
return fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
};
const auto update_id = FileSys::GetUpdateTitleID(program_id);
const auto application_update_id =
FileSys::GetUpdateTitleID(FileSys::GetBaseTitleID(program_id));
if (update_id != application_update_id && remove_update(update_id)) {
return true;
}
return remove_update(application_update_id);
const auto update_id = program_id | 0x800;
return fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
}
/**
@@ -120,26 +111,15 @@ inline bool RemoveBaseContent(const Service::FileSystem::FileSystemController& f
inline bool RemoveMod(const Service::FileSystem::FileSystemController& fs_controller,
const u64 program_id, const std::string& mod_name) {
// Check general Mods (LayeredFS and IPS)
const auto remove_from_root = [&mod_name](const auto& root) {
return root != nullptr && root->DeleteSubdirectoryRecursive(mod_name);
};
if (remove_from_root(fs_controller.GetModificationLoadRoot(program_id))) {
return true;
}
if (FileSys::GetBaseTitleID(program_id) != program_id &&
remove_from_root(
fs_controller.GetModificationLoadRoot(FileSys::GetBaseTitleID(program_id)))) {
return true;
const auto mod_dir = fs_controller.GetModificationLoadRoot(program_id);
if (mod_dir != nullptr) {
return mod_dir->DeleteSubdirectoryRecursive(mod_name);
}
// Check SDMC mod directory (RomFS LayeredFS)
if (remove_from_root(fs_controller.GetSDMCModificationLoadRoot(program_id))) {
return true;
}
if (FileSys::GetBaseTitleID(program_id) != program_id &&
remove_from_root(
fs_controller.GetSDMCModificationLoadRoot(FileSys::GetBaseTitleID(program_id)))) {
return true;
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(program_id);
if (sdmc_mod_dir != nullptr) {
return sdmc_mod_dir->DeleteSubdirectoryRecursive(mod_name);
}
return false;
+1 -2
View File
@@ -7,7 +7,6 @@
#include "common/fs/fs.h"
#include "common/fs/fs_types.h"
#include "common/logging.h"
#include "core/file_sys/common_funcs.h"
#include "frontend_common/data_manager.h"
#include "mod_manager.h"
@@ -41,7 +40,7 @@ std::vector<std::filesystem::path> GetModFolder(const std::string& root) {
}
ModInstallResult InstallMod(const std::filesystem::path& path, const u64 program_id, const bool copy) {
const auto program_id_string = fmt::format("{:016X}", FileSys::GetBaseTitleID(program_id));
const auto program_id_string = fmt::format("{:016X}", program_id);
const auto mod_name = path.filename();
const auto mod_dir =
DataManager::GetDataDir(DataManager::DataDir::Mods) / program_id_string / mod_name;
+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 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -65,9 +62,8 @@ void HidbusBase::DisablePollingMode() {
polling_mode_enabled = false;
}
void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem, Kernel::KProcess* owner) {
void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
transfer_memory = t_mem;
transfer_memory_owner = owner;
}
Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const {
+1 -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 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -17,7 +14,6 @@ class System;
namespace Kernel {
class KEvent;
class KProcess;
class KReadableEvent;
} // namespace Kernel
@@ -142,7 +138,7 @@ public:
void DisablePollingMode();
// Called on EnableJoyPollingReceiveMode
void SetTransferMemoryAddress(Common::ProcessAddress t_mem, Kernel::KProcess* owner);
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
Kernel::KReadableEvent& GetSendCommandAsycEvent() const;
@@ -179,7 +175,6 @@ protected:
ButtonOnlyPollingDataAccessor button_only_data{};
Common::ProcessAddress transfer_memory{};
Kernel::KProcess* transfer_memory_owner{};
Core::System& system;
Kernel::KEvent* send_command_async_event;
+2 -5
View File
@@ -6,7 +6,6 @@
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/memory.h"
#include "hid_core/frontend/emulated_controller.h"
@@ -68,10 +67,8 @@ void RingController::OnUpdate() {
curr_entry.polling_data.out_size = sizeof(ringcon_value);
std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value));
if (transfer_memory_owner != nullptr) {
transfer_memory_owner->GetMemory().WriteBlock(transfer_memory, &enable_sixaxis_data,
sizeof(enable_sixaxis_data));
}
system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data,
sizeof(enable_sixaxis_data));
break;
}
default:

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