Compare commits

...

12 Commits

Author SHA1 Message Date
Caio Oliveira
0490529a01 adapt to upstream changes
Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-12-18 22:52:50 +01:00
lizzie
c7a7fe15e5 do not register handlers for fastmem if fastmem is disabled
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-12-18 22:52:50 +01:00
Maufeat
1d869e8495 [hle] stubbed extra services from (parental controls and stuff) fw21 (#3175)
Adds more Firmware 20+ related service commands.
Renames existing service commands according to switchbrew docs,
Unstubs new parental service stuff.

Signed-off-by: lizzie lizzie@eden-emu.dev

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3175
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
2025-12-18 21:46:00 +01:00
lizzie
959f72297d [vk] use boost::container::deque instead of std::queue for presentation swapchain of frames (#3120)
This may reduce total overhead (as benchmarks show boost::container::deque being better performing than std::deque, especially with the limited set of ops like push_front and pop_back
May actually not help at all and be worse through, as always, performance tests are welcome

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3120
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-12-18 11:29:38 +01:00
Caio Oliveira
057d566ff4 [FIXUP] Partially revert "[dynarmic] allow better dtrace diagnostics for code - do not clobber %rbp and save frame pointer (#2653)" (#3176)
This partially reverts commit 50f8d4130d.

Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3176
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-12-18 00:09:42 +01:00
Lizzie
be592f0ab3 [dist, docs] Revolt renames itself to Stoat, change rvlt.gg to stt.gg (#2656)
No badges.io yet, no new SVG logo from them

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2656
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: Lizzie <lizzie@eden-emu.dev>
Co-committed-by: Lizzie <lizzie@eden-emu.dev>
2025-12-17 14:36:35 +01:00
Maufeat
bf68eede05 [bsd, ssl] fix connection between bsd:u and bsd:s and file descriptor copy (#3172)
as seen in repeated epic games api connection in sonic

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3172
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
2025-12-17 06:32:22 +01:00
Maufeat
1eed7efd09 [core, display, overlay] Add LayerIsOverlay to separate overlay on composer, stub RequestListSummaryOverlayNotification, sync emu settings when setting language (#3123)
This should fix the issue with, for example, ToTK running at 60 FPS when overlay applet is running.
This also should always run the overlay as actual overlay and not in the back.
Stubs RequestListSummaryOverlayNotifications in friends
Syncs Language of the Emulator, when setting language, this is used in Starter Applet

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3123
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
2025-12-17 06:26:02 +01:00
lizzie
50f8d4130d [dynarmic] allow better dtrace diagnostics for code - do not clobber %rbp and save frame pointer (#2653)
Saving the %rbp pointer allows us to backref previous stackframes easily

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2653
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-12-17 05:41:11 +01:00
Producdevity
e4dccd5a5c [android] setting to auto hide overlay on controller input (#3127)
Setting `HIDE_OVERLAY_ON_CONTROLLER_INPUT` in *Advanced settings → Input Overlay*

**Behavior:**
  - First controller input  -> hides overlay
  - Controller disconnect → shows overlay again
  - Subsequent controller inputs → ignored (already hidden, so no retrigger needed)
  - Touch screen → does **not** show overlay (so you can use a controller and touchscreen to interact with games)
  - Sidebar "Show/Hide controller" button → still works as master toggle

**State reset: The "first input" detection resets when:**
  1. Controller disconnects
  2. Overlay is shown via sidebar button
  3. Controller reconnects

**Interaction with other settings:**
  - Requires `SHOW_INPUT_OVERLAY` to be enabled (basicaly a master switch)
  - Independent from `ENABLE_INPUT_OVERLAY_AUTO_HIDE` (timer-based hide, was already implemented)
  - When both are enabled, touch-to-show is disabled (controller-hide takes precedence)

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3127
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Producdevity <y.gherbi.dev@gmail.com>
Co-committed-by: Producdevity <y.gherbi.dev@gmail.com>
2025-12-17 03:59:46 +01:00
Kleidis
b9530ae80f [core] Add overridable game setting functionality (#2963)
Adds a place to override specific game settings for specific vendors

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2963
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Kleidis <kleidis1@protonmail.com>
Co-committed-by: Kleidis <kleidis1@protonmail.com>
2025-12-17 03:59:27 +01:00
lizzie
5130185d12 [vk] avoid calling vkENumerateInstanceFeatures multiple times in init code (#3147)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3147
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-12-17 03:58:30 +01:00
77 changed files with 1456 additions and 694 deletions

2
.gitignore vendored
View File

@@ -37,6 +37,8 @@ CMakeLists.txt.user*
# *nix related
# Common convention for backup or temporary files
*~
*.core
dtrace-out/
# Visual Studio CMake settings
CMakeSettings.json

View File

@@ -25,9 +25,9 @@ It is written in C++ with portability in mind, and we actively maintain builds f
<img src="https://img.shields.io/discord/1367654015269339267?color=5865F2&label=Eden&logo=discord&logoColor=white"
alt="Discord">
</a>
<a href="https://rvlt.gg/qKgFEAbH">
<img src="https://img.shields.io/revolt/invite/qKgFEAbH?color=d61f3a&label=Revolt"
alt="Revolt">
<a href="https://stt.gg/qKgFEAbH">
<img src="https://img.shields.io/revolt/invite/qKgFEAbH?color=d61f3a&label=Stoat"
alt="Stoat">
</a>
</p>
@@ -52,10 +52,10 @@ Check out our [website](https://eden-emu.dev) for the latest news on exciting fe
## Development
Most of the development happens on our Git server. It is also where [our central repository](https://git.eden-emu.dev/eden-emu/eden) is hosted. For development discussions, please join us on [Discord](https://discord.gg/HstXbPch7X) or [Revolt](https://rvlt.gg/qKgFEAbH).
Most of the development happens on our Git server. It is also where [our central repository](https://git.eden-emu.dev/eden-emu/eden) is hosted. For development discussions, please join us on [Discord](https://discord.gg/HstXbPch7X) or [Stoat](https://stt.gg/qKgFEAbH).
You can also follow us on [X (Twitter)](https://nitter.poast.org/edenemuofficial) for updates and announcements.
If you would like to contribute, we are open to new developers and pull requests. Please ensure that your work is of a high standard and properly documented. You can also contact any of the developers on Discord or Revolt to learn more about the current state of the emulator.
If you would like to contribute, we are open to new developers and pull requests. Please ensure that your work is of a high standard and properly documented. You can also contact any of the developers on Discord or Stoat to learn more about the current state of the emulator.
See the [sign-up instructions](docs/SIGNUP.md) for information on registration.

View File

@@ -137,7 +137,7 @@ If your initial configure failed:
- Evaluate the error and find any related settings
- See the [CPM docs](CPM.md) to see if you may need to forcefully bundle any packages
Otherwise, feel free to ask for help in Revolt or Discord.
Otherwise, feel free to ask for help in Stoat or Discord.
## Caveats

View File

@@ -18,6 +18,7 @@ import android.content.IntentFilter
import android.content.res.Configuration
import android.graphics.Rect
import android.graphics.drawable.Icon
import android.hardware.input.InputManager
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
@@ -63,11 +64,12 @@ import kotlin.math.roundToInt
import org.yuzu.yuzu_emu.utils.ForegroundService
import androidx.core.os.BundleCompat
class EmulationActivity : AppCompatActivity(), SensorEventListener {
class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager.InputDeviceListener {
private lateinit var binding: ActivityEmulationBinding
var isActivityRecreated = false
private lateinit var nfcReader: NfcReader
private lateinit var inputManager: InputManager
private var touchDownTime: Long = 0
private val maxTapDuration = 500L
@@ -140,6 +142,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
nfcReader = NfcReader(this)
nfcReader.initialize()
inputManager = getSystemService(INPUT_SERVICE) as InputManager
inputManager.registerInputDeviceListener(this, null)
foregroundService = Intent(this, ForegroundService::class.java)
startForegroundService(foregroundService)
@@ -206,9 +211,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onDestroy() {
super.onDestroy()
inputManager.unregisterInputDeviceListener(this)
stopForegroundService(this)
NativeLibrary.playTimeManagerStop()
}
override fun onUserLeaveHint() {
@@ -244,8 +249,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
val isPhysicalKeyboard = event.source and InputDevice.SOURCE_KEYBOARD == InputDevice.SOURCE_KEYBOARD &&
event.device?.isVirtual == false
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
val isControllerInput = event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK ||
event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD
if (!isControllerInput &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE &&
!isPhysicalKeyboard
) {
@@ -256,12 +263,18 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
return super.dispatchKeyEvent(event)
}
if (isControllerInput && event.action == KeyEvent.ACTION_DOWN) {
notifyControllerInput()
}
return InputHandler.dispatchKeyEvent(event)
}
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
val isControllerInput = event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK ||
event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD
if (!isControllerInput &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) {
@@ -277,9 +290,54 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
return true
}
if (isControllerInput) {
notifyControllerInput()
}
return InputHandler.dispatchGenericMotionEvent(event)
}
private fun notifyControllerInput() {
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
val emulationFragment =
navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
emulationFragment?.onControllerInputDetected()
}
private fun isGameController(deviceId: Int): Boolean {
val device = InputDevice.getDevice(deviceId) ?: return false
val sources = device.sources
return sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD ||
sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK
}
override fun onInputDeviceAdded(deviceId: Int) {
if (isGameController(deviceId)) {
InputHandler.updateControllerData()
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
val emulationFragment =
navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
emulationFragment?.onControllerConnected()
}
}
override fun onInputDeviceRemoved(deviceId: Int) {
InputHandler.updateControllerData()
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
val emulationFragment =
navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
emulationFragment?.onControllerDisconnected()
}
override fun onInputDeviceChanged(deviceId: Int) {
if (isGameController(deviceId)) {
InputHandler.updateControllerData()
}
}
override fun onSensorChanged(event: SensorEvent) {
val rotation = this.display?.rotation
if (rotation == Surface.ROTATION_90) {
@@ -519,8 +577,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
touchDownTime = System.currentTimeMillis()
// show overlay immediately on touch and cancel timer
if (!emulationViewModel.drawerOpen.value) {
// show overlay immediately on touch and cancel timer when only auto-hide is enabled
if (!emulationViewModel.drawerOpen.value &&
BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean() &&
!BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT.getBoolean()) {
fragment.handler.removeCallbacksAndMessages(null)
fragment.showOverlay()
}

View File

@@ -52,6 +52,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SOC_OVERLAY_BACKGROUND("soc_overlay_background"),
ENABLE_INPUT_OVERLAY_AUTO_HIDE("enable_input_overlay_auto_hide"),
HIDE_OVERLAY_ON_CONTROLLER_INPUT("hide_overlay_on_controller_input"),
PERF_OVERLAY_BACKGROUND("perf_overlay_background"),
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),

View File

@@ -387,6 +387,13 @@ abstract class SettingsItem(
valueHint = R.string.seconds
)
)
put(
SwitchSetting(
BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT,
titleId = R.string.hide_overlay_on_controller_input,
descriptionId = R.string.hide_overlay_on_controller_input_description
)
)
put(
SwitchSetting(

View File

@@ -274,6 +274,7 @@ class SettingsFragmentPresenter(
sl.apply {
add(BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.key)
add(IntSetting.INPUT_OVERLAY_AUTO_HIDE.key)
add(BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT.key)
}
}

View File

@@ -100,7 +100,7 @@ class AboutFragment : Fragment() {
}
binding.buttonDiscord.setOnClickListener { openLink(getString(R.string.discord_link)) }
binding.buttonRevolt.setOnClickListener { openLink(getString(R.string.revolt_link)) }
binding.buttonStoat.setOnClickListener { openLink(getString(R.string.stoat_link)) }
binding.buttonX.setOnClickListener { openLink(getString(R.string.x_link)) }
binding.buttonWebsite.setOnClickListener { openLink(getString(R.string.website_link)) }
binding.buttonGithub.setOnClickListener { openLink(getString(R.string.github_link)) }

View File

@@ -93,7 +93,6 @@ import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.utils.CustomSettingsHandler
import java.io.ByteArrayOutputStream
import java.io.File
import kotlin.coroutines.coroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@@ -106,6 +105,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
val handler = Handler(Looper.getMainLooper())
private var isOverlayVisible = true
private var controllerInputReceived = false
private var _binding: FragmentEmulationBinding? = null
@@ -656,6 +656,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(newState)
updateQuickOverlayMenuEntry(newState)
binding.surfaceInputOverlay.refreshControls()
// Sync view visibility with the setting
if (newState) {
showOverlay()
} else {
hideOverlay()
}
NativeConfig.saveGlobalConfig()
true
}
@@ -1901,7 +1907,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
companion object {
fun fromValue(value: Int): AmiiboState =
values().firstOrNull { it.value == value } ?: Disabled
entries.firstOrNull { it.value == value } ?: Disabled
}
}
@@ -1914,7 +1920,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
companion object {
fun fromValue(value: Int): AmiiboLoadResult =
values().firstOrNull { it.value == value } ?: Unknown
entries.firstOrNull { it.value == value } ?: Unknown
}
}
@@ -1971,6 +1977,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
fun showOverlay() {
if (!isOverlayVisible) {
isOverlayVisible = true
// Reset controller input flag so controller can hide overlay again
controllerInputReceived = false
ViewUtils.showView(binding.surfaceInputOverlay, 500)
}
}
@@ -1978,7 +1986,26 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private fun hideOverlay() {
if (isOverlayVisible) {
isOverlayVisible = false
ViewUtils.hideView(binding.surfaceInputOverlay, 500)
ViewUtils.hideView(binding.surfaceInputOverlay)
}
}
fun onControllerInputDetected() {
if (!BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT.getBoolean()) return
if (!BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) return
if (controllerInputReceived) return
controllerInputReceived = true
hideOverlay()
}
fun onControllerConnected() {
controllerInputReceived = false
}
fun onControllerDisconnected() {
if (!BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT.getBoolean()) return
if (!BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) return
controllerInputReceived = false
showOverlay()
}
}

View File

@@ -92,6 +92,11 @@ namespace AndroidSettings {
Settings::Setting<u32> input_overlay_auto_hide{linkage, 5, "input_overlay_auto_hide",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true, &enable_input_overlay_auto_hide};
Settings::Setting<bool> hide_overlay_on_controller_input{linkage, false,
"hide_overlay_on_controller_input",
Settings::Category::Overlay,
Settings::Specialization::Default, true,
true};
Settings::Setting<bool> perf_overlay_background{linkage, false, "perf_overlay_background",
Settings::Category::Overlay,
Settings::Specialization::Default, true,

View File

@@ -220,12 +220,12 @@
app:iconPadding="0dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_revolt"
android:id="@+id/button_stoat"
style="@style/EdenButton.Secondary"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginEnd="12dp"
app:icon="@drawable/ic_revolt"
app:icon="@drawable/ic_stoat"
app:iconGravity="textStart"
app:iconSize="24dp"
app:iconPadding="0dp" />
@@ -270,4 +270,4 @@
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -215,12 +215,12 @@
<com.google.android.material.button.MaterialButton
style="@style/EdenButton.Secondary"
android:id="@+id/button_revolt"
android:id="@+id/button_stoat"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
app:icon="@drawable/ic_revolt"
app:icon="@drawable/ic_stoat"
app:iconSize="24dp"
app:iconGravity="textStart"
app:iconPadding="0dp" />
@@ -235,7 +235,7 @@
app:icon="@drawable/ic_x"
app:iconSize="24dp"
app:iconGravity="textStart"
app:iconPadding="0dp" />
app:iconPadding="0dp" />
<com.google.android.material.button.MaterialButton
style="@style/EdenButton.Secondary"
@@ -267,4 +267,4 @@
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -26,6 +26,8 @@
<string name="overlay_auto_hide">Overlay Auto Hide</string>
<string name="overlay_auto_hide_description">Automatically hide the touch controls overlay after the specified time of inactivity.</string>
<string name="enable_input_overlay_auto_hide">Enable Overlay Auto Hide</string>
<string name="hide_overlay_on_controller_input">Hide Overlay on Controller Input</string>
<string name="hide_overlay_on_controller_input_description">Automatically hide the touch controls overlay when a physical controller is used. Overlay reappears when controller is disconnected.</string>
<string name="input_overlay_options">Input Overlay</string>
<string name="input_overlay_options_description">Configure on-screen controls</string>
@@ -445,7 +447,7 @@
<string name="user_data_export_cancelled">Export cancelled</string>
<string name="user_data_import_failed_description">Make sure the user data folders are at the root of the zip folder and contain a config file at config/config.ini and try again.</string>
<string name="discord_link" translatable="false">https://discord.gg/HstXbPch7X</string>
<string name="revolt_link" translatable="false">https://rvlt.gg/qKgFEAbH</string>
<string name="stoat_link" translatable="false">https://stt.gg/qKgFEAbH</string>
<string name="x_link" translatable="false">https://nitter.poast.org/edenemuofficial</string>
<string name="website_link" translatable="false">https://eden-emu.dev</string>
<string name="github_link" translatable="false">https://git.eden-emu.dev/eden-emu</string>

View File

@@ -17,6 +17,8 @@ add_library(core STATIC
constants.h
core.cpp
core.h
game_settings.cpp
game_settings.h
core_timing.cpp
core_timing.h
cpu_manager.cpp

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <utility>
#include "game_settings.h"
#include "audio_core/audio_core.h"
#include "common/fs/fs.h"
#include "common/logging/log.h"
@@ -292,48 +293,6 @@ struct System::Impl {
return SystemResultStatus::Success;
}
void LoadOverrides(u64 programId) const {
std::string vendor = gpu_core->Renderer().GetDeviceVendor();
LOG_INFO(Core, "GPU Vendor: {}", vendor);
// Reset all per-game flags
Settings::values.use_squashed_iterated_blend = false;
// Insert PC overrides here
#ifdef ANDROID
// Example on how to set a setting based on the program ID and vendor
if (programId == 0x010028600EBDA000 && vendor == "Mali") { // Mario 3d World
// Settings::values.example = true;
}
// Example array of program IDs
const std::array<u64, 10> example_array = {
//0xprogramId
0x0004000000033400, // Game 1
0x0004000000033500 // Game 2
// And so on
};
for (auto id : example_array) {
if (programId == id) {
// Settings::values.example = true;
break;
}
}
#endif
// Ninja Gaiden Ragebound
constexpr u64 ngr = 0x0100781020710000ULL;
if (programId == ngr) {
LOG_INFO(Core, "Enabling game specifc override: use_squashed_iterated_blend");
Settings::values.use_squashed_iterated_blend = true;
}
}
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath,
Service::AM::FrontendAppletParameters& params) {
@@ -419,7 +378,8 @@ struct System::Impl {
LOG_ERROR(Core, "Failed to find program id for ROM");
}
LoadOverrides(program_id);
GameSettings::LoadOverrides(program_id, gpu_core->Renderer());
if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info;
game_info.name = name;

140
src/core/game_settings.cpp Normal file
View File

@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/game_settings.h"
#include <algorithm>
#include <cctype>
#include "common/logging/log.h"
#include "common/settings.h"
#include "video_core/renderer_base.h"
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
namespace Core::GameSettings {
static GPUVendor GetGPU(const std::string& gpu_vendor_string) {
struct Entry { const char* name; GPUVendor vendor; };
static constexpr Entry GpuVendor[] = {
// NVIDIA
{"NVIDIA", GPUVendor::Nvidia},
{"Nouveau", GPUVendor::Nvidia},
{"NVK", GPUVendor::Nvidia},
{"Tegra", GPUVendor::Nvidia},
// AMD
{"AMD", GPUVendor::AMD},
{"RadeonSI", GPUVendor::AMD},
{"RADV", GPUVendor::AMD},
{"AMDVLK", GPUVendor::AMD},
{"R600", GPUVendor::AMD},
// Intel
{"Intel", GPUVendor::Intel},
{"ANV", GPUVendor::Intel},
{"i965", GPUVendor::Intel},
{"i915", GPUVendor::Intel},
{"OpenSWR", GPUVendor::Intel},
// Apple
{"Apple", GPUVendor::Apple},
{"MoltenVK", GPUVendor::Apple},
// Qualcomm / Adreno
{"Qualcomm", GPUVendor::Qualcomm},
{"Turnip", GPUVendor::Qualcomm},
// ARM / Mali
{"Mali", GPUVendor::ARM},
{"PanVK", GPUVendor::ARM},
// Imagination / PowerVR
{"PowerVR", GPUVendor::Imagination},
{"PVR", GPUVendor::Imagination},
// Microsoft / WARP / D3D12 GL
{"D3D12", GPUVendor::Microsoft},
{"Microsoft", GPUVendor::Microsoft},
{"WARP", GPUVendor::Microsoft},
};
for (const auto& entry : GpuVendor) {
if (gpu_vendor_string == entry.name) {
return entry.vendor;
}
}
// legacy (shouldn't be needed anymore, but just in case)
std::string gpu = gpu_vendor_string;
std::transform(gpu.begin(), gpu.end(), gpu.begin(), [](unsigned char c){ return (char)std::tolower(c); });
if (gpu.find("geforce") != std::string::npos) {
return GPUVendor::Nvidia;
}
if (gpu.find("radeon") != std::string::npos || gpu.find("ati") != std::string::npos) {
return GPUVendor::AMD;
}
return GPUVendor::Unknown;
}
static OS DetectOS() {
#if defined(_WIN32)
return OS::Windows;
#elif defined(__FIREOS__)
return OS::FireOS;
#elif defined(__ANDROID__)
return OS::Android;
#elif defined(__OHOS__)
return OS::HarmonyOS;
#elif defined(__HAIKU__)
return OS::HaikuOS;
#elif defined(__DragonFly__)
return OS::DragonFlyBSD;
#elif defined(__NetBSD__)
return OS::NetBSD;
#elif defined(__OpenBSD__)
return OS::OpenBSD;
#elif defined(_AIX)
return OS::AIX;
#elif defined(__managarm__)
return OS::Managarm;
#elif defined(__redox__)
return OS::RedoxOS;
#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
return OS::IOS;
#elif defined(__APPLE__)
return OS::MacOS;
#elif defined(__FreeBSD__)
return OS::FreeBSD;
#elif defined(__sun) && defined(__SVR4)
return OS::Solaris;
#elif defined(__linux__)
return OS::Linux;
#else
return OS::Unknown;
#endif
}
EnvironmentInfo DetectEnvironment(const VideoCore::RendererBase& renderer) {
EnvironmentInfo env{};
env.os = DetectOS();
env.vendor_string = renderer.GetDeviceVendor();
env.vendor = GetGPU(env.vendor_string);
return env;
}
void LoadOverrides(std::uint64_t program_id, const VideoCore::RendererBase& renderer) {
const auto env = DetectEnvironment(renderer);
switch (static_cast<TitleID>(program_id)) {
case TitleID::NinjaGaidenRagebound:
Settings::values.use_squashed_iterated_blend = true;
break;
default:
break;
}
LOG_INFO(Core, "Applied game settings for title ID {:016X} on OS {}, GPU vendor {} ({})",
program_id,
static_cast<int>(env.os),
static_cast<int>(env.vendor),
env.vendor_string);
}
} // namespace Core::GameSettings

60
src/core/game_settings.h Normal file
View File

@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <cstdint>
#include <string>
namespace VideoCore { class RendererBase; }
namespace Core::GameSettings {
enum class OS {
Windows,
Linux,
MacOS,
IOS,
Android,
FireOS,
HarmonyOS,
FreeBSD,
DragonFlyBSD,
NetBSD,
OpenBSD,
HaikuOS,
AIX,
Managarm,
RedoxOS,
Solaris,
Unknown,
};
enum class GPUVendor {
Nvidia,
AMD,
Intel,
Apple,
Qualcomm,
ARM,
Imagination,
Microsoft,
Unknown,
};
enum class TitleID : std::uint64_t {
NinjaGaidenRagebound = 0x0100781020710000ULL
};
struct EnvironmentInfo {
OS os{OS::Unknown};
GPUVendor vendor{GPUVendor::Unknown};
std::string vendor_string; // raw string from driver
};
EnvironmentInfo DetectEnvironment(const VideoCore::RendererBase& renderer);
void LoadOverrides(std::uint64_t program_id, const VideoCore::RendererBase& renderer);
} // namespace Core::GameSettings

View File

@@ -12,7 +12,7 @@
#include "common/common_types.h"
#include "common/expected.h"
// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes
// All the constants in this file come from <http://switchbrew.org/index.php?title=Error_codes>
/**
* Identifies the module which caused the error. Error codes can be propagated through a call
@@ -87,6 +87,7 @@ enum class ErrorModule : u32 {
AM = 128,
PlayReport = 129,
AHID = 130,
APPLET = 131,
Qlaunch = 132,
PCV = 133,
USBPD = 134,
@@ -113,8 +114,8 @@ enum class ErrorModule : u32 {
NPNSHTTPSTREAM = 155,
IDLE = 156,
ARP = 157,
SWKBD = 158,
BOOT = 159,
UPDATER = 158,
SWKBD = 159,
NetDiag = 160,
NFCMifare = 161,
UserlandAssert = 162,
@@ -125,7 +126,8 @@ enum class ErrorModule : u32 {
BGTC = 167,
UserlandCrash = 168,
SASBUS = 169,
PI = 170,
PL = 170,
CDMSC = 171,
AudioCtrl = 172,
LBL = 173,
JIT = 175,
@@ -137,23 +139,30 @@ enum class ErrorModule : u32 {
Dauth = 181,
STDFU = 182,
DBG = 183,
CDACM = 184,
TCAP = 185,
DHCPS = 186,
SPI = 187,
AVM = 188,
PWM = 189,
DNSServer = 190,
RTC = 191,
Regulator = 192,
LED = 193,
HTCTool = 194,
SIO = 195,
PCM = 196,
CLKRST = 197,
POWCTL = 198,
HIDDriver = 199,
DMA = 200,
AudioOld = 201,
HID = 202,
LDN = 203,
CS = 204,
Irsensor = 205,
Capture = 206,
MM = 207,
Manu = 208,
ATK = 209,
WEB = 210,
@@ -166,19 +175,24 @@ enum class ErrorModule : u32 {
MigrationLdcServ = 217,
HIDBUS = 218,
ENS = 219,
ND = 220,
NDD = 221,
ToyCon = 222,
WebSocket = 223,
SocketIO = 224,
DCDMTP = 227,
PGL = 228,
Notification = 229,
INS = 230,
LP2P = 231,
RCD = 232,
LCM40607 = 233,
ICM40607 = 233,
PRC = 235,
TMAHTC = 237,
ECTX = 238,
BridgeCtrl = 237,
ErrContext = 238,
MNPP = 239,
HSHL = 240,
RINGCON = 241,
CAPMTP = 242,
DP2HDMI = 244,
Cradle = 245,
@@ -186,6 +200,8 @@ enum class ErrorModule : u32 {
Icm42607p = 248,
NDRM = 250,
Fst2 = 251,
TS = 253,
SPLAY = 260,
Nex = 306,
NPLN = 321,
TSPM = 499,

View File

@@ -36,10 +36,6 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
if (m_applet_id != AppletId::Application) {
(void)this->IsSystemBufferSharingEnabled();
}
}
void DisplayLayerManager::Finalize() {
@@ -80,11 +76,10 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
if (m_applet_id != AppletId::Application) {
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
if (m_applet_id == AppletId::OverlayDisplay) {
static constexpr s32 kOverlayBackgroundZ = -1;
(void)m_manager_display_service->SetLayerZIndex(kOverlayBackgroundZ, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
} else {
static constexpr s32 kOverlayZ = 3;
(void)m_manager_display_service->SetLayerZIndex(kOverlayZ, *out_layer_id);
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
}
}
@@ -131,6 +126,7 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
s32 initial_z = 1;
if (m_applet_id == AppletId::OverlayDisplay) {
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);
R_SUCCEED();

View File

@@ -88,13 +88,13 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{181, nullptr, "UpgradeLaunchRequiredVersion"},
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
{200, nullptr, "GetLastApplicationExitReason"},
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"}, // [20.0.0+]
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"}, // [20.0.0+]
{220, nullptr, "Unknown220"}, // [20.0.0+]
{300, nullptr, "Unknown300"}, // [20.0.0+]
{310, nullptr, "Unknown310"}, // [20.0.0+]
{320, nullptr, "Unknown320"}, // [20.0.0+]
{330, nullptr, "Unknown330"}, // [20.0.0+]
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"}, //20.0.0+
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"}, //20.0.0+
{220, nullptr, "Unknown220"}, //20.0.0+
{300, nullptr, "CreateMovieWriter"}, //20.0.0+
{310, nullptr, "Unknown310"}, //20.0.0+
{320, nullptr, "Unknown320"}, //20.0.0+
{330, nullptr, "Unknown330"}, //20.0.0+
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},

View File

@@ -18,7 +18,7 @@ IAudioController::IAudioController(Core::System& system_)
{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
{5, nullptr, "Unknown5"},
{5, nullptr, "Unknown5"}, //20.0.0+
};
// clang-format on

View File

@@ -24,7 +24,7 @@ namespace Service::AM {
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{21, nullptr, "SetHandlingTouchScreenInputEnabled"},
{30, nullptr, "SetHealthWarningShowingState"},
{31, nullptr, "IsHealthWarningRequired"},
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
{40, nullptr, "GetApplicationNintendoLogo"},
{41, nullptr, "GetApplicationStartupMovie"},
{50, nullptr, "SetGpuTimeSliceBoostForApplication"},
@@ -69,12 +69,33 @@ namespace Service::AM {
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
LOG_DEBUG(Service_AM, "called");
// Prefer explicit application_id if available, else fall back to program_id
std::shared_ptr<Applet> target_applet;
auto* window_system = system.GetAppletManager().GetWindowSystem();
if (window_system) {
target_applet = window_system->GetMainApplet();
if (target_applet) {
std::scoped_lock lk{target_applet->lock};
LOG_DEBUG(Service_AM, "applet_id={}, program_id={:016X}, type={}",
static_cast<u32>(target_applet->applet_id), target_applet->program_id,
static_cast<u32>(target_applet->type));
u64 id = target_applet->screen_shot_identity.application_id;
if (id == 0) {
id = target_applet->program_id;
}
LOG_DEBUG(Service_AM, "application_id={:016X}", id);
*out_application_id = id;
R_SUCCEED();
}
}
std::scoped_lock lk{m_applet->lock};
u64 id = m_applet->screen_shot_identity.application_id;
if (id == 0) {
id = m_applet->program_id;
}
LOG_DEBUG(Service_AM, "application_id={:016X} (fallback)", id);
*out_application_id = id;
R_SUCCEED();
}
@@ -86,6 +107,13 @@ namespace Service::AM {
R_SUCCEED();
}
Result IOverlayFunctions::IsHealthWarningRequired(Out<bool> is_required) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
*is_required = false;
R_SUCCEED();
}
Result IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled(bool enabled) {
LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};

View File

@@ -18,6 +18,7 @@ namespace Service::AM {
Result EndToWatchShortHomeButtonMessage();
Result GetApplicationIdForLogo(Out<u64> out_application_id);
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
Result IsHealthWarningRequired(Out<bool> is_required);
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
Result Unknown70();

View File

@@ -186,8 +186,6 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) {
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;
// Tie window visibility to foreground state so hidden when not active
m_overlay_display->window_visible = 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);
@@ -393,7 +391,7 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
s32 z_index = 0;
const bool now_foreground = inherited_foreground;
if (applet->applet_id == AppletId::OverlayDisplay) {
z_index = applet->overlay_in_foreground ? 100000 : -100000;
z_index = applet->overlay_in_foreground ? 100000 : -1;
} else if (now_foreground && !is_obscured) {
z_index = 2;
} else if (now_foreground) {

View File

@@ -30,7 +30,7 @@ IAudioController::IAudioController(Core::System& system_)
{3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{4, D<&IAudioController::IsTargetMute>, "IsTargetMute"},
{5, D<&IAudioController::SetTargetMute>, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{6, nullptr, "IsTargetConnected"}, //20.0.0+
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
{9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
@@ -67,7 +67,8 @@ IAudioController::IAudioController(Core::System& system_)
{40, nullptr, "GetSystemInformationForDebug"},
{41, nullptr, "SetVolumeButtonLongPressTime"},
{42, nullptr, "SetNativeVolumeForDebug"},
{5000, D<&IAudioController::Unknown5000>, "Unknown5000"},
{43, nullptr, "Unknown43"}, //21.0.0+
{5000, D<&IAudioController::Unknown5000>, "Unknown5000"}, //19.0.0+
{10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
{10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
{10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
@@ -76,13 +77,13 @@ IAudioController::IAudioController(Core::System& system_)
{10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
{10103, nullptr, "GetAudioOutputTargetForPlayReport"},
{10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
{10200, nullptr, "Unknown10200"}, // [20.0.0+]
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
{50001, nullptr, "OverrideDefaultTargetForDebug"},
{50003, nullptr, "SetForceOverrideExternalDeviceNameForDebug"},
{50004, nullptr, "ClearForceOverrideExternalDeviceNameForDebug"}
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, //14.0.0-19.0.1
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"}, //14.0.0-19.0.1
{10200, nullptr, "Unknown10200"}, //20.0.0+
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"}, //15.0.0-18.1.0
{50001, nullptr, "OverrideDefaultTargetForDebug"}, //19.0.0-19.0.1
{50003, nullptr, "SetForceOverrideExternalDeviceNameForDebug"}, //19.0.0+
{50004, nullptr, "ClearForceOverrideExternalDeviceNameForDebug"} //19.0.0+
};
// clang-format on

View File

@@ -32,13 +32,13 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
{15, nullptr, "AcquireAudioInputDeviceNotification"}, // 17.0.0+
{16, nullptr, "ReleaseAudioInputDeviceNotification"}, // 17.0.0+
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, // 17.0.0+
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, // 17.0.0+
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
{21, nullptr, "IsActiveOutputDeviceEstimatedLowLatency"} // 21.0.0+
{15, nullptr, "AcquireAudioInputDeviceNotification"}, //17.0.0+
{16, nullptr, "ReleaseAudioInputDeviceNotification"}, //17.0.0+
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, //17.0.0+
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, //17.0.0+
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, //18.0.0+
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"}, //18.0.0+
{21, nullptr, "IsActiveOutputDeviceEstimatedLowLatency"} //21.0.0+
};
RegisterHandlers(functions);

View File

@@ -43,21 +43,21 @@ IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
{20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
{20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
{30100, D<&IBcatService::SetPassphrase>, "SetPassphrase"},
{30101, nullptr, "Unknown30101"},
{30102, nullptr, "Unknown30102"},
{30101, nullptr, "Unknown30101"}, //2.0.0-2.3.0
{30102, nullptr, "Unknown30102"}, //2.0.0-2.3.0
{30200, nullptr, "RegisterBackgroundDeliveryTask"},
{30201, nullptr, "UnregisterBackgroundDeliveryTask"},
{30202, nullptr, "BlockDeliveryTask"},
{30203, nullptr, "UnblockDeliveryTask"},
{30210, nullptr, "SetDeliveryTaskTimer"},
{30300, D<&IBcatService::RegisterSystemApplicationDeliveryTasks>, "RegisterSystemApplicationDeliveryTasks"},
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
{90101, nullptr, "Unknown90101"},
{90100, nullptr, "GetDeliveryTaskList"},
{90101, nullptr, "GetDeliveryTaskListForSystem"}, //11.0.0+
{90200, nullptr, "GetDeliveryList"},
{90201, D<&IBcatService::ClearDeliveryCacheStorage>, "ClearDeliveryCacheStorage"},
{90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
{90300, nullptr, "GetPushNotificationLog"},
{90301, nullptr, "Unknown90301"},
{90301, nullptr, "GetDeliveryCacheStorageUsage"}, //11.0.0+
};
// clang-format on
RegisterHandlers(functions);

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -12,19 +15,19 @@ INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "I
{10100, D<&INewsService::PostLocalNews>, "PostLocalNews"},
{20100, nullptr, "SetPassphrase"},
{30100, D<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"},
{30101, nullptr, "GetTopicList"},
{30110, nullptr, "Unknown30110"},
{30101, nullptr, "GetTopicList"}, //3.0.0+
{30110, nullptr, "Unknown30110"}, //6.0.0+
{30200, D<&INewsService::IsSystemUpdateRequired>, "IsSystemUpdateRequired"},
{30201, nullptr, "Unknown30201"},
{30210, nullptr, "Unknown30210"},
{30201, nullptr, "Unknown30201"}, //8.0.0+
{30210, nullptr, "Unknown30210"}, //10.0.0+
{30300, nullptr, "RequestImmediateReception"},
{30400, nullptr, "DecodeArchiveFile"},
{30500, nullptr, "Unknown30500"},
{30900, nullptr, "Unknown30900"},
{30901, nullptr, "Unknown30901"},
{30902, nullptr, "Unknown30902"},
{30400, nullptr, "DecodeArchiveFile"}, //3.0.0-18.1.0
{30500, nullptr, "Unknown30500"}, //8.0.0+
{30900, nullptr, "Unknown30900"}, //1.0.0
{30901, nullptr, "Unknown30901"}, //1.0.0
{30902, nullptr, "Unknown30902"}, //1.0.0
{40100, nullptr, "SetSubscriptionStatus"},
{40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"},
{40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"}, //3.0.0+
{40200, nullptr, "ClearStorage"},
{40201, nullptr, "ClearSubscriptionStatusAll"},
{90100, nullptr, "GetNewsDatabaseDump"},

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -77,31 +80,33 @@ public:
{57, nullptr, "RegisterAppletResourceUserId"},
{58, nullptr, "UnregisterAppletResourceUserId"},
{59, nullptr, "SetAppletResourceUserId"},
{60, nullptr, "Unknown60"},
{61, nullptr, "Unknown61"},
{62, nullptr, "Unknown62"},
{63, nullptr, "Unknown63"},
{64, nullptr, "Unknown64"},
{65, nullptr, "Unknown65"},
{66, nullptr, "Unknown66"},
{67, nullptr, "Unknown67"},
{68, nullptr, "Unknown68"},
{69, nullptr, "Unknown69"},
{70, nullptr, "Unknown70"},
{71, nullptr, "Unknown71"},
{72, nullptr, "Unknown72"},
{73, nullptr, "Unknown73"},
{74, nullptr, "Unknown74"},
{75, nullptr, "Unknown75"},
{76, nullptr, "Unknown76"},
{100, nullptr, "Unknown100"},
{101, nullptr, "Unknown101"},
{110, nullptr, "Unknown110"},
{111, nullptr, "Unknown111"},
{112, nullptr, "Unknown112"},
{113, nullptr, "Unknown113"},
{114, nullptr, "Unknown114"},
{115, nullptr, "Unknown115"},
{60, nullptr, "AcquireBleConnectionParameterUpdateEvent"}, //8.0.0+
{61, nullptr, "SetCeLength"}, //8.0.0+
{62, nullptr, "EnsureSlotExpansion"}, //9.0.0+
{63, nullptr, "IsSlotExpansionEnsured"}, //9.0.0+
{64, nullptr, "CancelConnectionTrigger"}, //10.0.0+
{65, nullptr, "GetConnectionCapacity"}, //13.0.0+
{66, nullptr, "GetWlanMode"}, //13.0.0+
{67, nullptr, "IsSlotSavingEnabled"}, //13.0.0+
{68, nullptr, "IsSlotSavingForPairingEnabled"}, //13.0.0+
{69, nullptr, "AcquireAudioDeviceConnectionEvent"}, //13.0.0+
{70, nullptr, "GetConnectedAudioDevices"}, //13.0.0+
{71, nullptr, "SetAudioSourceVolume"}, //13.0.0+
{72, nullptr, "GetAudioSourceVolume"}, //13.0.0+
{73, nullptr, "RequestAudioDeviceConnectionRejection"}, //13.0.0+
{74, nullptr, "CancelAudioDeviceConnectionRejection"}, //13.0.0+
{75, nullptr, "GetPairedAudioDevices"}, //13.0.0+
{76, nullptr, "SetWlanModeWithOption"}, //13.1.0+
{100, nullptr, "AcquireConnectionDisallowedEvent"}, //13.0.0+
{101, nullptr, "GetUsecaseViolationFactor"}, //13.0.0+
{110, nullptr, "GetShortenedDeviceInfo"}, //13.0.0+
{111, nullptr, "AcquirePairingCountUpdateEvent"},//13.0.0+
{112, nullptr, "Unknown112"}, //14.0.0-14.1.2
{113, nullptr, "Unknown113"}, //14.0.0-14.1.2
{114, nullptr, "IsFirstAudioControlConnection"}, //14.0.0+
{115, nullptr, "GetShortenedDeviceCondition"}, //14.0.0+
{116, nullptr, "SetAudioSinkVolume"}, //15.0.0+
{117, nullptr, "GetAudioSinkVolume"}, //15.0.0+
};
// clang-format on

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -17,11 +20,15 @@ IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg
{6, nullptr, "SetTsiMode"},
{7, nullptr, "GeneralTest"},
{8, nullptr, "HidConnect"},
{9, nullptr, "GeneralGet"},
{10, nullptr, "GetGattClientDisconnectionReason"},
{11, nullptr, "GetBleConnectionParameter"},
{12, nullptr, "GetBleConnectionParameterRequest"},
{13, nullptr, "Unknown13"},
{9, nullptr, "GeneralGet"}, //5.0.0+
{10, nullptr, "GetGattClientDisconnectionReason"}, //5.0.0+
{11, nullptr, "GetBleConnectionParameter"}, //5.1.0+
{12, nullptr, "GetBleConnectionParameterRequest"}, //5.1.0+
{13, nullptr, "GetDiscoveredDevice"}, //12.0.0+
{14, nullptr, "SleepAwakeLoopTest"}, //15.0.0+
{15, nullptr, "SleepTest"}, //15.0.0+
{16, nullptr, "MinimumAwakeTest"}, //15.0.0+
{17, nullptr, "ForceEnableBtm"}, //15.0.0+
};
// clang-format on

View File

@@ -60,6 +60,16 @@ public:
{38, nullptr, "OwnTicket3"},
{39, nullptr, "DeleteAllInactivePersonalizedTicket"},
{40, nullptr, "DeletePrepurchaseRecordByNintendoAccountId"},
{101, nullptr, "Unknown101"}, //18.0.0+
{102, nullptr, "Unknown102"}, //18.0.0+
{103, nullptr, "Unknown103"}, //18.0.0+
{104, nullptr, "Unknown104"}, //18.0.0+
{105, nullptr, "Unknown105"}, //20.0.0+
{201, nullptr, "Unknown201"}, //18.0.0+
{202, nullptr, "Unknown202"}, //18.0.0+
{203, nullptr, "Unknown203"}, //18.0.0+
{204, nullptr, "Unknown204"}, //18.0.0+
{205, nullptr, "Unknown205"}, //18.0.0+
{501, nullptr, "Unknown501"},
{502, nullptr, "Unknown502"},
{503, nullptr, "GetTitleKey"},

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -67,7 +70,7 @@ public:
{20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"},
{20800, &IFriendService::LoadUserSetting, "LoadUserSetting"},
{20801, nullptr, "SyncUserSetting"},
{20900, nullptr, "RequestListSummaryOverlayNotification"},
{20900, &IFriendService::RequestListSummaryOverlayNotification, "RequestListSummaryOverlayNotification"},
{21000, nullptr, "GetExternalApplicationCatalog"},
{22000, nullptr, "GetReceivedFriendInvitationList"},
{22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
@@ -317,6 +320,13 @@ private:
rb.Push(ResultSuccess);
}
void RequestListSummaryOverlayNotification(HLERequestContext& ctx) {
LOG_INFO(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out");

View File

@@ -125,13 +125,10 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{250, nullptr, "IsVirtual"},
{251, nullptr, "GetAnalogStickModuleParam"},
{253, nullptr, "ClearStorageForShipment"}, //19.0.0+
{254, nullptr, "Unknown254"},
{255, nullptr, "Unknown255"},
{256, nullptr, "Unknown256"},
{261, nullptr, "UpdateDesignInfo12"},
{262, nullptr, "GetUniquePadButtonCount"},
{267, nullptr, "Unknown267"},
{268, nullptr, "Unknown268"},
{261, nullptr, "UpdateDesignInfo12"}, //21.0.0+
{262, nullptr, "GetUniquePadButtonCount"}, //21.0.0+
{267, nullptr, "SetAnalogStickCalibration"}, //21.0.0+
{268, nullptr, "ResetAnalogStickCalibration"}, //21.0.0+
{301, nullptr, "GetAbstractedPadHandles"},
{302, nullptr, "GetAbstractedPadState"},
{303, nullptr, "GetAbstractedPadsState"},
@@ -148,6 +145,8 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{331, nullptr, "DetachHdlsVirtualDevice"},
{332, nullptr, "SetHdlsState"},
{350, nullptr, "AddRegisteredDevice"},
{351, nullptr, "GetRegisteredDevicesCountDebug"}, //17.0.0-18.1.0
{352, nullptr, "DeleteRegisteredDevicesDebug"}, //17.0.0-18.1.0
{400, nullptr, "DisableExternalMcuOnNxDevice"},
{401, nullptr, "DisableRailDeviceFiltering"},
{402, nullptr, "EnableWiredPairing"},
@@ -159,14 +158,30 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{551, nullptr, "GetAnalogStickModelData"},
{552, nullptr, "ResetAnalogStickModelData"},
{600, nullptr, "ConvertPadState"},
{601, nullptr, "IsButtonConfigSupported"}, //18.0.0+
{602, nullptr, "IsButtonConfigEmbeddedSupported"}, //18.0.0+
{603, nullptr, "DeleteButtonConfig"}, //18.0.0+
{604, nullptr, "DeleteButtonConfigEmbedded"}, //18.0.0+
{605, nullptr, "SetButtonConfigEnabled"}, //18.0.0+
{606, nullptr, "SetButtonConfigEmbeddedEnabled"}, //18.0.0+
{607, nullptr, "IsButtonConfigEnabled"}, //18.0.0+
{608, nullptr, "IsButtonConfigEmbeddedEnabled"}, //18.0.0+
{609, nullptr, "SetButtonConfigEmbedded"}, //18.0.0+
{610, nullptr, "SetButtonConfigFull"}, //18.0.0+
{611, nullptr, "SetButtonConfigLeft"}, //18.0.0+
{612, nullptr, "SetButtonConfigRight"}, //18.0.0+
{613, nullptr, "GetButtonConfigEmbedded"}, //18.0.0+
{614, nullptr, "GetButtonConfigFull"}, //18.0.0+
{615, nullptr, "GetButtonConfigLeft"}, //18.0.0+
{616, nullptr, "GetButtonConfigRight"}, //18.0.0+
{650, nullptr, "AddButtonPlayData"},
{651, nullptr, "StartButtonPlayData"},
{652, nullptr, "StopButtonPlayData"},
{700, nullptr, "Unknown700"},
{700, nullptr, "GetRailAttachEventCount"}, //21.0.0+
{2000, nullptr, "DeactivateDigitizer"},
{2001, nullptr, "SetDigitizerAutoPilotState"},
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
{2002, nullptr, "ReloadFirmwareDebugSettings"},
{3000, nullptr, "ReloadFirmwareDebugSettings"},
};
// clang-format on

View File

@@ -70,7 +70,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{328, nullptr, "AttachAbstractedPadToNpad"},
{329, nullptr, "DetachAbstractedPadAll"},
{330, nullptr, "CheckAbstractedPadConnection"},
{500, nullptr, "SetAppletResourceUserId"},
{332, nullptr, "ConvertAppletDetailedUiTypeFromPlayReportType"}, //19.0.0+
{333, nullptr, "SetNpadUserSpgApplet"}, //20.0.0+
{334, nullptr, "AcquireUniquePadButtonStateChangedEventHandle"}, //20.0.0+
{501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
{502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
{503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
@@ -99,7 +101,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{547, nullptr, "GetAllowedBluetoothLinksCount"},
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
{549, nullptr, "GetConnectableRegisteredDevices"},
{551, nullptr, "GetRegisteredDevicesForControllerSupport"},
{551, nullptr, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+
{700, nullptr, "ActivateUniquePad"},
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
@@ -119,6 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{810, nullptr, "GetUniquePadControllerNumber"},
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
{813, nullptr, "GetDeviceType"},
{821, nullptr, "StartAnalogStickManualCalibration"},
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
{823, nullptr, "CancelAnalogStickManualCalibration"},
@@ -149,6 +152,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1009, nullptr, "AcquireAudioControlEventHandle"},
{1010, nullptr, "GetAudioControlStates"},
{1011, nullptr, "DeactivateAudioControl"},
{1012, nullptr, "GetFirmwareVersionStringForUserSupportPage"},
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
@@ -169,6 +173,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
{1157, nullptr, "CancelConnectionTrigger"},
{1158, nullptr, "SetConnectionLimitForSplay"}, //20.1.0+
{1159, nullptr, "ClearConnectionLimitForSplay"}, //20.1.0+
{1200, nullptr, "IsButtonConfigSupported"},
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
{1202, nullptr, "DeleteButtonConfig"},
@@ -227,16 +233,17 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1289, nullptr, "SetButtonConfigStorageFull"},
{1290, nullptr, "DeleteButtonConfigStorageRight"},
{1291, nullptr, "DeleteButtonConfigStorageRight"},
{1308, nullptr, "SetButtonConfigVisible"}, // 18.0.0+
{1309, nullptr, "IsButtonConfigVisible"}, // 18.0.0+
{1320, nullptr, "WakeTouchScreenUp"}, // 17.0.0+
{1321, nullptr, "PutTouchScreenToSleep"}, // 17.0.0+
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"}, // 20.0.0+
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"}, // 21.0.0+
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"}, // 21.0.0+
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"}, // 21.0.0+
{1326, nullptr, "Unknown1326"}, // 21.0.0+
{1420, nullptr, "GetAppletResourceProperty"}, // 19.0.0+
{1308, nullptr, "SetButtonConfigVisible"}, //18.0.0+
{1309, nullptr, "IsButtonConfigVisible"}, //18.0.0+
{1320, nullptr, "WakeTouchScreenUp"}, //17.0.0+
{1321, nullptr, "PutTouchScreenToSleep"}, //17.0.0+
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"}, //20.0.0+
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"}, //21.0.0+
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"}, //21.0.0+
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"}, //21.0.0+
{1326, nullptr, "SetTouchScreenOffset"}, //21.0.0+
{1420, nullptr, "GetAppletResourceProperty"}, //19.0.0+
{12010, nullptr, "SetButtonConfigLeft"} //11.0.0-17.0.1
};
// clang-format on

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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,17 +17,42 @@ public:
explicit MIG_USR(Core::System& system_) : ServiceFramework{system_, "mig:usr"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Unknown0"}, //19.0.0+
{1, nullptr, "Unknown1"}, //20.0.0+
{2, nullptr, "Unknown2"}, //20.0.0+
{10, nullptr, "TryGetLastMigrationInfo"},
{100, nullptr, "CreateServer"},
{101, nullptr, "ResumeServer"},
{200, nullptr, "CreateClient"},
{201, nullptr, "ResumeClient"},
{1001, nullptr, "Unknown1001"},
{1010, nullptr, "Unknown1010"},
{1100, nullptr, "Unknown1100"},
{1101, nullptr, "Unknown1101"},
{1200, nullptr, "Unknown1200"},
{1201, nullptr, "Unknown1201"}
{11, nullptr, "Unknown11"}, //20.0.0+
{100, nullptr, "CreateUserMigrationServer"}, //7.0.0+
{101, nullptr, "ResumeUserMigrationServer"}, //7.0.0+
{200, nullptr, "CreateUserMigrationClient"}, //7.0.0+
{201, nullptr, "ResumeUserMigrationClient"}, //7.0.0+
{1001, nullptr, "GetSaveDataMigrationPolicyInfoAsync"}, //8.0.0-20.5.0
{1010, nullptr, "TryGetLastSaveDataMigrationInfo"}, //7.0.0+
{1100, nullptr, "CreateSaveDataMigrationServer"}, //7.0.0-19.0.1
{1101, nullptr, "ResumeSaveDataMigrationServer"}, //7.0.0+
{1110, nullptr, "Unknown1101"}, //17.0.0+
{1200, nullptr, "CreateSaveDataMigrationClient"}, //7.0.0+
{1201, nullptr, "ResumeSaveDataMigrationClient"}, //7.0.0+
{2001, nullptr, "Unknown2001"}, //20.0.0+
{2010, nullptr, "Unknown2010"}, //20.0.0+
{2100, nullptr, "Unknown2100"}, //20.0.0+
{2110, nullptr, "Unknown2110"}, //20.0.0+
{2200, nullptr, "Unknown2200"}, //20.0.0+
{2210, nullptr, "Unknown2210"}, //20.0.0+
{2220, nullptr, "Unknown2220"}, //20.0.0+
{2230, nullptr, "Unknown2230"}, //20.0.0+
{2231, nullptr, "Unknown2231"}, //20.0.0+
{2232, nullptr, "Unknown2232"}, //20.0.0+
{2233, nullptr, "Unknown2233"}, //20.0.0+
{2234, nullptr, "Unknown2234"}, //20.0.0+
{2250, nullptr, "Unknown2250"}, //20.0.0+
{2260, nullptr, "Unknown2260"}, //20.0.0+
{2270, nullptr, "Unknown2270"}, //20.0.0+
{2280, nullptr, "Unknown2280"}, //20.0.0+
{2300, nullptr, "Unknown2300"}, //20.0.0+
{2310, nullptr, "Unknown2310"}, //20.0.0+
{2400, nullptr, "Unknown2400"}, //20.0.0+
{2420, nullptr, "Unknown2420"}, //20.0.0+
};
// clang-format on

View File

@@ -167,57 +167,146 @@ public:
{81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
{82, nullptr, "GetReceivedSystemDataPath"},
{83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
{84, nullptr, "Unknown84"},
{84, nullptr, "ReloadErrorSimulation"},
{85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
{86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
{87, nullptr, "Unknown87"},
{88, nullptr, "Unknown88"},
{89, nullptr, "Unknown89"},
{90, nullptr, "Unknown90"},
{91, nullptr, "Unknown91"},
{92, nullptr, "Unknown92"},
{93, nullptr, "Unknown93"},
{94, nullptr, "Unknown94"},
{95, nullptr, "Unknown95"},
{96, nullptr, "Unknown96"},
{97, nullptr, "Unknown97"},
{98, nullptr, "Unknown98"},
{99, nullptr, "Unknown99"},
{100, nullptr, "Unknown100"},
{101, nullptr, "Unknown101"},
{102, nullptr, "Unknown102"},
{103, nullptr, "Unknown103"},
{104, nullptr, "Unknown104"},
{105, nullptr, "Unknown105"},
{106, nullptr, "Unknown106"},
{107, nullptr, "Unknown107"},
{108, nullptr, "Unknown108"},
{109, nullptr, "Unknown109"},
{110, nullptr, "Unknown110"},
{111, nullptr, "Unknown111"},
{112, nullptr, "Unknown112"},
{113, nullptr, "Unknown113"},
{114, nullptr, "Unknown114"},
{115, nullptr, "Unknown115"},
{116, nullptr, "Unknown116"},
{117, nullptr, "Unknown117"},
{118, nullptr, "Unknown118"},
{119, nullptr, "Unknown119"},
{120, nullptr, "Unknown120"},
{121, nullptr, "Unknown121"},
{122, nullptr, "Unknown122"},
{123, nullptr, "Unknown123"},
{124, nullptr, "Unknown124"},
{125, nullptr, "Unknown125"},
{126, nullptr, "Unknown126"},
{127, nullptr, "Unknown127"},
{128, nullptr, "Unknown128"},
{129, nullptr, "Unknown129"},
{130, nullptr, "Unknown130"},
{131, nullptr, "Unknown131"},
{132, nullptr, "Unknown132"},
{133, nullptr, "Unknown133"},
{134, nullptr, "Unknown134"},
{87, nullptr, "RequestQueryAvailableELicenses"},
{88, nullptr, "RequestAssignELicenses"},
{89, nullptr, "RequestExtendELicenses"},
{90, nullptr, "RequestSyncELicenses"},
{91, nullptr, "Unknown91"}, //6.0.0-14.1.2
{92, nullptr, "Unknown92"}, //21.0.0+
{93, nullptr, "RequestReportActiveELicenses"},
{94, nullptr, "RequestReportActiveELicensesPassively"},
{95, nullptr, "RequestRegisterDynamicRightsNotificationToken"},
{96, nullptr, "RequestAssignAllDeviceLinkedELicenses"},
{97, nullptr, "RequestRevokeAllELicenses"},
{98, nullptr, "RequestPrefetchForDynamicRights"},
{99, nullptr, "CreateNetworkInstallTask"},
{100, nullptr, "ListNetworkInstallTaskRightsIds"},
{101, nullptr, "RequestDownloadETickets"},
{102, nullptr, "RequestQueryDownloadableContents"},
{103, nullptr, "DeleteNetworkInstallTaskContentMeta"},
{104, nullptr, "RequestIssueEdgeTokenForDebug"},
{105, nullptr, "RequestQueryAvailableELicenses2"},
{106, nullptr, "RequestAssignELicenses2"},
{107, nullptr, "GetNetworkInstallTaskStateCounter"},
{108, nullptr, "InvalidateDynamicRightsNaIdTokenCacheForDebug"},
{109, nullptr, "ListNetworkInstallTaskPartialInstallContentMeta"},
{110, nullptr, "ListNetworkInstallTaskRightsIdsFromIndex"},
{111, nullptr, "AddNetworkInstallTaskContentMetaForUser"},
{112, nullptr, "RequestAssignELicensesAndDownloadETickets"},
{113, nullptr, "RequestQueryAvailableCommonELicenses"},
{114, nullptr, "SetNetworkInstallTaskExtendedAttribute"},
{115, nullptr, "GetNetworkInstallTaskExtendedAttribute"},
{116, nullptr, "GetAllocatorInfo"},
{117, nullptr, "RequestQueryDownloadableContentsByApplicationId"},
{118, nullptr, "MarkNoDownloadRightsErrorResolved"},
{119, nullptr, "GetApplyDeltaTaskAllAppliedContentMeta"},
{120, nullptr, "PrioritizeNetworkInstallTask"},
{121, nullptr, "RequestQueryAvailableCommonELicenses2"},
{122, nullptr, "RequestAssignCommonELicenses"},
{123, nullptr, "RequestAssignCommonELicenses2"},
{124, nullptr, "IsNetworkInstallTaskFrontOfQueue"},
{125, nullptr, "PrioritizeApplyDeltaTask"},
{126, nullptr, "RerouteDownloadingPatch"},
{127, nullptr, "UnmarkNoDownloadRightsErrorResolved"},
{128, nullptr, "RequestContentsSize"},
{129, nullptr, "RequestContentsAuthorizationToken"},
{130, nullptr, "RequestCdnVendorDiscovery"},
{131, nullptr, "RefreshDebugAvailability"},
{132, nullptr, "ClearResponseSimulationEntry"},
{133, nullptr, "RegisterResponseSimulationEntry"},
{134, nullptr, "GetProcessedCdnVendors"},
{135, nullptr, "RefreshRuntimeBehaviorsForDebug"},
{136, nullptr, "RequestOnlineSubscriptionFreeTrialAvailability"},
{137, nullptr, "GetNetworkInstallTaskContentMetaCount"},
{138, nullptr, "RequestRevokeELicenses"},
{139, nullptr, "EnableNetworkConnectionToUseApplicationCore"},
{140, nullptr, "DisableNetworkConnectionToUseApplicationCore"},
{141, nullptr, "IsNetworkConnectionEnabledToUseApplicationCore"},
{142, nullptr, "RequestCheckSafeSystemVersion"},
{143, nullptr, "RequestApplicationIcon"},
{144, nullptr, "RequestDownloadIdbeIconFile"},
{147, nullptr, "Unknown147"}, //18.0.0+
{148, nullptr, "Unknown148"}, //18.0.0+
{150, nullptr, "Unknown150"}, //19.0.0+
{151, nullptr, "Unknown151"}, //20.0.0+
{152, nullptr, "Unknown152"}, //20.0.0+
{153, nullptr, "Unknown153"}, //20.0.0+
{154, nullptr, "Unknown154"}, //20.0.0+
{155, nullptr, "Unknown155"}, //20.0.0+
{156, nullptr, "Unknown156"}, //20.0.0+
{157, nullptr, "Unknown157"}, //20.0.0+
{158, nullptr, "Unknown158"}, //20.0.0+
{159, nullptr, "Unknown159"}, //20.0.0+
{160, nullptr, "Unknown160"}, //20.0.0+
{161, nullptr, "Unknown161"}, //20.0.0+
{162, nullptr, "Unknown162"}, //20.0.0+
{163, nullptr, "Unknown163"}, //20.0.0+
{164, nullptr, "Unknown164"}, //20.0.0+
{165, nullptr, "Unknown165"}, //20.0.0+
{166, nullptr, "Unknown166"}, //20.0.0+
{167, nullptr, "Unknown167"}, //20.0.0+
{168, nullptr, "Unknown168"}, //20.0.0+
{169, nullptr, "Unknown169"}, //20.0.0+
{170, nullptr, "Unknown170"}, //20.0.0+
{171, nullptr, "Unknown171"}, //20.0.0+
{172, nullptr, "Unknown172"}, //20.0.0+
{173, nullptr, "Unknown173"}, //20.0.0+
{174, nullptr, "Unknown174"}, //20.0.0+
{175, nullptr, "Unknown175"}, //20.0.0+
{176, nullptr, "Unknown176"}, //20.0.0+
{177, nullptr, "Unknown177"}, //20.0.0+
{2000, nullptr, "Unknown2000"}, //20.0.0+
{2001, nullptr, "Unknown2001"}, //20.0.0+
{2002, nullptr, "Unknown2002"}, //20.0.0+
{2003, nullptr, "Unknown2003"}, //20.0.0+
{2004, nullptr, "Unknown2004"}, //20.0.0+
{2007, nullptr, "Unknown2007"}, //20.0.0+
{2011, nullptr, "Unknown2011"}, //20.0.0+
{2012, nullptr, "Unknown2012"}, //20.0.0+
{2013, nullptr, "Unknown2013"}, //20.0.0+
{2014, nullptr, "Unknown2014"}, //20.0.0+
{2015, nullptr, "Unknown2015"}, //20.0.0+
{2016, nullptr, "Unknown2016"}, //20.0.0+
{2017, nullptr, "Unknown2017"}, //20.0.0+
{2018, nullptr, "Unknown2018"}, //20.0.0+
{2019, nullptr, "Unknown2019"}, //20.0.0+
{2020, nullptr, "Unknown2020"}, //20.0.0+
{2021, nullptr, "Unknown2021"}, //20.0.0+
{2022, nullptr, "Unknown2022"}, //20.0.0+
{2023, nullptr, "Unknown2023"}, //20.0.0+
{2024, nullptr, "Unknown2024"}, //20.0.0+
{2025, nullptr, "Unknown2025"}, //20.0.0+
{2026, nullptr, "Unknown2026"}, //20.0.0+
{2027, nullptr, "Unknown2027"}, //20.0.0+
{2028, nullptr, "Unknown2028"}, //20.0.0+
{2029, nullptr, "Unknown2029"}, //20.0.0+
{2030, nullptr, "Unknown2030"}, //20.0.0+
{2031, nullptr, "Unknown2031"}, //20.0.0+
{2032, nullptr, "Unknown2032"}, //20.0.0+
{2033, nullptr, "Unknown2033"}, //20.0.0+
{2034, nullptr, "Unknown2034"}, //20.0.0+
{2035, nullptr, "Unknown2035"}, //20.0.0+
{2036, nullptr, "Unknown2036"}, //20.0.0+
{2037, nullptr, "Unknown2037"}, //20.0.0+
{2038, nullptr, "Unknown2038"}, //20.0.0+
{2039, nullptr, "Unknown2039"}, //20.0.0+
{2040, nullptr, "Unknown2040"}, //20.0.0+
{2041, nullptr, "Unknown2041"}, //20.0.0+
{2042, nullptr, "Unknown2042"}, //20.0.0+
{2043, nullptr, "Unknown2043"}, //20.0.0+
{2044, nullptr, "Unknown2044"}, //20.0.0+
{2045, nullptr, "Unknown2045"}, //20.0.0+
{2046, nullptr, "Unknown2046"}, //20.0.0+
{2047, nullptr, "Unknown2047"}, //20.0.0+
{2048, nullptr, "Unknown2048"}, //20.0.0+
{2049, nullptr, "Unknown2049"}, //20.0.0+
{2050, nullptr, "Unknown2050"}, //20.0.0+
{2051, nullptr, "Unknown2051"}, //20.0.0+
{3000, nullptr, "RequestLatestApplicationIcon"}, //17.0.0+
{3001, nullptr, "RequestDownloadIdbeLatestIconFile"}, //17.0.0+
};
// clang-format on

View File

@@ -10,6 +10,8 @@
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/application_manager_interface.h"
#include "core/file_sys/content_archive.h"
#include "core/hle/service/ns/content_management_interface.h"
#include "core/hle/service/ns/read_only_application_control_data_interface.h"
#include "core/file_sys/patch_manager.h"
@@ -54,7 +56,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{37, nullptr, "ListRequiredVersion"},
{38, D<&IApplicationManagerInterface::CheckApplicationLaunchVersion>, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{40, D<&IApplicationManagerInterface::GetApplicationLogoData>, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, D<&IApplicationManagerInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"},
@@ -132,7 +134,26 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{406, nullptr, "GetApplicationControlProperty"},
{407, nullptr, "ListApplicationTitle"},
{408, nullptr, "ListApplicationIcon"},
{411, nullptr, "Unknown411"}, //19.0.0+
{412, nullptr, "Unknown412"}, //19.0.0+
{413, nullptr, "Unknown413"}, //19.0.0+
{414, nullptr, "Unknown414"}, //19.0.0+
{415, nullptr, "Unknown415"}, //19.0.0+
{416, nullptr, "Unknown416"}, //19.0.0+
{417, nullptr, "InvalidateAllApplicationControlCacheOfTheStage"}, //19.0.0+
{418, nullptr, "InvalidateApplicationControlCacheOfTheStage"}, //19.0.0+
{419, D<&IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground>, "RequestDownloadApplicationControlDataInBackground"},
{420, nullptr, "CloneApplicationControlDataCacheForDebug"},
{421, nullptr, "Unknown421"}, //20.0.0+
{422, nullptr, "Unknown422"}, //20.0.0+
{423, nullptr, "Unknown423"}, //20.0.0+
{424, nullptr, "Unknown424"}, //20.0.0+
{425, nullptr, "Unknown425"}, //20.0.0+
{426, nullptr, "Unknown426"}, //20.0.0+
{427, nullptr, "Unknown427"}, //20.0.0+
{428, nullptr, "Unknown428"}, //21.0.0+
{429, nullptr, "Unknown429"}, //21.0.0+
{430, nullptr, "Unknown430"}, //21.0.0+
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
@@ -144,6 +165,13 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{510, nullptr, "GetGameCardPlatformRegion"},
{511, D<&IApplicationManagerInterface::GetGameCardWakenReadyEvent>, "GetGameCardWakenReadyEvent"},
{512, D<&IApplicationManagerInterface::IsGameCardApplicationRunning>, "IsGameCardApplicationRunning"},
{513, nullptr, "Unknown513"}, //20.0.0+
{514, nullptr, "Unknown514"}, //20.0.0+
{515, nullptr, "Unknown515"}, //20.0.0+
{516, nullptr, "Unknown516"}, //21.0.0+
{517, nullptr, "Unknown517"}, //21.0.0+
{518, nullptr, "Unknown518"}, //21.0.0+
{519, nullptr, "Unknown519"}, //21.0.0+
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
@@ -181,6 +209,22 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{914, nullptr, "HideApplicationRecord"},
{915, nullptr, "ShowApplicationRecord"},
{916, nullptr, "IsApplicationAutoDeleteDisabled"},
{916, nullptr, "Unknown916"}, //20.0.0+
{917, nullptr, "Unknown917"}, //20.0.0+
{918, nullptr, "Unknown918"}, //20.0.0+
{919, nullptr, "Unknown919"}, //20.0.0+
{920, nullptr, "Unknown920"}, //20.0.0+
{921, nullptr, "Unknown921"}, //20.0.0+
{922, nullptr, "Unknown922"}, //20.0.0+
{923, nullptr, "Unknown923"}, //20.0.0+
{928, nullptr, "Unknown928"}, //20.0.0+
{929, nullptr, "Unknown929"}, //20.0.0+
{930, nullptr, "Unknown930"}, //20.0.0+
{931, nullptr, "Unknown931"}, //20.0.0+
{933, nullptr, "Unknown933"}, //20.0.0+
{934, nullptr, "Unknown934"}, //20.0.0+
{935, nullptr, "Unknown935"}, //20.0.0+
{936, nullptr, "Unknown936"}, //20.0.0+
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -209,6 +253,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1506, nullptr, "GetSdCardStartupStatus"},
{1508, nullptr, "Unknown1508"}, //20.0.0+
{1509, nullptr, "Unknown1509"}, //20.0.0+
{1510, nullptr, "Unknown1510"}, //20.0.0+
{1511, nullptr, "Unknown1511"}, //20.0.0+
{1512, nullptr, "Unknown1512"}, //20.0.0+
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
@@ -245,8 +294,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2019, nullptr, "Unknown2019"}, //20.0.0+
{2050, D<&IApplicationManagerInterface::GetApplicationRightsOnClient>, "GetApplicationRightsOnClient"},
{2051, nullptr, "InvalidateRightsIdCache"},
{2052, nullptr, "Unknown2052"}, //20.0.0+
{2053, nullptr, "Unknown2053"}, //20.0.0+
{2100, D<&IApplicationManagerInterface::GetApplicationTerminateResult>, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
@@ -263,6 +315,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2183, nullptr, "Unknown2183"}, //20.1.0+
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
@@ -279,6 +332,16 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2357, nullptr, "EnableMultiCoreDownload"},
{2358, nullptr, "DisableMultiCoreDownload"},
{2359, nullptr, "IsMultiCoreDownloadEnabled"},
{2360, nullptr, "GetApplicationDownloadTaskCount"}, //19.0.0+
{2361, nullptr, "GetMaxApplicationDownloadTaskCount"}, //19.0.0+
{2362, nullptr, "Unknown2362"}, //20.0.0+
{2363, nullptr, "Unknown2363"}, //20.0.0+
{2364, nullptr, "Unknown2364"}, //20.0.0+
{2365, nullptr, "Unknown2365"}, //20.0.0+
{2366, nullptr, "Unknown2366"}, //20.0.0+
{2367, nullptr, "Unknown2367"}, //20.0.0+
{2368, nullptr, "Unknown2368"}, //20.0.0+
{2369, nullptr, "Unknown2369"}, //21.0.0+
{2400, nullptr, "GetPromotionInfo"},
{2401, nullptr, "CountPromotionInfo"},
{2402, nullptr, "ListPromotionInfo"},
@@ -297,6 +360,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
{2521, nullptr, "GetRightsUserChangedEvent"},
{2522, nullptr, "IsRomRedirectionAvailable"},
{2523, nullptr, "GetProgramId"}, //17.0.0+
{2524, nullptr, "Unknown2524"}, //19.0.0+
{2525, nullptr, "Unknown2525"}, //20.0.0+
{2800, nullptr, "GetApplicationIdOfPreomia"},
{3000, nullptr, "RegisterDeviceLockKey"},
{3001, nullptr, "UnregisterDeviceLockKey"},
@@ -314,11 +380,99 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{3013, nullptr, "IsGameCardEnabled"},
{3014, nullptr, "IsLocalContentShareEnabled"},
{3050, nullptr, "ListAssignELicenseTaskResult"},
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"},
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"},
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"},
{4053, D<&IApplicationManagerInterface::Unknown4053>, "Unknown4053"},
{9999, nullptr, "GetApplicationCertificate"},
{3104, nullptr, "GetApplicationNintendoLogo"}, //18.0.0+
{3105, nullptr, "GetApplicationStartupMovie"}, //18.0.0+
{4000, nullptr, "Unknown4000"}, //20.0.0+
{4004, nullptr, "Unknown4004"}, //20.0.0+
{4006, nullptr, "Unknown4006"}, //20.0.0+
{4007, nullptr, "Unknown4007"}, //20.0.0+
{4008, nullptr, "Unknown4008"}, //20.0.0+
{4009, nullptr, "Unknown4009"}, //20.0.0+
{4010, nullptr, "Unknown4010"}, //20.0.0+
{4011, nullptr, "Unknown4011"}, //20.0.0+
{4012, nullptr, "Unknown4012"}, //20.0.0+
{4013, nullptr, "Unknown4013"}, //20.0.0+
{4015, nullptr, "Unknown4015"}, //20.0.0+
{4017, nullptr, "Unknown4017"}, //20.0.0+
{4019, nullptr, "Unknown4019"}, //20.0.0+
{4020, nullptr, "Unknown4020"}, //20.0.0+
{4021, nullptr, "Unknown4021"}, //20.0.0+
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"}, //20.0.0+
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"}, //20.0.0+
{4024, nullptr, "Unknown4024"}, //20.0.0+
{4025, nullptr, "Unknown4025"}, //20.0.0+
{4026, nullptr, "Unknown4026"}, //20.0.0+
{4027, nullptr, "Unknown4027"}, //20.0.0+
{4028, nullptr, "Unknown4028"}, //20.0.0+
{4029, nullptr, "Unknown4029"}, //20.0.0+
{4030, nullptr, "Unknown4030"}, //20.0.0+
{4031, nullptr, "Unknown4031"}, //20.0.0+
{4032, nullptr, "Unknown4032"}, //20.0.0+
{4033, nullptr, "Unknown4033"}, //20.0.0+
{4034, nullptr, "Unknown4034"}, //20.0.0+
{4035, nullptr, "Unknown4035"}, //20.0.0+
{4037, nullptr, "Unknown4037"}, //20.0.0+
{4038, nullptr, "Unknown4038"}, //20.0.0+
{4039, nullptr, "Unknown4039"}, //20.0.0+
{4040, nullptr, "Unknown4040"}, //20.0.0+
{4041, nullptr, "Unknown4041"}, //20.0.0+
{4042, nullptr, "Unknown4042"}, //20.0.0+
{4043, nullptr, "Unknown4043"}, //20.0.0+
{4044, nullptr, "Unknown4044"}, //20.0.0+
{4045, nullptr, "Unknown4045"}, //20.0.0+
{4046, nullptr, "Unknown4046"}, //20.0.0+
{4049, nullptr, "Unknown4049"}, //20.0.0+
{4050, nullptr, "Unknown4050"}, //20.0.0+
{4051, nullptr, "Unknown4051"}, //20.0.0+
{4052, nullptr, "Unknown4052"}, //20.0.0+
{4053, D<&IApplicationManagerInterface::Unknown4053>, "Unknown4053"}, //20.0.0+
{4054, nullptr, "Unknown4054"}, //20.0.0+
{4055, nullptr, "Unknown4055"}, //20.0.0+
{4056, nullptr, "Unknown4056"}, //20.0.0+
{4057, nullptr, "Unknown4057"}, //20.0.0+
{4058, nullptr, "Unknown4058"}, //20.0.0+
{4059, nullptr, "Unknown4059"}, //20.0.0+
{4060, nullptr, "Unknown4060"}, //20.0.0+
{4061, nullptr, "Unknown4061"}, //20.0.0+
{4062, nullptr, "Unknown4062"}, //20.0.0+
{4063, nullptr, "Unknown4063"}, //20.0.0+
{4064, nullptr, "Unknown4064"}, //20.0.0+
{4065, nullptr, "Unknown4065"}, //20.0.0+
{4066, nullptr, "Unknown4066"}, //20.0.0+
{4067, nullptr, "Unknown4067"}, //20.0.0+
{4068, nullptr, "Unknown4068"}, //20.0.0+
{4069, nullptr, "Unknown4069"}, //20.0.0+
{4070, nullptr, "Unknown4070"}, //20.0.0+
{4071, nullptr, "Unknown4071"}, //20.0.0+
{4072, nullptr, "Unknown4072"}, //20.0.0+
{4073, nullptr, "Unknown4073"}, //20.0.0+
{4074, nullptr, "Unknown4074"}, //20.0.0+
{4075, nullptr, "Unknown4075"}, //20.0.0+
{4076, nullptr, "Unknown4076"}, //20.0.0+
{4077, nullptr, "Unknown4077"}, //20.0.0+
{4078, nullptr, "Unknown4078"}, //20.0.0+
{4079, nullptr, "Unknown4079"}, //20.0.0+
{4080, nullptr, "Unknown4080"}, //20.0.0+
{4081, nullptr, "Unknown4081"}, //20.0.0+
{4083, nullptr, "Unknown4083"}, //20.0.0+
{4084, nullptr, "Unknown4084"}, //20.0.0+
{4085, nullptr, "Unknown4085"}, //20.0.0+
{4086, nullptr, "Unknown4086"}, //20.0.0+
{4087, nullptr, "Unknown4087"}, //20.0.0+
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"}, //20.0.0+
{4089, nullptr, "Unknown4089"}, //20.0.0+
{4090, nullptr, "Unknown4090"}, //20.0.0+
{4091, nullptr, "Unknown4091"}, //20.0.0+
{4092, nullptr, "Unknown4092"}, //20.0.0+
{4093, nullptr, "Unknown4093"}, //20.0.0+
{4094, nullptr, "Unknown4094"}, //20.0.0+
{4095, nullptr, "Unknown4095"}, //20.0.0+
{4096, nullptr, "Unknown4096"}, //20.0.0+
{4097, nullptr, "Unknown4097"}, //20.0.0+
{4099, nullptr, "Unknown4099"}, //21.0.0+
{5000, nullptr, "Unknown5000"}, //18.0.0+
{5001, nullptr, "Unknown5001"}, //18.0.0+
{9999, nullptr, "GetApplicationCertificate"}, //10.0.0-10.2.0
};
// clang-format on
@@ -331,6 +485,53 @@ Result IApplicationManagerInterface::UnregisterNetworkServiceAccountWithUserSave
LOG_DEBUG(Service_NS, "called, user_id={}", user_id.FormattedString());
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationLogoData(
Out<s64> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_buffer, u64 application_id,
InBuffer<BufferAttr_HipcMapAlias> logo_path_buffer) {
const std::string path_view{reinterpret_cast<const char*>(logo_path_buffer.data()),
logo_path_buffer.size()};
// Find null terminator and trim the path
auto null_pos = path_view.find('\0');
std::string path = (null_pos != std::string::npos) ? path_view.substr(0, null_pos) : path_view;
LOG_DEBUG(Service_NS, "called, application_id={:016X}, logo_path={}", application_id, path);
auto& content_provider = system.GetContentProviderUnion();
auto program = content_provider.GetEntry(application_id, FileSys::ContentRecordType::Program);
if (!program) {
LOG_WARNING(Service_NS, "Application program not found for id={:016X}", application_id);
R_RETURN(ResultUnknown);
}
const auto logo_dir = program->GetLogoPartition();
if (!logo_dir) {
LOG_WARNING(Service_NS, "Logo partition not found for id={:016X}", application_id);
R_RETURN(ResultUnknown);
}
const auto file = logo_dir->GetFile(path);
if (!file) {
LOG_WARNING(Service_NS, "Logo path not found: {} for id={:016X}", path,
application_id);
R_RETURN(ResultUnknown);
}
const auto data = file->ReadAllBytes();
if (data.size() > out_buffer.size()) {
LOG_WARNING(Service_NS, "Logo buffer too small: have={}, need={}", out_buffer.size(),
data.size());
R_RETURN(ResultUnknown);
}
std::memcpy(out_buffer.data(), data.data(), data.size());
*out_size = static_cast<s64>(data.size());
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationControlData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, u64 application_id) {

View File

@@ -60,6 +60,10 @@ public:
u64 application_id);
Result CheckApplicationLaunchVersion(u64 application_id);
Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
Result GetApplicationLogoData(Out<s64> out_size,
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
u64 application_id,
InBuffer<BufferAttr_HipcMapAlias> logo_path_buffer);
Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result Unknown4023(Out<u64> out_result);
Result Unknown4053();

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -22,6 +25,7 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{607, nullptr, "IsAnyApplicationRunning"},
{608, nullptr, "Unknown608"}, //21.0.0+
};
// clang-format on

View File

@@ -37,7 +37,11 @@ IDynamicRightsInterface::IDynamicRightsInterface(Core::System& system_)
{23, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
{24, nullptr, "NotifyLimitedApplicationLicenseUpgradableEventForDebug"},
{25, nullptr, "RequestProceedDynamicRightsState"},
{26, D<&IDynamicRightsInterface::HasAccountRestrictedRightsInRunningApplications>, "HasAccountRestrictedRightsInRunningApplications"}
{26, D<&IDynamicRightsInterface::HasAccountRestrictedRightsInRunningApplications>, "HasAccountRestrictedRightsInRunningApplications"},
{27, nullptr, "Unknown27"}, //20.0.0+
{28, nullptr, "Unknown28"}, //20.0.0+
{29, nullptr, "Unknown29"}, //21.0.0+
{30, nullptr, "Unknown30"}, //21.0.0+
};
// clang-format on

View File

@@ -179,4 +179,9 @@ struct ApplicationDisplayData {
};
static_assert(sizeof(ApplicationDisplayData) == 0x300, "ApplicationDisplayData has incorrect size.");
struct LogoPath {
std::array<char, 0x300> path;
};
static_assert(std::is_trivially_copyable_v<LogoPath>, "LogoPath must be trivially copyable.");
} // namespace Service::NS

View File

@@ -15,7 +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) {}
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {}
~Layer() {
buffer_item_consumer->Abandon();
}
@@ -25,6 +25,7 @@ struct Layer {
LayerBlending blending;
bool visible;
s32 z_index;
bool is_overlay;
};
struct LayerStack {

View File

@@ -78,8 +78,25 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
for (auto& layer : display.stack.layers) {
auto consumer_id = layer->consumer_id;
bool should_try_acquire = true;
if (!layer->is_overlay) {
auto fb_it = m_framebuffers.find(consumer_id);
if (fb_it != m_framebuffers.end() && fb_it->second.is_acquired) {
const u64 frames_since_last_acquire = m_frame_number - fb_it->second.last_acquire_frame;
const s32 expected_interval = NormalizeSwapInterval(nullptr, fb_it->second.item.swap_interval);
if (frames_since_last_acquire < static_cast<u64>(expected_interval)) {
should_try_acquire = false;
}
}
}
// Try to fetch the framebuffer (either new or stale).
const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
const auto result = should_try_acquire
? this->CacheFramebufferLocked(*layer, consumer_id)
: (m_framebuffers.find(consumer_id) != m_framebuffers.end() && m_framebuffers[consumer_id].is_acquired
? CacheStatus::CachedBufferReused
: CacheStatus::NoBufferAvailable);
// If we failed, skip this layer.
if (result == CacheStatus::NoBufferAvailable) {
@@ -111,6 +128,12 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
});
}
// Overlay layers run at their own framerate independently of the game.
// Skip them when calculating the swap interval for the main game.
if (layer->is_overlay) {
continue;
}
// We need to compose again either before this frame is supposed to
// be released, or exactly on the vsync period it should be released.
const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval);
@@ -138,33 +161,44 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
// Batch framebuffer releases, instead of one-into-one.
std::vector<std::pair<Layer*, Framebuffer*>> to_release;
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number || !framebuffer.is_acquired)
if (!framebuffer.is_acquired)
continue;
if (auto layer = display.stack.FindLayer(layer_id); layer)
auto layer = display.stack.FindLayer(layer_id);
if (!layer)
continue;
// Overlay layers always release after every compose
// Non-overlay layers release based on their swap interval
if (layer->is_overlay || framebuffer.release_frame_number <= m_frame_number) {
to_release.emplace_back(layer.get(), &framebuffer);
}
}
for (auto& [layer, framebuffer] : to_release) {
layer->buffer_item_consumer->ReleaseBuffer(framebuffer->item, android::Fence::NoFence());
framebuffer->is_acquired = false;
}
// Advance by at least one frame.
const u32 frame_advance = swap_interval.value_or(1);
m_frame_number += frame_advance;
// Advance by 1 frame (60 FPS compositing)
m_frame_number += 1;
// Release any necessary framebuffers.
// Release any necessary framebuffers (non-overlay layers only, as overlays are already released above).
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (framebuffer.release_frame_number > m_frame_number) {
continue;
}
if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
// Skip overlay layers as they were already released above
if (layer->is_overlay) {
continue;
}
// TODO: support release fence
// This is needed to prevent screen tearing
layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
@@ -172,7 +206,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
}
}
return frame_advance;
return 1;
}
void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
@@ -200,8 +234,9 @@ bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& fr
}
// We succeeded, so set the new release frame info.
framebuffer.release_frame_number =
NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
const s32 swap_interval = layer.is_overlay ? 1 : NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
framebuffer.release_frame_number = m_frame_number + swap_interval;
framebuffer.last_acquire_frame = m_frame_number;
framebuffer.is_acquired = true;
return true;

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -34,6 +37,7 @@ private:
struct Framebuffer {
android::BufferItem item{};
ReleaseFrameNumber release_frame_number{};
u64 last_acquire_frame{0};
bool is_acquired{false};
};

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -101,6 +104,13 @@ void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blen
}
}
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;
LOG_DEBUG(Service_VI, "Layer {} marked as overlay: {}", consumer_binder_id, is_overlay);
}
}
Display* SurfaceFlinger::FindDisplay(u64 display_id) {
for (auto& display : m_displays) {
if (display.id == display_id) {

View File

@@ -47,6 +47,7 @@ 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);
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);

View File

@@ -16,64 +16,67 @@ IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_
: ServiceFramework{system_, "olsc:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
{1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
{2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{0, D<&IOlscServiceForSystemService::GetTransferTaskListController>, "GetTransferTaskListController"},
{1, D<&IOlscServiceForSystemService::GetRemoteStorageController>, "GetRemoteStorageController"},
{2, D<&IOlscServiceForSystemService::GetDaemonController>, "GetDaemonController"},
{10, nullptr, "PrepareDeleteUserProperty"},
{11, nullptr, "DeleteUserSaveDataProperty"},
{12, nullptr, "InvalidateMountCache"},
{13, nullptr, "DeleteDeviceSaveDataProperty"},
{100, nullptr, "ListLastTransferTaskErrorInfo"},
{101, nullptr, "GetLastErrorInfoCount"},
{102, nullptr, "RemoveLastErrorInfoOld"},
{103, nullptr, "GetLastErrorInfo"},
{104, nullptr, "GetLastErrorEventHolder"},
{105, nullptr, "GetLastTransferTaskErrorInfo"},
{200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
{201, nullptr, "RemoveDataTransferPolicyInfo"},
{202, nullptr, "UpdateDataTransferPolicyOld"},
{203, nullptr, "UpdateDataTransferPolicy"},
{204, nullptr, "CleanupDataTransferPolicyInfo"},
{205, nullptr, "RequestDataTransferPolicy"},
{300, nullptr, "GetAutoTransferSeriesInfo"},
{301, nullptr, "UpdateAutoTransferSeriesInfo"},
{400, nullptr, "CleanupSaveDataArchiveInfoType1"},
{900, nullptr, "CleanupTransferTask"},
{902, nullptr, "CleanupSeriesInfoType0"},
{903, nullptr, "CleanupSaveDataArchiveInfoType0"},
{904, nullptr, "CleanupApplicationAutoTransferSetting"},
{905, nullptr, "CleanupErrorHistory"},
{906, nullptr, "SetLastError"},
{907, nullptr, "AddSaveDataArchiveInfoType0"},
{908, nullptr, "RemoveSeriesInfoType0"},
{909, nullptr, "GetSeriesInfoType0"},
{910, nullptr, "RemoveLastErrorInfo"},
{911, nullptr, "CleanupSeriesInfoType1"},
{912, nullptr, "RemoveSeriesInfoType1"},
{913, nullptr, "GetSeriesInfoType1"},
{200, D<&IOlscServiceForSystemService::GetDataTransferPolicy>, "GetDataTransferPolicy"},
{201, nullptr, "DeleteDataTransferPolicyCache"},
{202, nullptr, "Unknown202"},
{203, nullptr, "RequestUpdateDataTransferPolicyCacheAsync"},
{204, nullptr, "ClearDataTransferPolicyCache"},
{205, nullptr, "RequestGetDataTransferPolicyAsync"},
{206, nullptr, "Unknown206"}, //21.0.0+
{300, nullptr, "GetUserSaveDataProperty"},
{301, nullptr, "SetUserSaveDataProperty"},
{302, nullptr, "Unknown302"}, //21.0.0+
{400, nullptr, "CleanupSaveDataBackupContextForSpecificApplications"},
{900, nullptr, "DeleteAllTransferTask"},
{902, nullptr, "DeleteAllSeriesInfo"},
{903, nullptr, "DeleteAllSdaInfoCache"},
{904, nullptr, "DeleteAllApplicationSetting"},
{905, nullptr, "DeleteAllTransferTaskErrorInfo"},
{906, nullptr, "RegisterTransferTaskErrorInfo"},
{907, nullptr, "AddSaveDataArchiveInfoCache"},
{908, nullptr, "DeleteSeriesInfo"},
{909, nullptr, "GetSeriesInfo"},
{910, nullptr, "RemoveTransferTaskErrorInfo"},
{911, nullptr, "DeleteAllSeriesInfoForSaveDataBackup"},
{912, nullptr, "DeleteSeriesInfoForSaveDataBackup"},
{913, nullptr, "GetSeriesInfoForSaveDataBackup"},
{914, nullptr, "Unknown914"}, //20.2.0+
{1000, nullptr, "UpdateIssueOld"},
{1010, nullptr, "Unknown1010"},
{1011, nullptr, "ListIssueInfoOld"},
{1012, nullptr, "GetIssueOld"},
{1013, nullptr, "GetIssue2Old"},
{1014, nullptr, "GetIssue3Old"},
{1020, nullptr, "RepairIssueOld"},
{1021, nullptr, "RepairIssueWithUserIdOld"},
{1022, nullptr, "RepairIssue2Old"},
{1023, nullptr, "RepairIssue3Old"},
{1011, nullptr, "Unknown1011"},
{1012, nullptr, "Unknown1012"},
{1013, nullptr, "Unkown1013"},
{1014, nullptr, "Unknown1014"},
{1020, nullptr, "Unknown1020"},
{1021, nullptr, "Unknown1021"},
{1022, nullptr, "Unknown1022"},
{1023, nullptr, "Unknown1023"},
{1024, nullptr, "Unknown1024"},
{1100, nullptr, "UpdateIssue"},
{1110, nullptr, "Unknown1110"},
{1111, nullptr, "ListIssueInfo"},
{1112, nullptr, "GetIssue"},
{1113, nullptr, "GetIssue2"},
{1114, nullptr, "GetIssue3"},
{1120, nullptr, "RepairIssue"},
{1121, nullptr, "RepairIssueWithUserId"},
{1122, nullptr, "RepairIssue2"},
{1123, nullptr, "RepairIssue3"},
{1124, nullptr, "Unknown1124"},
{10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
{1100, nullptr, "RepairUpdateIssueInfoCacheAync"},
{1110, nullptr, "RepairGetIssueInfo"},
{1111, nullptr, "RepairListIssueInfo"},
{1112, nullptr, "RepairListOperationPermissionInfo"},
{1113, nullptr, "RepairListDataInfoForRepairedSaveDataDownload"},
{1114, nullptr, "RepairListDataInfoForOriginalSaveDataDownload"},
{1120, nullptr, "RepairUploadSaveDataAsync"},
{1121, nullptr, "RepairUploadSaveDataAsync1"},
{1122, nullptr, "RepairDownloadRepairedSaveDataAsync"},
{1123, nullptr, "RepairDownloadOriginalSaveDataAsync"},
{1124, nullptr, "RepairGetOperationProgressInfo"},
{10000, D<&IOlscServiceForSystemService::GetOlscServiceForSystemService>, "GetOlscServiceForSystemService"},
};
// clang-format on
@@ -82,38 +85,38 @@ IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_
IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
Result IOlscServiceForSystemService::OpenTransferTaskListController(
Result IOlscServiceForSystemService::GetTransferTaskListController(
Out<SharedPointer<ITransferTaskListController>> out_interface) {
LOG_INFO(Service_OLSC, "called");
*out_interface = std::make_shared<ITransferTaskListController>(system);
R_SUCCEED();
}
Result IOlscServiceForSystemService::OpenRemoteStorageController(
Result IOlscServiceForSystemService::GetRemoteStorageController(
Out<SharedPointer<IRemoteStorageController>> out_interface) {
LOG_INFO(Service_OLSC, "called");
*out_interface = std::make_shared<IRemoteStorageController>(system);
R_SUCCEED();
}
Result IOlscServiceForSystemService::OpenDaemonController(
Result IOlscServiceForSystemService::GetDaemonController(
Out<SharedPointer<IDaemonController>> out_interface) {
LOG_INFO(Service_OLSC, "called");
*out_interface = std::make_shared<IDaemonController>(system);
R_SUCCEED();
}
Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(
Out<DataTransferPolicy> out_policy_info, u64 application_id) {
Result IOlscServiceForSystemService::GetDataTransferPolicy(
Out<DataTransferPolicy> out_policy, u64 application_id) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
DataTransferPolicy policy{};
policy.upload_policy = 0;
policy.download_policy = 0;
*out_policy_info = policy;
*out_policy = policy;
R_SUCCEED();
}
Result IOlscServiceForSystemService::CloneService(
Result IOlscServiceForSystemService::GetOlscServiceForSystemService(
Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
LOG_INFO(Service_OLSC, "called");
*out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());

View File

@@ -24,12 +24,12 @@ public:
~IOlscServiceForSystemService() override;
private:
Result OpenTransferTaskListController(
Result GetTransferTaskListController(
Out<SharedPointer<ITransferTaskListController>> out_interface);
Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
Result GetDataTransferPolicyInfo(Out<DataTransferPolicy> out_policy_info, u64 application_id);
Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
Result GetRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
Result GetDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
Result GetDataTransferPolicy(Out<DataTransferPolicy> out_policy, u64 application_id);
Result GetOlscServiceForSystemService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
};
} // namespace Service::OLSC

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -11,32 +14,37 @@ ITransferTaskListController::ITransferTaskListController(Core::System& system_)
: ServiceFramework{system_, "ITransferTaskListController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Unknown0"},
{1, nullptr, "Unknown1"},
{2, nullptr, "Unknown2"},
{3, nullptr, "Unknown3"},
{4, nullptr, "Unknown4"},
{5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
{6, nullptr, "Unknown6"},
{7, nullptr, "Unknown7"},
{8, nullptr, "GetRemoteStorageController"},
{9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{14, nullptr, "Unknown14"},
{15, nullptr, "Unknown15"},
{16, nullptr, "Unknown16"},
{17, nullptr, "Unknown17"},
{18, nullptr, "Unknown18"},
{19, nullptr, "Unknown19"},
{20, nullptr, "Unknown20"},
{21, nullptr, "Unknown21"},
{22, nullptr, "Unknown22"},
{23, nullptr, "Unknown23"},
{24, nullptr, "Unknown24"},
{25, nullptr, "Unknown25"},
{0, nullptr, "GetTransferTaskCountForOcean"},
{1, nullptr, "GetTransferTaskInfoForOcean"},
{2, nullptr, "ListTransferTaskInfoForOcean"},
{3, nullptr, "DeleteTransferTaskForOcean"},
{4, nullptr, "RaiseTransferTaskPriorityForOcean"},
{5, D<&ITransferTaskListController::GetTransferTaskEndEventNativeHandleHolder>, "GetTransferTaskEndEventNativeHandleHolder"},
{6, nullptr, "GetTransferTaskProgressForOcean"},
{7, nullptr, "GetTransferTaskLastResultForOcean"},
{8, nullptr, "StopNextTransferTaskExecution"},
{9, D<&ITransferTaskListController::GetTransferTaskStartEventNativeHandleHolder>, "GetTransferTaskStartEventNativeHandleHolder"},
{10, nullptr, "SuspendTransferTaskForOcean"},
{11, nullptr, "GetCurrentTransferTaskInfoForOcean"},
{12, nullptr, "FindTransferTaskInfoForOcean"},
{13, nullptr, "CancelCurrentRepairTransferTask"},
{14, nullptr, "GetRepairTransferTaskProgress"},
{15, nullptr, "EnsureExecutableForRepairTransferTask"},
{16, nullptr, "GetTransferTaskCount"},
{17, nullptr, "GetTransferTaskInfo"},
{18, nullptr, "ListTransferTaskInfo"},
{19, nullptr, "DeleteTransferTask"},
{20, nullptr, "RaiseTransferTaskPriority"},
{21, nullptr, "GetTransferTaskProgress"},
{22, nullptr, "GetTransferTaskLastResult"},
{23, nullptr, "SuspendTransferTask"},
{24, nullptr, "GetCurrentTransferTaskInfo"},
{25, nullptr, "Unknown25"}, //20.1.0+
{26, nullptr, "Unknown26"}, //20.1.0+
{27, nullptr, "Unknown27"}, //20.1.0+
{28, nullptr, "Unknown28"}, //20.1.0+
{29, nullptr, "Unknown29"}, //20.1.0+
{30, nullptr, "Unknown30"}, //20.1.0+
};
// clang-format on
@@ -45,7 +53,14 @@ ITransferTaskListController::ITransferTaskListController(Core::System& system_)
ITransferTaskListController::~ITransferTaskListController() = default;
Result ITransferTaskListController::GetNativeHandleHolder(
Result ITransferTaskListController::GetTransferTaskEndEventNativeHandleHolder(
Out<SharedPointer<INativeHandleHolder>> out_holder) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
*out_holder = std::make_shared<INativeHandleHolder>(system);
R_SUCCEED();
}
Result ITransferTaskListController::GetTransferTaskStartEventNativeHandleHolder(
Out<SharedPointer<INativeHandleHolder>> out_holder) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
*out_holder = std::make_shared<INativeHandleHolder>(system);

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -14,7 +17,8 @@ public:
~ITransferTaskListController() override;
private:
Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
Result GetTransferTaskEndEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
Result GetTransferTaskStartEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
};
} // namespace Service::OLSC

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -34,10 +37,10 @@ public:
{17, nullptr, "AcquireIrq"},
{18, nullptr, "ReleaseIrq"},
{19, nullptr, "SetIrqEnable"},
{20, nullptr, "SetAspmEnable"},
{21, nullptr, "SetResetUponResumeEnable"},
{22, nullptr, "ResetFunction"},
{23, nullptr, "Unknown23"},
{20, nullptr, "GetIrqEvent"},
{21, nullptr, "SetAspmEnable"},
{22, nullptr, "SetResetUponResumeEnable"},
{23, nullptr, "ResetFunction"},
};
// clang-format on

View File

@@ -39,6 +39,9 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
{1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
{1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
{1019, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
{1020, nullptr, "ConfirmLaunchSharedApplicationPermission"}, //20.0.0+
{1021, nullptr, "TryBeginFreeCommunicationForStreamPlay"}, //21.0.0+
{1022, nullptr, "EndFreeCommunicationForStreamPlay"}, //21.0.0+
{1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
{1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"},
@@ -56,6 +59,8 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
{1047, nullptr, "NotifyApplicationDownloadStarted"},
{1048, nullptr, "NotifyNetworkProfileCreated"},
{1049, nullptr, "ResetFreeCommunicationApplicationList"},
{1050, nullptr, "AddToFreeCommunicationApplicationList"}, //20.0.0+
{1051, nullptr, "NotifyApplicationDownloadStarted"}, //20.0.0+
{1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
{1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
{1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
@@ -126,8 +131,17 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
{2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
{2014, nullptr, "FinishSynchronizeParentalControlSettings"},
{2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
{2016, nullptr, "RequestUpdateExemptionListAsync"},
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"} // 18.0.0+
{2016, nullptr, "RequestUpdateExemptionListAsync"}, //5.0.0+
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"}, // 18.0.0+
{2017, nullptr, "AuthorizePairingAsync"}, //19.0.0+
{2019, nullptr, "RequestUpdateDeviceUsersBackground"}, //19.0.0+
{2021, nullptr, "RequestCopyPairingAsync"}, //20.0.0+
{2022, nullptr, "FinishRequestCopyPairing"}, //20.0.0+
{2023, nullptr, "IsFromPairingActiveDevice"}, //20.0.0+
{2024, nullptr, "RollbackCopyPairing"}, //21.0.0+
{3001, nullptr, "GetErrorContextChangedEvent"}, //20.0.0+
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"}, // 18.0.0+
{195101, D<&IParentalControlService::SetPlayTimerSettings>, "SetPlayTimerSettingsForDebug"}, //18.0.0+
};
// clang-format on
RegisterHandlers(functions);
@@ -393,16 +407,21 @@ Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restric
}
Result IParentalControlService::GetPlayTimerSettingsOld(
Out<PlayTimerSettings> out_play_timer_settings) {
Out<PlayTimerSettingsOld> out_play_timer_settings) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
*out_play_timer_settings = {};
R_SUCCEED();
}
Result IParentalControlService::GetPlayTimerSettings(
Out<PlayTimerSettings> out_play_timer_settings) {
Result IParentalControlService::GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
*out_play_timer_settings = {};
*out_play_timer_settings = raw_play_timer_settings;
R_SUCCEED();
}
Result IParentalControlService::SetPlayTimerSettings(PlayTimerSettings play_timer_settings) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
raw_play_timer_settings = play_timer_settings;
R_SUCCEED();
}

View File

@@ -51,7 +51,7 @@ private:
Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
Result GetPlayTimerRemainingTime(Out<s32> out_remaining_time);
Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
Result GetPlayTimerSettingsOld(Out<PlayTimerSettings> out_play_timer_settings);
Result GetPlayTimerSettingsOld(Out<PlayTimerSettingsOld> out_play_timer_settings);
Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
Result GetPlayTimerRemainingTimeDisplayInfo();
@@ -60,6 +60,7 @@ private:
Result SetStereoVisionRestriction(bool stereo_vision_restriction);
Result ResetConfirmedStereoVisionPermission();
Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
Result SetPlayTimerSettings(PlayTimerSettings out_play_timer_settings);
struct States {
u64 current_tid{};
@@ -83,6 +84,8 @@ private:
RestrictionSettings restriction_settings{};
std::array<char, 8> pin_code{};
Capability capability{};
// TODO: this is RAW as fuck
PlayTimerSettings raw_play_timer_settings{};
KernelHelpers::ServiceContext service_context;
Event synchronization_event;

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -34,10 +37,16 @@ struct RestrictionSettings {
};
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
// This is nn::pctl::PlayTimerSettings
struct PlayTimerSettings {
// This is nn::pctl::PlayTimerSettingsOld
struct PlayTimerSettingsOld {
std::array<u32, 13> settings;
};
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
static_assert(sizeof(PlayTimerSettingsOld) == 0x34, "PlayTimerSettingsOld has incorrect size.");
// This is nn::pctl::PlayTimerSettings
struct PlayTimerSettings {
std::array<u32, 17> settings; //21.0.0+ now takes 0x44
};
static_assert(sizeof(PlayTimerSettings) == 0x44, "PlayTimerSettings has incorrect size.");
} // namespace Service::PCTL

View File

@@ -34,9 +34,9 @@ public:
{10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"},
{10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"},
{20100, &PlayReport::SaveSystemReportOld, "SaveSystemReport"},
{20101, &PlayReport::SaveSystemReportWithUserOld, "SaveSystemReportWithUser"},
{20102, &PlayReport::SaveSystemReport, "SaveSystemReport"},
{20103, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20101, &PlayReport::SaveSystemReportWithUserOld, "SaveSystemReportWithUser"},
{20102, &PlayReport::SaveSystemReport, "SaveSystemReport"},
{20103, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20200, nullptr, "SetOperationMode"},
{30100, nullptr, "ClearStorage"},
{30200, nullptr, "ClearStatistics"},

View File

@@ -18,49 +18,43 @@
namespace Service {
/**
* Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name,
std::string_view port_name,
const u32* cmd_buff) {
/// @brief Creates a function string for logging, complete with the name (or header code, depending
/// on what's passed in) the port name, and all the cmd_buff arguments.
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name, std::string_view port_name, const u32* cmd_buff) {
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
std::string function_string = fmt::format("function '{}': port={}", name, port_name);
for (int i = 1; i <= num_params; ++i) {
for (int i = 1; i <= num_params; ++i)
function_string += fmt::format(", cmd_buff[{}]={:#X}", i, cmd_buff[i]);
}
return function_string;
}
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
u32 max_sessions_, InvokerFn* handler_invoker_)
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
service_name{service_name_}, handler_invoker{handler_invoker_}, max_sessions{max_sessions_} {}
ServiceFrameworkBase::~ServiceFrameworkBase() {
// Wait for other threads to release access before destroying
const auto guard = LockService();
const auto guard = ServiceFrameworkBase::LockService();
}
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
// Usually this array is sorted by id already, so hint to insert at the end
handlers.reserve(handlers.size() + n);
for (std::size_t i = 0; i < n; ++i) {
// Usually this array is sorted by id already, so hint to insert at the end
for (std::size_t i = 0; i < n; ++i)
handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]);
}
}
void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
std::size_t n) {
void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n) {
// Usually this array is sorted by id already, so hint to insert at the end
handlers_tipc.reserve(handlers_tipc.size() + n);
for (std::size_t i = 0; i < n; ++i) {
// Usually this array is sorted by id already, so hint to insert at the end
for (std::size_t i = 0; i < n; ++i)
handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
functions[i]);
}
}
void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
@@ -69,15 +63,12 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
std::string function_name = info == nullptr ? "<unknown>" : info->name;
fmt::memory_buffer buf;
fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}",
ctx.GetCommand(), function_name, service_name, cmd_buf[0]);
for (int i = 1; i <= 8; ++i) {
fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}", ctx.GetCommand(), function_name, service_name, cmd_buf[0]);
for (int i = 1; i <= 8; ++i)
fmt::format_to(std::back_inserter(buf), ", [{}]={:#X}", i, cmd_buf[i]);
}
buf.push_back('}');
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
service_name);
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, service_name);
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
if (Settings::values.use_auto_stub) {
LOG_WARNING(Service, "Using auto stub fallback!");
@@ -87,25 +78,20 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
}
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
auto itr = handlers.find(ctx.GetCommand());
const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second;
if (info == nullptr || info->handler_callback == nullptr) {
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);
}
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
itr = handlers_tipc.find(ctx.GetCommand());
const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
if (info == nullptr || info->handler_callback == nullptr) {
auto it = handlers_tipc.find(ctx.GetCommand());
FunctionInfoBase const* info = it == handlers_tipc.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);

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -47,25 +50,23 @@ static_assert(ServerSessionCountMax == 0x40,
class ServiceFrameworkBase : public SessionRequestHandler {
public:
/// Returns the string identifier used to connect to the service.
std::string GetServiceName() const {
[[nodiscard]] std::string_view GetServiceName() const noexcept {
return service_name;
}
/**
* Returns the maximum number of sessions that can be connected to this service at the same
* time.
*/
u32 GetMaxSessions() const {
/// @brief Returns the maximum number of sessions that can be connected to this service at the same
/// time.
u32 GetMaxSessions() const noexcept {
return max_sessions;
}
/// Invokes a service request routine using the HIPC protocol.
/// @brief Invokes a service request routine using the HIPC protocol.
void InvokeRequest(HLERequestContext& ctx);
/// Invokes a service request routine using the HIPC protocol.
/// @brief Invokes a service request routine using the HIPC protocol.
void InvokeRequestTipc(HLERequestContext& ctx);
/// Handles a synchronization request for the service.
/// @brief Handles a synchronization request for the service.
Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& context) override;
protected:
@@ -74,7 +75,7 @@ protected:
using HandlerFnP = void (Self::*)(HLERequestContext&);
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() {
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() noexcept {
return std::unique_lock{lock_service};
}
@@ -105,20 +106,19 @@ private:
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
void ReportUnimplementedFunction(HLERequestContext& ctx, const FunctionInfoBase* info);
boost::container::flat_map<u32, FunctionInfoBase> handlers;
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
std::mutex lock_service;
/// 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.
u32 max_sessions;
/// Flag to store if a port was already create/installed to detect multiple install attempts,
/// which is not supported.
bool service_registered = false;
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker;
boost::container::flat_map<u32, FunctionInfoBase> handlers;
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
std::mutex lock_service;
};
/**
@@ -142,20 +142,12 @@ protected:
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
/**
* Constructs a FunctionInfo for a function.
*
* @param expected_header_ request header in the command buffer which will trigger dispatch
* to this handler
* @param handler_callback_ member function in this service which will be called to handle
* the request
* @param name_ human-friendly name for the request. Used mostly for logging purposes.
*/
FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
: FunctionInfoBase{
expected_header_,
// Type-erase member function pointer by casting it down to the base class.
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
/// @brief Constructs a FunctionInfo for a function.
/// @param expected_header_ request header in the command buffer which will trigger dispatch to this handler
/// @param handler_callback_ member function in this service which will be called to handle the request
/// @param name_ human-friendly name for the request. Used mostly for logging purposes.
constexpr FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
: FunctionInfoBase{expected_header_, HandlerFnP<ServiceFrameworkBase>(handler_callback_), name_} {}
};
using FunctionInfo = FunctionInfoTyped<Self>;

View File

@@ -36,6 +36,29 @@ struct SettingsHeader {
u32 version;
u32 reserved;
};
void SyncGlobalLanguageFromCode(LanguageCode language_code) {
const auto it = std::find_if(available_language_codes.begin(), available_language_codes.end(),
[language_code](LanguageCode code) { return code == language_code; });
if (it == available_language_codes.end()) {
return;
}
const std::size_t index = static_cast<std::size_t>(std::distance(available_language_codes.begin(), it));
if (index >= static_cast<std::size_t>(Settings::values.language_index.GetValue())) {
Settings::values.language_index.SetValue(static_cast<Settings::Language>(index));
}
}
void SyncGlobalRegionFromCode(SystemRegionCode region_code) {
const auto region_index = static_cast<std::size_t>(region_code);
if (region_index > static_cast<std::size_t>(Settings::Region::Taiwan)) {
return;
}
Settings::values.region_index.SetValue(static_cast<Settings::Region>(region_index));
}
} // Anonymous namespace
Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system,
@@ -457,6 +480,7 @@ Result ISystemSettingsServer::SetLanguageCode(LanguageCode language_code) {
LOG_INFO(Service_SET, "called, language_code={}", language_code);
m_system_settings.language_code = language_code;
SyncGlobalLanguageFromCode(language_code);
SetSaveNeeded();
R_SUCCEED();
}
@@ -889,6 +913,7 @@ Result ISystemSettingsServer::SetRegionCode(SystemRegionCode region_code) {
LOG_INFO(Service_SET, "called, region_code={}", region_code);
m_system_settings.region_code = region_code;
SyncGlobalRegionFromCode(region_code);
SetSaveNeeded();
R_SUCCEED();
}
@@ -1224,6 +1249,7 @@ Result ISystemSettingsServer::SetKeyboardLayout(KeyboardLayout keyboard_layout)
LOG_INFO(Service_SET, "called, keyboard_layout={}", keyboard_layout);
m_system_settings.keyboard_layout = keyboard_layout;
SetSaveNeeded();
R_SUCCEED();
}

View File

@@ -578,7 +578,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
}
std::vector<Network::PollFD> host_pollfds(fds.size());
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) {
Network::PollFD result;
result.socket = file_descriptors[pollfd.fd]->socket.get();
result.events = Translate(pollfd.events);
@@ -657,7 +657,11 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
const auto result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
if (result != Errno::SUCCESS) {
LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast<int>(result));
if (result == Errno::INPROGRESS || result == Errno::AGAIN) {
LOG_DEBUG(Service, "Connect fd={} in progress (non-blocking), errno={}", fd, static_cast<int>(result));
} else {
LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast<int>(result));
}
} else {
LOG_INFO(Service, "Connect fd={} succeeded", fd);
}
@@ -967,7 +971,11 @@ Expected<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
return Unexpected(Errno::MFILE);
}
file_descriptors[new_fd] = file_descriptors[fd];
file_descriptors[new_fd] = FileDescriptor{
.socket = file_descriptors[fd]->socket,
.flags = file_descriptors[fd]->flags,
.is_connection_based = file_descriptors[fd]->is_connection_based,
};
return new_fd;
}
@@ -1074,8 +1082,7 @@ BSD::~BSD() {
}
}
std::unique_lock<std::mutex> BSD::LockService() {
// Do not lock socket IClient instances.
std::unique_lock<std::mutex> BSD::LockService() noexcept {
return {};
}

View File

@@ -179,7 +179,7 @@ private:
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
/// Callback to parse and handle a received wifi packet.
void OnProxyPacketReceived(const Network::ProxyPacket& packet);
@@ -188,7 +188,7 @@ private:
Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
protected:
virtual std::unique_lock<std::mutex> LockService() override;
std::unique_lock<std::mutex> LockService() noexcept override;
};
class BSDCFG final : public ServiceFramework<BSDCFG> {

View File

@@ -157,22 +157,24 @@ private:
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
// Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
auto res = bsd->DuplicateSocketImpl(fd);
if (!res.has_value()) {
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
return ResultInvalidSocket;
}
const s32 duplicated_fd = *res;
if (do_not_close_socket) {
auto res = bsd->DuplicateSocketImpl(fd);
if (!res.has_value()) {
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
return ResultInvalidSocket;
}
fd = *res;
fd_to_close = fd;
*out_fd = fd;
*out_fd = duplicated_fd;
} else {
*out_fd = -1;
fd_to_close = duplicated_fd;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(duplicated_fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {}", fd);
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", duplicated_fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
@@ -325,7 +327,19 @@ private:
res = backend->GetServerCerts(&certs);
if (res == ResultSuccess) {
const std::vector<u8> certs_buf = SerializeServerCerts(certs);
ctx.WriteBuffer(certs_buf);
if (ctx.CanWriteBuffer()) {
const size_t buffer_size = ctx.GetWriteBufferSize();
if (certs_buf.size() <= buffer_size) {
ctx.WriteBuffer(certs_buf);
} else {
LOG_WARNING(Service_SSL, "Certificate buffer too small: {} bytes needed, {} bytes available",
certs_buf.size(), buffer_size);
ctx.WriteBuffer(std::span<const u8>(certs_buf.data(), buffer_size));
}
} else {
LOG_DEBUG(Service_SSL, "No output buffer provided for certificates ({} bytes)", certs_buf.size());
}
out.certs_count = static_cast<u32>(certs.size());
out.certs_size = static_cast<u32>(certs_buf.size());
}
@@ -664,119 +678,119 @@ class ISslServiceForSystem final : public ServiceFramework<ISslServiceForSystem>
{103, D<&ISslServiceForSystem::VerifySignature>, "VerifySignature"}
};
// clang-format on
RegisterHandlers(functions);
};
Result CreateContext() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result GetContextCount() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result GetCertificates() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result GetCertificateBufSize() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result DebugIoctl() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result SetInterfaceVersion() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result FlushSessionCache() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result SetDebugOption() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result GetDebugOption() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result ClearTls12FallbackFlag() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result CreateContextForSystem() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result SetThreadCoreMask() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result GetThreadCoreMask() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
Result VerifySignature() {
LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell)
return ResultSuccess;
};
};

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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

View File

@@ -166,6 +166,16 @@ Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) {
R_RETURN(VI::ResultNotFound);
}
Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
m_surface_flinger->SetLayerIsOverlay(layer->GetConsumerBinderId(), is_overlay);
R_SUCCEED();
}
void Container::LinkVsyncEvent(u64 display_id, Event* event) {
std::scoped_lock lk{m_lock};
m_conductor->LinkVsyncEvent(display_id, event);

View File

@@ -67,6 +67,7 @@ public:
Result SetLayerBlending(u64 layer_id, bool enabled);
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);
void LinkVsyncEvent(u64 display_id, Event* event);
void UnlinkVsyncEvent(u64 display_id, Event* event);

View File

@@ -46,8 +46,8 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
for (; start < end; ++start) {
*start = 0x00000000; // ARGB/RGBA with alpha=0
for (; start < end; start++) {
*start = 0xFF0000FF;
}
}
@@ -257,7 +257,6 @@ Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64*
// Configure blending and z-index
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
R_ASSERT(m_container.SetLayerZIndex(session.layer_id, 100000));
// Get the producer and set preallocated buffers.
std::shared_ptr<android::BufferQueueProducer> producer;
@@ -374,11 +373,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError,
VI::ResultOperationFailed);
// Ensure the layer is visible when content is presented.
// Re-assert overlay priority in case clients reset it.
(void)m_container.SetLayerZIndex(layer_id, 100000);
(void)m_container.SetLayerVisibility(layer_id, true);
// We succeeded.
R_SUCCEED();
}
@@ -415,51 +409,22 @@ Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32*
// TODO: this could be optimized
s64 e = -1280 * 768 * 4;
for (auto& block : *m_buffer_page_group) {
u8* const block_start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* ptr = block_start;
u8* const block_end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
for (; ptr < block_end; ++ptr) {
for (; start < end; start++) {
*start = 0;
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
*ptr = capture_buffer[static_cast<size_t>(e)];
} else {
*ptr = 0;
*start = capture_buffer[e];
}
++e;
e++;
}
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(block_start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, block_end - block_start);
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, end - start);
});
}
// After writing, present a frame on each active shared layer so it becomes visible.
for (auto& [aruid, session] : m_sessions) {
std::shared_ptr<android::BufferQueueProducer> producer;
if (R_FAILED(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id))) {
continue;
}
s32 slot = -1;
android::Fence fence = android::Fence::NoFence();
if (producer->DequeueBuffer(&slot, &fence, SharedBufferAsync != 0, SharedBufferWidth,
SharedBufferHeight, SharedBufferBlockLinearFormat, 0) !=
android::Status::NoError) {
continue;
}
std::shared_ptr<android::GraphicBuffer> gb;
if (producer->RequestBuffer(slot, &gb) != android::Status::NoError) {
producer->CancelBuffer(slot, android::Fence::NoFence());
continue;
}
android::QueueBufferInput qin{};
android::QueueBufferOutput qout{};
qin.crop = {0, 0, static_cast<s32>(SharedBufferWidth), static_cast<s32>(SharedBufferHeight)};
qin.fence = android::Fence::NoFence();
qin.transform = static_cast<android::NativeWindowTransform>(0);
qin.swap_interval = 1;
(void)producer->QueueBuffer(slot, qin, &qout);
}
*out_was_written = true;
*out_layer_index = 1;
R_SUCCEED();

View File

@@ -57,7 +57,7 @@ class SigHandler {
public:
SigHandler() noexcept {
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);
signal_stack_memory = std::malloc(signal_stack_size);
stack_t signal_stack{};
signal_stack.ss_sp = signal_stack_memory;
@@ -89,7 +89,7 @@ public:
}
~SigHandler() noexcept {
munmap(signal_stack_memory, signal_stack_size);
std::free(signal_stack_memory);
}
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {

View File

@@ -82,7 +82,8 @@ FP::FPCR A32EmitContext::FPCR(bool fpcr_controlled) const {
A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_interface)
: EmitX64(code), conf(std::move(conf)), jit_interface(jit_interface) {
GenFastmemFallbacks();
if (conf.fastmem_pointer.has_value())
GenFastmemFallbacks();
GenTerminalHandlers();
code.PreludeComplete();
ClearFastDispatchTable();
@@ -217,13 +218,13 @@ void A32EmitX64::ClearFastDispatchTable() {
}
void A32EmitX64::GenTerminalHandlers() {
// PC ends up in ebp, location_descriptor ends up in rbx
// PC ends up in edi, location_descriptor ends up in rbx
const auto calculate_location_descriptor = [this] {
// This calculation has to match up with IREmitter::PushRSB
code.mov(ebx, dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)]);
code.shl(rbx, 32);
code.mov(ecx, MJitStateReg(A32::Reg::PC));
code.mov(ebp, ecx);
code.mov(edi, ecx);
code.or_(rbx, rcx);
};
@@ -238,7 +239,7 @@ void A32EmitX64::GenTerminalHandlers() {
code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]);
if (conf.HasOptimization(OptimizationFlag::FastDispatch)) {
code.jne(rsb_cache_miss);
code.jne(rsb_cache_miss, code.T_NEAR);
} else {
code.jne(code.GetReturnFromRunCodeAddress());
}
@@ -251,20 +252,21 @@ void A32EmitX64::GenTerminalHandlers() {
terminal_handler_fast_dispatch_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.L(rsb_cache_miss);
code.mov(r12, reinterpret_cast<u64>(fast_dispatch_table.data()));
code.mov(rbp, rbx);
code.mov(r8, reinterpret_cast<u64>(fast_dispatch_table.data()));
//code.mov(r12d, MJitStateReg(A32::Reg::PC));
code.mov(r12, rbx);
if (code.HasHostFeature(HostFeature::SSE42)) {
code.crc32(rbp, r12);
code.crc32(r12, r8);
}
code.and_(ebp, fast_dispatch_table_mask);
code.lea(rbp, ptr[r12 + rbp]);
code.cmp(rbx, qword[rbp + offsetof(FastDispatchEntry, location_descriptor)]);
code.jne(fast_dispatch_cache_miss);
code.jmp(ptr[rbp + offsetof(FastDispatchEntry, code_ptr)]);
code.and_(r12d, fast_dispatch_table_mask);
code.lea(r12, ptr[r8 + r12]);
code.cmp(rbx, qword[r12 + offsetof(FastDispatchEntry, location_descriptor)]);
code.jne(fast_dispatch_cache_miss, code.T_NEAR);
code.jmp(ptr[r12 + offsetof(FastDispatchEntry, code_ptr)]);
code.L(fast_dispatch_cache_miss);
code.mov(qword[rbp + offsetof(FastDispatchEntry, location_descriptor)], rbx);
code.mov(qword[r12 + offsetof(FastDispatchEntry, location_descriptor)], rbx);
code.LookupBlock();
code.mov(ptr[rbp + offsetof(FastDispatchEntry, code_ptr)], rax);
code.mov(ptr[r12 + offsetof(FastDispatchEntry, code_ptr)], rax);
code.jmp(rax);
PerfMapRegister(terminal_handler_fast_dispatch_hint, code.getCurr(), "a32_terminal_handler_fast_dispatch_hint");

View File

@@ -56,7 +56,8 @@ FP::FPCR A64EmitContext::FPCR(bool fpcr_controlled) const {
A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_interface)
: EmitX64(code), conf(conf), jit_interface{jit_interface} {
GenMemory128Accessors();
GenFastmemFallbacks();
if (conf.fastmem_pointer.has_value())
GenFastmemFallbacks();
GenTerminalHandlers();
code.PreludeComplete();
ClearFastDispatchTable();
@@ -188,13 +189,14 @@ void A64EmitX64::ClearFastDispatchTable() {
}
void A64EmitX64::GenTerminalHandlers() {
// PC ends up in rbp, location_descriptor ends up in rbx
// PC ends up in rcx, location_descriptor ends up in rbx
static_assert(std::find(ABI_ALL_CALLEE_SAVE.begin(), ABI_ALL_CALLEE_SAVE.end(), HostLoc::R12) != ABI_ALL_CALLEE_SAVE.end());
const auto calculate_location_descriptor = [this] {
// This calculation has to match up with A64::LocationDescriptor::UniqueHash
// TODO: Optimization is available here based on known state of fpcr.
code.mov(rbp, qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]);
code.mov(rdi, qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]);
code.mov(rcx, A64::LocationDescriptor::pc_mask);
code.and_(rcx, rbp);
code.and_(rcx, rdi);
code.mov(ebx, dword[code.ABI_JIT_PTR + offsetof(A64JitState, fpcr)]);
code.and_(ebx, A64::LocationDescriptor::fpcr_mask);
code.shl(rbx, A64::LocationDescriptor::fpcr_shift);
@@ -226,20 +228,21 @@ void A64EmitX64::GenTerminalHandlers() {
terminal_handler_fast_dispatch_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.L(rsb_cache_miss);
code.mov(r12, reinterpret_cast<u64>(fast_dispatch_table.data()));
code.mov(rbp, rbx);
code.mov(r8, reinterpret_cast<u64>(fast_dispatch_table.data()));
//code.mov(r12, qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]);
code.mov(r12, rbx);
if (code.HasHostFeature(HostFeature::SSE42)) {
code.crc32(rbp, r12);
code.crc32(r12, r8);
}
code.and_(ebp, fast_dispatch_table_mask);
code.lea(rbp, ptr[r12 + rbp]);
code.cmp(rbx, qword[rbp + offsetof(FastDispatchEntry, location_descriptor)]);
code.jne(fast_dispatch_cache_miss);
code.jmp(ptr[rbp + offsetof(FastDispatchEntry, code_ptr)]);
code.and_(r12d, fast_dispatch_table_mask);
code.lea(r12, ptr[r8 + r12]);
code.cmp(rbx, qword[r12 + offsetof(FastDispatchEntry, location_descriptor)]);
code.jne(fast_dispatch_cache_miss, code.T_NEAR);
code.jmp(ptr[r12 + offsetof(FastDispatchEntry, code_ptr)]);
code.L(fast_dispatch_cache_miss);
code.mov(qword[rbp + offsetof(FastDispatchEntry, location_descriptor)], rbx);
code.mov(qword[r12 + offsetof(FastDispatchEntry, location_descriptor)], rbx);
code.LookupBlock();
code.mov(ptr[rbp + offsetof(FastDispatchEntry, code_ptr)], rax);
code.mov(ptr[r12 + offsetof(FastDispatchEntry, code_ptr)], rax);
code.jmp(rax);
PerfMapRegister(terminal_handler_fast_dispatch_hint, code.getCurr(), "a64_terminal_handler_fast_dispatch_hint");

View File

@@ -370,7 +370,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
cmp(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], 0);
jne(return_to_caller_mxcsr_already_exited, T_NEAR);
lock(); or_(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], static_cast<u32>(HaltReason::Step));
lock(); or_(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], u32(HaltReason::Step));
SwitchMxcsrOnEntry();
jmp(ABI_PARAM2);

View File

@@ -37,6 +37,9 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/opt_passes.h"
#include "./A32/testenv.h"
#include "./A64/testenv.h"
using namespace Dynarmic;
std::string_view GetNameOfA32Instruction(u32 instruction) {
@@ -65,7 +68,10 @@ void PrintA32Instruction(u32 instruction) {
fmt::print("should_continue: {}\n\n", should_continue);
fmt::print("IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
Optimization::Optimize(ir_block, A32::UserConfig{}, {});
ArmTestEnv jit_env{};
Dynarmic::A32::UserConfig jit_user_config{};
jit_user_config.callbacks = &jit_env;
Optimization::Optimize(ir_block, jit_user_config, {});
fmt::print("Optimized IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
}
@@ -80,7 +86,10 @@ void PrintA64Instruction(u32 instruction) {
fmt::print("should_continue: {}\n\n", should_continue);
fmt::print("IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
Optimization::Optimize(ir_block, A64::UserConfig{}, {});
A64TestEnv jit_env{};
Dynarmic::A64::UserConfig jit_user_config{};
jit_user_config.callbacks = &jit_env;
Optimization::Optimize(ir_block, jit_user_config, {});
fmt::print("Optimized IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
}
@@ -98,7 +107,10 @@ void PrintThumbInstruction(u32 instruction) {
fmt::print("should_continue: {}\n\n", should_continue);
fmt::print("IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
Optimization::Optimize(ir_block, A32::UserConfig{}, {});
ThumbTestEnv jit_env{};
Dynarmic::A32::UserConfig jit_user_config{};
jit_user_config.callbacks = &jit_env;
Optimization::Optimize(ir_block, jit_user_config, {});
fmt::print("Optimized IR:\n");
fmt::print("{}\n", IR::DumpBlock(ir_block));
}
@@ -219,7 +231,7 @@ void ExecuteA32Instruction(u32 instruction) {
*(iter->second) = *value;
fmt::print("> {} = 0x{:08x}\n", reg_name, *value);
}
} else if (reg_name == "mem" || reg_name == "memory") {
} else if (reg_name.starts_with("m")) {
fmt::print("address: ");
if (const auto address = get_value()) {
fmt::print("value: ");
@@ -228,7 +240,7 @@ void ExecuteA32Instruction(u32 instruction) {
fmt::print("> mem[0x{:08x}] = 0x{:08x}\n", *address, *value);
}
}
} else if (reg_name == "end") {
} else if (reg_name == "exit" || reg_name == "end" || reg_name.starts_with("q")) {
break;
}
}
@@ -244,6 +256,7 @@ void ExecuteA32Instruction(u32 instruction) {
env.MemoryWrite32(initial_pc + 4, 0xEAFFFFFE); // B +0
cpu.Run();
fmt::print("{}", fmt::join(cpu.Disassemble(), "\n"));
fmt::print("Registers modified:\n");
for (size_t i = 0; i < regs.size(); ++i) {

View File

@@ -146,7 +146,7 @@ PresentManager::PresentManager(const vk::Instance& instance_,
.pNext = nullptr,
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
});
free_queue.push(&frame);
free_queue.push_back(&frame);
}
if (use_present_thread) {
@@ -164,7 +164,7 @@ Frame* PresentManager::GetRenderFrame() {
// Take the frame from the queue
Frame* frame = free_queue.front();
free_queue.pop();
free_queue.pop_front();
// Wait for the presentation to be finished so all frame resources are free
frame->present_done.Wait();
@@ -174,18 +174,17 @@ Frame* PresentManager::GetRenderFrame() {
}
void PresentManager::Present(Frame* frame) {
if (!use_present_thread) {
if (use_present_thread) {
scheduler.Record([this, frame](vk::CommandBuffer) {
std::unique_lock lock{queue_mutex};
present_queue.push_back(frame);
frame_cv.notify_one();
});
} else {
scheduler.WaitWorker();
CopyToSwapchain(frame);
free_queue.push(frame);
return;
free_queue.push_back(frame);
}
scheduler.Record([this, frame](vk::CommandBuffer) {
std::unique_lock lock{queue_mutex};
present_queue.push(frame);
frame_cv.notify_one();
});
}
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
@@ -277,29 +276,25 @@ void PresentManager::PresentThread(std::stop_token token) {
Common::SetCurrentThreadName("VulkanPresent");
while (!token.stop_requested()) {
std::unique_lock lock{queue_mutex};
// Wait for presentation frames
frame_cv.wait(lock, token, [this] { return !present_queue.empty(); });
if (token.stop_requested()) {
return;
if (!token.stop_requested()) {
// Take the frame and notify anyone waiting
Frame* frame = present_queue.front();
present_queue.pop_front();
frame_cv.notify_one();
// By exchanging the lock ownership we take the swapchain lock
// before the queue lock goes out of scope. This way the swapchain
// lock in WaitPresent is guaranteed to occur after here.
std::exchange(lock, std::unique_lock{swapchain_mutex});
CopyToSwapchain(frame);
// Free the frame for reuse
std::scoped_lock fl{free_mutex};
free_queue.push_back(frame);
free_cv.notify_one();
}
// Take the frame and notify anyone waiting
Frame* frame = present_queue.front();
present_queue.pop();
frame_cv.notify_one();
// By exchanging the lock ownership we take the swapchain lock
// before the queue lock goes out of scope. This way the swapchain
// lock in WaitPresent is guaranteed to occur after here.
std::exchange(lock, std::unique_lock{swapchain_mutex});
CopyToSwapchain(frame);
// Free the frame for reuse
std::scoped_lock fl{free_mutex};
free_queue.push(frame);
free_cv.notify_one();
}
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 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
@@ -5,7 +8,7 @@
#include <condition_variable>
#include <mutex>
#include <queue>
#include <boost/container/deque.hpp>
#include "common/common_types.h"
#include "common/polyfill_thread.h"
@@ -88,8 +91,8 @@ private:
#endif
vk::CommandPool cmdpool;
std::vector<Frame> frames;
std::queue<Frame*> present_queue;
std::queue<Frame*> free_queue;
boost::container::deque<Frame*> present_queue;
boost::container::deque<Frame*> free_queue;
std::condition_variable_any frame_cv;
std::condition_variable free_cv;
std::mutex swapchain_mutex;

View File

@@ -20,18 +20,12 @@
namespace Vulkan {
namespace {
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
std::span<const char* const> extensions) {
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
return false;
}
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, std::vector<VkExtensionProperties> const& properties, std::span<const char* const> extensions) {
for (const char* extension : extensions) {
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
const auto it = std::ranges::find_if(properties, [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0;
});
if (it == properties->end()) {
if (it == properties.end()) {
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
return false;
}
@@ -78,14 +72,16 @@ namespace {
if (window_type != Core::Frontend::WindowSystemType::Headless) {
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
}
if (auto const properties = vk::EnumerateInstanceExtensionProperties(dld); properties) {
#ifdef __APPLE__
if (AreExtensionsSupported(dld, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME})) {
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
}
if (AreExtensionsSupported(dld, *properties, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}))
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
if (enable_validation &&
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME})) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
// VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1
if (window_type != Core::Frontend::WindowSystemType::Headless && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME}))
extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
}
return extensions;
}
@@ -133,11 +129,10 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
const std::vector<const char*> extensions =
RequiredExtensions(dld, window_type, enable_validation);
if (!AreExtensionsSupported(dld, extensions)) {
std::vector<const char*> const extensions = RequiredExtensions(dld, window_type, enable_validation);
auto const properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties || !AreExtensionsSupported(dld, *properties, extensions))
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
}
std::vector<const char*> layers = Layers(enable_validation);
RemoveUnavailableLayers(dld, layers);

View File

@@ -128,7 +128,7 @@ li.checked::marker { content: &quot;\2612&quot;; }
<item>
<widget class="QLabel" name="labelLinks">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://eden-emulator.github.io/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev/eden-emu/eden/activity/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://discord.gg/HstXbPch7X&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Discord&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://rvlt.gg/qKgFEAbH&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Revolt&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://nitter.poast.org/edenemuofficial&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Twitter&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://eden-emulator.github.io/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev/eden-emu/eden/activity/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://discord.gg/HstXbPch7X&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Discord&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://stt.gg/qKgFEAbH&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Stoat&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://nitter.poast.org/edenemuofficial&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Twitter&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>

View File

@@ -1900,7 +1900,7 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
tr("Error while loading ROM! %1", "%1 signifies a numeric error code.")
.arg(QString::fromStdString(error_code));
const auto description =
tr("%1<br>Please redump your files or ask on Discord/Revolt for help.",
tr("%1<br>Please redump your files or ask on Discord/Stoat for help.",
"%1 signifies an error string.")
.arg(QString::fromStdString(
GetResultStatusString(static_cast<Loader::ResultStatus>(error_id))));

View File

@@ -1,59 +0,0 @@
#!/usr/local/bin/bash -ex
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# Basic script to run dtrace sampling over the program (requires Flamegraph)
# Usage is either running as: ./dtrace-tool.sh pid (then input the pid of the process)
# Or just run directly with: ./dtrace-tool.sh <command>
FLAMEGRAPH_DIR=".."
fail() {
printf '%s\n' "$1" >&2
exit "${2-1}"
}
[ -f $FLAMEGRAPH_DIR/FlameGraph/stackcollapse.pl ] || fail 'Where is flamegraph?'
#[ which dtrace ] || fail 'Needs DTrace installed'
read -r "Sampling Hz [800]: " TRACE_CFG_HZ
if [ -z "${TRACE_CFG_HZ}" ]; then
TRACE_CFG_HZ=800
fi
read -r "Sampling time [5] sec: " TRACE_CFG_TIME
if [ -z "${TRACE_CFG_TIME}" ]; then
TRACE_CFG_TIME=5
fi
TRACE_FILE=dtrace-out.user_stacks
TRACE_FOLD=dtrace-out.fold
TRACE_SVG=dtrace-out.svg
ps
if [ "$1" = 'pid' ]; then
read -r "PID: " TRACE_CFG_PID
sudo echo 'Sudo!'
else
if [ -f "$1" ] && [ "$1" ]; then
fail 'Usage: ./tools/dtrace-profile.sh <path to program>'
fi
printf "Executing: "
echo "$@"
sudo echo 'Sudo!'
"$@" &
TRACE_CFG_PID=$!
fi
TRACE_PROBE="profile-${TRACE_CFG_HZ} /pid == ${TRACE_CFG_PID} && arg1/ { @[ustack()] = count(); } tick-${TRACE_CFG_TIME}s { exit(0); }"
rm -- $TRACE_SVG || echo 'Skip'
sudo dtrace -x ustackframes=100 -Z -n "$TRACE_PROBE" -o $TRACE_FILE 2>/dev/null || exit
perl $FLAMEGRAPH_DIR/FlameGraph/stackcollapse.pl $TRACE_FILE > $TRACE_FOLD || exit
perl $FLAMEGRAPH_DIR/FlameGraph/flamegraph.pl $TRACE_FOLD > $TRACE_SVG || exit
sudo chmod 0666 $TRACE_FILE
rm -- $TRACE_FILE $TRACE_FOLD