Compare commits

..

33 Commits

Author SHA1 Message Date
lizzie 9985c74cea fixup primitive restart 2026-08-29 06:45:54 +00:00
lizzie eec3a4168f fix build errors 2026-05-20 2026-08-29 06:45:54 +00:00
lizzie d39f9126f7 Trigger Build 2026-08-29 06:45:54 +00:00
lizzie 4563af7527 fx 2026-08-29 06:45:54 +00:00
crueter 64059d5d64 Fix license headers 2026-08-29 06:45:54 +00:00
crueter d5f064380d Fix build
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:54 +00:00
crueter 06a2420ae7 Limit on MSVC
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:54 +00:00
crueter 71d43234a1 Unity batch size
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:54 +00:00
crueter 0c389249a0 MSVC fixes
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:54 +00:00
crueter 5bcbf2cf91 ACTUALLY fix VMA garbage
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:44 +00:00
crueter ed351fbd41 barely-working VMA fix
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:30 +00:00
crueter a57c284ee9 Some build fixes
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:08 +00:00
crueter 3cd8aea0ae Fix comp
Signed-off-by: crueter <crueter@eden-emu.dev>
2026-08-29 06:45:08 +00:00
lizzie 45074ba1ae fix? 2026-08-29 06:45:01 +00:00
lizzie 764cbf747c fix? 2026-08-29 06:45:01 +00:00
lizzie 5ec2d443c0 fix cityhash 2026-08-29 06:45:01 +00:00
lizzie c1eece6218 qrc buildage exclude 2026-08-29 06:45:01 +00:00
lizzie 5201e6bea5 fix polygon lut name issue 2026-08-29 06:44:17 +00:00
lizzie 81162d376f fix openg 2026-08-29 06:44:17 +00:00
lizzie e80ec69795 ENABLE_UNITY_BUILD 2026-08-29 06:44:17 +00:00
lizzie 07f8605957 yay it works 2026-08-29 06:44:17 +00:00
lizzie e3fc6fc6ea stupid 1 2026-08-29 06:44:17 +00:00
lizzie 1d377180e7 EVEN MORE FIXES 2026-08-29 06:44:17 +00:00
lizzie ecb1ac96e0 more qt fixes 2026-08-29 06:44:17 +00:00
lizzie daded9e507 FIX BSD DEFINE IN FUCKING BSD?, fix INVALID_SOCKET on httplib 2026-08-29 06:44:17 +00:00
lizzie 80a6576c7a fix pragma once in even MORE core stuff 2026-08-29 06:43:10 +00:00
lizzie 6d03182e33 more fs fixes 2026-08-29 06:42:48 +00:00
lizzie bc47304607 fuck? 2026-08-29 06:42:48 +00:00
lizzie f5e488db05 fixup more compile issues 2026-08-29 06:42:48 +00:00
lizzie c9df8409df fixup dynarmic, and dont forget push constants 2026-08-29 06:42:48 +00:00
lizzie 7cf84f0936 fix with bigger batch sizes 2026-08-29 06:42:48 +00:00
lizzie 6e5af6a3c1 FIX FMT 2026-08-29 06:42:48 +00:00
lizzie c2fbcd816a [cmake] Allow proper unity builds
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-08-29 06:42:48 +00:00
184 changed files with 1925 additions and 1897 deletions
+20
View File
@@ -69,6 +69,26 @@ if (YUZU_STATIC_ROOM)
set(fmt_FORCE_BUNDLED ON) set(fmt_FORCE_BUNDLED ON)
endif() endif()
# my unity/jumbo build
option(ENABLE_UNITY_BUILD "Enable Unity/Jumbo build" OFF)
# 0 compiles all files in
# not ideal, but if you're going gung-ho with a unity build, expect failure
# MSVC physically can't compile that many files into one TU, so we limit it to 100.
if (MSVC)
set(_unity_default 100)
else()
set(_unity_default 0)
endif()
set(UNITY_BATCH_SIZE ${_unity_default} CACHE STRING "Unity build batch size")
if(MSVC AND ENABLE_UNITY_BUILD)
message(STATUS "Unity build")
# Unity builds need big objects for MSVC...
add_compile_options(/bigobj)
endif()
# qt stuff # qt stuff
option(ENABLE_QT "Enable the Qt frontend" ON) option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
+2 -2
View File
@@ -340,10 +340,10 @@
"version": "vulkan-sdk-%NUMERIC_VERSION%" "version": "vulkan-sdk-%NUMERIC_VERSION%"
}, },
"xbyak": { "xbyak": {
"hash": "e0aa0a603dd3ac1a39d82213df1e73c042831aec2d6b2fe382c899651eaae4ed7e8aeb6be9c41ea0097087c9d091961ab18f313cd6a9e10d621715ffd49bfe36", "hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
"package": "xbyak", "package": "xbyak",
"repo": "herumi/xbyak", "repo": "herumi/xbyak",
"version": "v7.40.1" "version": "v7.35.2"
}, },
"zlib": { "zlib": {
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4", "hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
+1
View File
@@ -39,6 +39,7 @@ These options control dependencies.
- This option is subject for removal. - This option is subject for removal.
- `YUZU_TESTS` (ON) Compile tests - requires Catch2 - `YUZU_TESTS` (ON) Compile tests - requires Catch2
- `ENABLE_LTO` (OFF) Enable link-time optimization - `ENABLE_LTO` (OFF) Enable link-time optimization
- `ENABLE_UNITY_BUILD` (OFF) Enables "Unity/Jumbo" builds
- Not recommended on Windows - Not recommended on Windows
- UNIX may be better off appending `-flto=thin` to compiler args - UNIX may be better off appending `-flto=thin` to compiler args
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available - `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
+5
View File
@@ -7,6 +7,11 @@
# Enable modules to include each other's files # Enable modules to include each other's files
include_directories(.) include_directories(.)
if (ENABLE_UNITY_BUILD)
set(CMAKE_UNITY_BUILD ON)
set(CMAKE_UNITY_BUILD_BATCH_SIZE ${UNITY_BATCH_SIZE})
endif()
# Dynarmic # Dynarmic
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM) if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
add_subdirectory(dynarmic) add_subdirectory(dynarmic)
@@ -47,6 +47,7 @@ import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler import info.debatty.java.stringsimilarity.JaroWinkler
import java.util.Locale import java.util.Locale
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.view.doOnNextLayout
class GamesFragment : Fragment() { class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null private var _binding: FragmentGamesBinding? = null
@@ -58,6 +59,7 @@ class GamesFragment : Fragment() {
private var originalHeaderLeftMargin: Int? = null private var originalHeaderLeftMargin: Int? = null
private var lastViewType: Int = GameAdapter.VIEW_TYPE_GRID private var lastViewType: Int = GameAdapter.VIEW_TYPE_GRID
private var fallbackBottomInset: Int = 0
private var pendingPostReloadListSettle = false private var pendingPostReloadListSettle = false
private var pendingPostReloadListSettleGeneration = 0 private var pendingPostReloadListSettleGeneration = 0
private var gameListSubmitGeneration = 0 private var gameListSubmitGeneration = 0
@@ -225,7 +227,12 @@ class GamesFragment : Fragment() {
} }
else -> throw IllegalArgumentException("Invalid view type: $savedViewType") else -> throw IllegalArgumentException("Invalid view type: $savedViewType")
} }
if (savedViewType != GameAdapter.VIEW_TYPE_CAROUSEL) { if (savedViewType == GameAdapter.VIEW_TYPE_CAROUSEL) {
(binding.gridGames as? View)?.let { it -> ViewCompat.requestApplyInsets(it)}
doOnNextLayout { //Carousel: important to avoid overlap issues
(this as? CarouselRecyclerView)?.notifyLaidOut(fallbackBottomInset)
}
} else {
(this as? CarouselRecyclerView)?.setupCarousel(false) (this as? CarouselRecyclerView)?.setupCarousel(false)
} }
adapter = gameAdapter adapter = gameAdapter
@@ -583,6 +590,11 @@ class GamesFragment : Fragment() {
qlaunchButton.layoutParams = mlpQLaunch qlaunchButton.layoutParams = mlpQLaunch
} }
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
val gestureInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
val bottomInset = maxOf(navInsets.bottom, gestureInsets.bottom, cutoutInsets.bottom)
fallbackBottomInset = bottomInset
(binding.gridGames as? CarouselRecyclerView)?.notifyInsetsReady(bottomInset)
windowInsets windowInsets
} }
} }
@@ -12,16 +12,13 @@ import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sin import kotlin.math.sin
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.GameAdapter import org.yuzu.yuzu_emu.adapters.GameAdapter
import androidx.core.view.doOnNextLayout import androidx.core.view.doOnNextLayout
import androidx.core.view.ViewCompat
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import org.yuzu.yuzu_emu.utils.FullscreenHelper
/** /**
* CarouselRecyclerView encapsulates all carousel content for the games UI. * CarouselRecyclerView encapsulates all carousel content for the games UI.
* It manages overlapping cards, center snapping, custom drawing order, * It manages overlapping cards, center snapping, custom drawing order,
@@ -35,9 +32,7 @@ class CarouselRecyclerView @JvmOverloads constructor(
private var overlapFactor: Float = 0f private var overlapFactor: Float = 0f
private var overlapPx: Int = 0 private var overlapPx: Int = 0
private var bottomInset: Int = 0 private var bottomInset: Int = -1
private var latestWindowInsets: WindowInsetsCompat? = null
private var cardGeometryInitialized: Boolean = false
private var overlapDecoration: OverlappingDecoration? = null private var overlapDecoration: OverlappingDecoration? = null
private var pagerSnapHelper: PagerSnapHelper? = null private var pagerSnapHelper: PagerSnapHelper? = null
private var scalingScrollListener: OnScrollListener? = null private var scalingScrollListener: OnScrollListener? = null
@@ -96,38 +91,6 @@ class CarouselRecyclerView @JvmOverloads constructor(
init { init {
setChildrenDrawingOrderEnabled(true) setChildrenDrawingOrderEnabled(true)
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
latestWindowInsets = insets
updateCardGeometry()
applyCarouselPadding()
insets
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
ViewCompat.requestApplyInsets(this)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (w != oldw || h != oldh) {
updateCardGeometry()
applyCarouselPadding()
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (isCarouselMode) updateChildScalesAndAlpha()
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
ViewCompat.requestApplyInsets(this)
post { updateCardGeometry() }
}
} }
override fun setAdapter(adapter: Adapter<*>?) { override fun setAdapter(adapter: Adapter<*>?) {
@@ -140,8 +103,6 @@ class CarouselRecyclerView @JvmOverloads constructor(
super.setAdapter(adapter) super.setAdapter(adapter)
(adapter as? GameAdapter)?.registerAdapterDataObserver(carouselAdapterObserver) (adapter as? GameAdapter)?.registerAdapterDataObserver(carouselAdapterObserver)
updateCardGeometry()
applyCarouselPadding()
} }
private fun calculateCenter(width: Int, paddingStart: Int, paddingEnd: Int): Int { private fun calculateCenter(width: Int, paddingStart: Int, paddingEnd: Int): Int {
@@ -292,71 +253,40 @@ class CarouselRecyclerView @JvmOverloads constructor(
} }
} }
private fun resolveBottomInset(windowInsets: WindowInsetsCompat): Int { fun notifyInsetsReady(newBottomInset: Int) {
val navigationBottom = if (FullscreenHelper.isFullscreenEnabled(context)) { if (bottomInset != newBottomInset) {
0 bottomInset = newBottomInset
} else { }
windowInsets.getInsetsIgnoringVisibility(WindowInsetsCompat.Type.navigationBars()).bottom
if (isCarouselMode) {
setupCarousel(true)
} else {
setupCarousel(false)
} }
val gestureInsets = windowInsets.getInsetsIgnoringVisibility(
WindowInsetsCompat.Type.systemGestures()
)
val cutoutInsets = windowInsets.getInsetsIgnoringVisibility(
WindowInsetsCompat.Type.displayCutout()
)
return maxOf(navigationBottom, gestureInsets.bottom, cutoutInsets.bottom)
} }
private fun updateCardGeometry() { fun notifyLaidOut(fallBackBottomInset: Int) {
if (!isCarouselMode || height <= 0) return if (bottomInset < 0) bottomInset = fallBackBottomInset
var gameAdapter = adapter as? GameAdapter ?: return
var newCardSize = cardSize(bottomInset)
if (gameAdapter.cardSize != newCardSize) {
gameAdapter.setCardSize(newCardSize)
}
val gameAdapter = adapter as? GameAdapter ?: return if (isCarouselMode) {
val windowInsets = latestWindowInsets ?: ViewCompat.getRootWindowInsets(this) ?: return setupCarousel(true)
}
}
if (cardGeometryInitialized && !hasWindowFocus()) return fun cardSize(bottomInset: Int): Int {
val newBottomInset = resolveBottomInset(windowInsets).coerceIn(0, height)
val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1) val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1)
val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn( val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn(
0f, 0f,
1f 1f
) )
val screenWidth = resources.displayMetrics.widthPixels.toFloat() val scaledHeight = height * userFactor
val screenHeight = resources.displayMetrics.heightPixels.toFloat() val availableHeight = height - bottomInset
val aspectFactor = ((screenWidth / screenHeight) / (20f / 9f)) return minOf(scaledHeight.toInt(), availableHeight.toInt())
.pow(0.75f)
.coerceIn(0.5f, 1f)
val newCardSize = minOf(
(height * userFactor).toInt(),
height - newBottomInset,
(height * aspectFactor).toInt()
)
if (newCardSize <= 0) return
val insetChanged = bottomInset != newBottomInset
val cardSizeChanged = gameAdapter.cardSize != newCardSize
bottomInset = newBottomInset
cardGeometryInitialized = true
if (cardSizeChanged) gameAdapter.setCardSize(newCardSize)
if (insetChanged || cardSizeChanged) setupCarousel(true)
}
private fun applyCarouselPadding() {
if (!isCarouselMode) return
val gameAdapter = adapter as? GameAdapter ?: return
val cardSize = gameAdapter.cardSize
if (cardSize <= 0 || bottomInset < 0) return
val topPadding = ((height - bottomInset - cardSize) / 2).coerceAtLeast(0)
val sidePadding = (width - cardSize) / 2
if (paddingLeft != sidePadding || paddingTop != topPadding ||
paddingRight != sidePadding || paddingBottom != 0
) {
setPadding(sidePadding, topPadding, sidePadding, 0)
}
clipToPadding = false
} }
fun setupCarousel(enabled: Boolean) { fun setupCarousel(enabled: Boolean) {
@@ -385,6 +315,9 @@ class CarouselRecyclerView @JvmOverloads constructor(
internalFlingMultiplier internalFlingMultiplier
).coerceIn(1f, 5f) ).coerceIn(1f, 5f)
// Detach SnapHelper during setup
pagerSnapHelper?.attachToRecyclerView(null)
// Add overlap decoration if not present // Add overlap decoration if not present
if (overlapDecoration == null) { if (overlapDecoration == null) {
overlapDecoration = OverlappingDecoration(overlapPx) overlapDecoration = OverlappingDecoration(overlapPx)
@@ -402,7 +335,12 @@ class CarouselRecyclerView @JvmOverloads constructor(
addOnScrollListener(scalingScrollListener!!) addOnScrollListener(scalingScrollListener!!)
} }
applyCarouselPadding() if (cardSize > 0) {
val topPadding = ((height - bottomInset - cardSize) / 2).coerceAtLeast(0) // Center vertically
val sidePadding = (width - cardSize) / 2 // Center first/last card
setPadding(sidePadding, topPadding, sidePadding, 0)
clipToPadding = false
}
if (pagerSnapHelper == null) { if (pagerSnapHelper == null) {
pagerSnapHelper = CenterPagerSnapHelper() pagerSnapHelper = CenterPagerSnapHelper()
@@ -424,7 +362,6 @@ class CarouselRecyclerView @JvmOverloads constructor(
} }
savedItemAnimator = null savedItemAnimator = null
} }
cardGeometryInitialized = false
useCustomDrawingOrder = false useCustomDrawingOrder = false
// Reset padding and fling // Reset padding and fling
setPadding(0, 0, 0, 0) setPadding(0, 0, 0, 0)
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -5,17 +8,11 @@
#include "common/assert.h" #include "common/assert.h"
namespace AudioCore::ADSP::OpusDecoder { namespace AudioCore::ADSP::OpusDecoder {
namespace {
bool IsValidChannelCount(u32 channel_count) {
return channel_count == 1 || channel_count == 2;
}
} // namespace
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
if (!IsValidChannelCount(channel_count)) { if (channel_count == 1 || channel_count == 2)
return 0; return 0;
} return u32(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
} }
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
@@ -22,10 +22,6 @@ namespace AudioCore::ADSP::OpusDecoder {
namespace { namespace {
constexpr size_t OpusStreamCountMax = 255; constexpr size_t OpusStreamCountMax = 255;
bool IsValidChannelCount(u32 channel_count) {
return channel_count == 1 || channel_count == 2;
}
bool IsValidMultiStreamChannelCount(u32 channel_count) { bool IsValidMultiStreamChannelCount(u32 channel_count) {
return channel_count <= OpusStreamCountMax; return channel_count <= OpusStreamCountMax;
} }
+1 -1
View File
@@ -12,7 +12,7 @@
namespace AudioCore { namespace AudioCore {
AudioCore::AudioCore(Core::System& system) { AudioCore::AudioCore(Core::System& system) {
audio_manager.emplace(system); audio_manager.emplace();
CreateSinks(); CreateSinks();
// Must be created after the sinks // Must be created after the sinks
adsp.emplace(system, *output_sink); adsp.emplace(system, *output_sink);
+15 -12
View File
@@ -15,12 +15,12 @@
namespace AudioCore::AudioIn { namespace AudioCore::AudioIn {
Manager::Manager(Core::System& system) { Manager::Manager(Core::System& system_) : system{system_} {
std::iota(session_ids.begin(), session_ids.end(), 0); std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxInSessions; num_free_sessions = MaxInSessions;
} }
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) { Result Manager::AcquireSessionId(size_t& session_id) {
if (num_free_sessions == 0) { if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more"); LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions; return Service::Audio::ResultOutOfSessions;
@@ -31,7 +31,7 @@ Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
return ResultSuccess; return ResultSuccess;
} }
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) { void Manager::ReleaseSessionId(const size_t session_id) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id); LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id);
session_ids[free_session_id] = session_id; session_ids[free_session_id] = session_id;
@@ -41,20 +41,21 @@ void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
applet_resource_user_ids[session_id] = 0; applet_resource_user_ids[session_id] = 0;
} }
Result Manager::LinkToManager(Core::System& system) { Result Manager::LinkToManager() {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
if (!linked_to_manager) { if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetInManager(&Manager::BufferReleaseAndRegister); system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true; linked_to_manager = true;
} }
return ResultSuccess; return ResultSuccess;
} }
void Manager::Start(Core::System& system) { void Manager::Start() {
if (sessions_started) { if (sessions_started) {
return; return;
} }
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
for (auto& session : sessions) { for (auto& session : sessions) {
if (session) { if (session) {
@@ -65,19 +66,21 @@ void Manager::Start(Core::System& system) {
sessions_started = true; sessions_started = true;
} }
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept { void Manager::BufferReleaseAndRegister() {
Manager* this_ = (Manager*)data; std::scoped_lock l{mutex};
std::scoped_lock l{this_->mutex}; for (auto& session : sessions) {
for (auto& session : this_->sessions) {
if (session != nullptr) { if (session != nullptr) {
session->ReleaseAndRegisterBuffers(); session->ReleaseAndRegisterBuffers();
} }
} }
} }
u32 Manager::GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, [[maybe_unused]] const bool filter) { u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
LinkToManager(system);
LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (!input_devices.empty() && !names.empty()) { if (!input_devices.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac"); names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
+11 -10
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,29 +30,31 @@ public:
* @param session_id - Output session_id. * @param session_id - Output session_id.
* @return Result code. * @return Result code.
*/ */
Result AcquireSessionId(Core::System& system, size_t& session_id); Result AcquireSessionId(size_t& session_id);
/** /**
* Release a session id on close. * Release a session id on close.
* *
* @param session_id - Session id to free. * @param session_id - Session id to free.
*/ */
void ReleaseSessionId(Core::System& system, const size_t session_id); void ReleaseSessionId(size_t session_id);
/** /**
* Link the audio in manager to the main audio manager. * Link the audio in manager to the main audio manager.
* *
* @return Result code. * @return Result code.
*/ */
Result LinkToManager(Core::System& system); Result LinkToManager();
/** /**
* Start the audio in manager. * Start the audio in manager.
*/ */
void Start(Core::System& system); void Start();
/// @brief Callback function, called by the audio manager when the audio in event is signalled. /**
static void BufferReleaseAndRegister(void *data, Core::System& system) noexcept; * Callback function, called by the audio manager when the audio in event is signalled.
*/
void BufferReleaseAndRegister();
/** /**
* Get a list of audio in device names. * Get a list of audio in device names.
@@ -65,8 +64,10 @@ public:
* *
* @return Number of names written. * @return Number of names written.
*/ */
u32 GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter); u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
Core::System& system;
/// Array of session ids /// Array of session ids
std::array<size_t, MaxInSessions> session_ids{}; std::array<size_t, MaxInSessions> session_ids{};
/// Array of resource user ids /// Array of resource user ids
+3 -3
View File
@@ -11,8 +11,8 @@
namespace AudioCore { namespace AudioCore {
AudioManager::AudioManager(Core::System& system) { AudioManager::AudioManager() {
thread = std::jthread([&](std::stop_token stop_token) { thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("AudioManager"); Common::SetCurrentThreadName("AudioManager");
std::unique_lock l{events.GetAudioEventLock()}; std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents(); events.ClearEvents();
@@ -25,7 +25,7 @@ AudioManager::AudioManager(Core::System& system) {
const auto event_type = Event::Type(i); const auto event_type = Event::Type(i);
if (events.CheckAudioEventSet(event_type) || timed_out) { if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) { if (buffer_events[i]) {
buffer_events[i](this, system); buffer_events[i]();
} }
} }
events.SetAudioEvent(event_type, false); events.SetAudioEvent(event_type, false);
+3 -6
View File
@@ -16,10 +16,6 @@
#include "audio_core/audio_event.h" #include "audio_core/audio_event.h"
namespace Core {
class System;
}
union Result; union Result;
namespace AudioCore { namespace AudioCore {
@@ -38,9 +34,10 @@ namespace AudioCore {
* This is only used by audio in and audio out. * This is only used by audio in and audio out.
*/ */
class AudioManager { class AudioManager {
using BufferEventFunc = void (*)(void *data, Core::System& system) noexcept; using BufferEventFunc = std::function<void()>;
public: public:
explicit AudioManager(Core::System& system); explicit AudioManager();
/** /**
* Shutdown the audio manager. * Shutdown the audio manager.
+15 -10
View File
@@ -14,12 +14,12 @@
namespace AudioCore::AudioOut { namespace AudioCore::AudioOut {
Manager::Manager(Core::System& system) { Manager::Manager(Core::System& system_) : system{system_} {
std::iota(session_ids.begin(), session_ids.end(), 0); std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxOutSessions; num_free_sessions = MaxOutSessions;
} }
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) { Result Manager::AcquireSessionId(size_t& session_id) {
if (num_free_sessions == 0) { if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more"); LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions; return Service::Audio::ResultOutOfSessions;
@@ -30,7 +30,7 @@ Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
return ResultSuccess; return ResultSuccess;
} }
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) { void Manager::ReleaseSessionId(const size_t session_id) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id); LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id);
session_ids[free_session_id] = session_id; session_ids[free_session_id] = session_id;
@@ -40,17 +40,17 @@ void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
applet_resource_user_ids[session_id] = 0; applet_resource_user_ids[session_id] = 0;
} }
Result Manager::LinkToManager(Core::System& system) { Result Manager::LinkToManager() {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
if (!linked_to_manager) { if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetOutManager(&Manager::BufferReleaseAndRegister); system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true; linked_to_manager = true;
} }
return ResultSuccess; return ResultSuccess;
} }
void Manager::Start(Core::System& system) { void Manager::Start() {
if (sessions_started) { if (sessions_started) {
return; return;
} }
@@ -65,14 +65,19 @@ void Manager::Start(Core::System& system) {
sessions_started = true; sessions_started = true;
} }
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept { void Manager::BufferReleaseAndRegister() {
Manager* this_ = (Manager*)data; std::scoped_lock l{mutex};
std::scoped_lock l{this_->mutex}; for (auto& session : sessions) {
for (auto& session : this_->sessions) {
if (session != nullptr) { if (session != nullptr) {
session->ReleaseAndRegisterBuffers(); session->ReleaseAndRegisterBuffers();
} }
} }
} }
u32 Manager::GetAudioOutDeviceNames(
std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const {
names.emplace_back("DeviceOut");
return 1;
}
} // namespace AudioCore::AudioOut } // namespace AudioCore::AudioOut
+15 -8
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -32,32 +29,42 @@ public:
* @param session_id - Output session_id. * @param session_id - Output session_id.
* @return Result code. * @return Result code.
*/ */
Result AcquireSessionId(Core::System& system, size_t& session_id); Result AcquireSessionId(size_t& session_id);
/** /**
* Release a session id on close. * Release a session id on close.
* *
* @param session_id - Session id to free. * @param session_id - Session id to free.
*/ */
void ReleaseSessionId(Core::System& system, const size_t session_id); void ReleaseSessionId(size_t session_id);
/** /**
* Link this manager to the main audio manager. * Link this manager to the main audio manager.
* *
* @return Result code. * @return Result code.
*/ */
Result LinkToManager(Core::System& system); Result LinkToManager();
/** /**
* Start the audio out manager. * Start the audio out manager.
*/ */
void Start(Core::System& system); void Start();
/** /**
* Callback function, called by the audio manager when the audio out event is signalled. * Callback function, called by the audio manager when the audio out event is signalled.
*/ */
static void BufferReleaseAndRegister(void* data, Core::System& system) noexcept; void BufferReleaseAndRegister();
/**
* Get a list of audio out device names.
*
* @param names - Output container to write names to.
* @return Number of names written.
*/
u32 GetAudioOutDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const;
/// Core system
Core::System& system;
/// Array of session ids /// Array of session ids
std::array<size_t, MaxOutSessions> session_ids{}; std::array<size_t, MaxOutSessions> session_ids{};
/// Array of resource user ids /// Array of resource user ids
+3 -8
View File
@@ -1,20 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_render_manager.h" #include "audio_core/audio_render_manager.h"
#include "audio_core/common/audio_renderer_parameter.h" #include "audio_core/common/audio_renderer_parameter.h"
#include "audio_core/renderer/system_manager.h"
#include "audio_core/common/feature_support.h" #include "audio_core/common/feature_support.h"
#include "core/core.h" #include "core/core.h"
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
Manager::Manager(Core::System& system_) Manager::Manager(Core::System& system_)
: system_manager{std::make_unique<SystemManager>(system_)} : system{system_}, system_manager{std::make_unique<SystemManager>(system)} {
{
std::iota(session_ids.begin(), session_ids.end(), 0); std::iota(session_ids.begin(), session_ids.end(), 0);
} }
@@ -64,11 +59,11 @@ u32 Manager::GetSessionCount() const {
return session_count; return session_count;
} }
bool Manager::AddSystem(Renderer::System& system_) { bool Manager::AddSystem(System& system_) {
return system_manager->Add(system_); return system_manager->Add(system_);
} }
bool Manager::RemoveSystem(Renderer::System& system_) { bool Manager::RemoveSystem(System& system_) {
return system_manager->Remove(system_); return system_manager->Remove(system_);
} }
+4 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -74,7 +71,7 @@ public:
* @param system - The system to add. * @param system - The system to add.
* @return True if the system was successfully added, otherwise false. * @return True if the system was successfully added, otherwise false.
*/ */
bool AddSystem(Renderer::System& system); bool AddSystem(System& system);
/** /**
* Remove a renderer system from the manager. * Remove a renderer system from the manager.
@@ -82,7 +79,7 @@ public:
* @param system - The system to remove. * @param system - The system to remove.
* @return True if the system was successfully removed, otherwise false. * @return True if the system was successfully removed, otherwise false.
*/ */
bool RemoveSystem(Renderer::System& system); bool RemoveSystem(System& system);
/** /**
* Free a session id when the system wants to shut down. * Free a session id when the system wants to shut down.
@@ -92,6 +89,8 @@ public:
void ReleaseSessionId(s32 session_id); void ReleaseSessionId(s32 session_id);
private: private:
/// Core system
Core::System& system;
/// Session ids, -1 when in use /// Session ids, -1 when in use
std::array<s32, MaxRendererSessions> session_ids{}; std::array<s32, MaxRendererSessions> session_ids{};
/// Number of active renderers /// Number of active renderers
+22 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -19,9 +16,8 @@ namespace AudioCore {
*/ */
class WorkbufferAllocator { class WorkbufferAllocator {
public: public:
explicit WorkbufferAllocator(std::span<u8> buffer_) explicit WorkbufferAllocator(std::span<u8> buffer_, u64 size_)
: buffer{buffer_} : buffer{reinterpret_cast<u64>(buffer_.data())}, size{size_} {}
{}
/** /**
* Allocate the given count of T elements, aligned to alignment. * Allocate the given count of T elements, aligned to alignment.
@@ -33,31 +29,36 @@ public:
template <typename T> template <typename T>
std::span<T> Allocate(u64 count, u64 alignment) { std::span<T> Allocate(u64 count, u64 alignment) {
u64 out{0}; u64 out{0};
u64 byte_size = count * sizeof(T); u64 byte_size{count * sizeof(T)};
if (byte_size > 0) { if (byte_size > 0) {
auto current{uintptr_t(buffer.data()) + offset}; auto current{buffer + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)}; auto aligned_buffer{Common::AlignUp(current, alignment)};
if (aligned_buffer + byte_size <= uintptr_t(buffer.data()) + buffer.size()) { if (aligned_buffer + byte_size <= buffer + size) {
out = aligned_buffer; out = aligned_buffer;
offset = byte_size - uintptr_t(buffer.data()) + aligned_buffer; offset = byte_size - buffer + aligned_buffer;
} else { } else {
LOG_ERROR( LOG_ERROR(
Service_Audio, Service_Audio,
"Allocated buffer was too small to hold new alloc.\nAllocator size={:08X}, " "Allocated buffer was too small to hold new alloc.\nAllocator size={:08X}, "
"offset={:08X}.\nAttempting to allocate {:08X} with alignment={:02X}", "offset={:08X}.\nAttempting to allocate {:08X} with alignment={:02X}",
buffer.size(), offset, byte_size, alignment); size, offset, byte_size, alignment);
count = 0; count = 0;
} }
} }
return std::span<T>(reinterpret_cast<T*>(out), count); return std::span<T>(reinterpret_cast<T*>(out), count);
} }
/// @brief Align the current offset to the given alignment. /**
/// @param alignment - The required starting alignment. * Align the current offset to the given alignment.
*
* @param alignment - The required starting alignment.
*/
void Align(u64 alignment) { void Align(u64 alignment) {
auto current{uintptr_t(buffer.data()) + offset}; auto current{buffer + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)}; auto aligned_buffer{Common::AlignUp(current, alignment)};
offset = 0 - uintptr_t(buffer.data()) + aligned_buffer; offset = 0 - buffer + aligned_buffer;
} }
/** /**
@@ -75,7 +76,7 @@ public:
* @return The size of the current buffer. * @return The size of the current buffer.
*/ */
u64 GetSize() const { u64 GetSize() const {
return buffer.size(); return size;
} }
/** /**
@@ -84,11 +85,14 @@ public:
* @return The remaining size left in the buffer. * @return The remaining size left in the buffer.
*/ */
u64 GetRemainingSize() const { u64 GetRemainingSize() const {
return buffer.size() - offset; return size - offset;
} }
private: private:
const std::span<u8> buffer; /// The buffer into which we are allocating.
u64 buffer;
/// Size of the buffer we're allocating to.
u64 size;
/// Current offset into the buffer, an error will be thrown if it exceeds size. /// Current offset into the buffer, an error will be thrown if it exceeds size.
u64 offset{}; u64 offset{};
}; };
+20 -21
View File
@@ -11,43 +11,42 @@
namespace AudioCore::AudioIn { namespace AudioCore::AudioIn {
In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_) In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_} : manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
, audio_system{system_, event, session_id_} session_id_} {}
{}
void In::Free(Core::System& system) { void In::Free() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system, audio_system.GetSessionId()); manager.ReleaseSessionId(system.GetSessionId());
} }
System& In::GetSystem() { System& In::GetSystem() {
return audio_system; return system;
} }
AudioIn::State In::GetState() { AudioIn::State In::GetState() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetState(); return system.GetState();
} }
Result In::StartSystem() { Result In::StartSystem() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.Start(); return system.Start();
} }
void In::StartSession() { void In::StartSession() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
audio_system.StartSession(); system.StartSession();
} }
Result In::StopSystem() { Result In::StopSystem() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.Stop(); return system.Stop();
} }
Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) { Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
if (audio_system.AppendBuffer(buffer, tag)) { if (system.AppendBuffer(buffer, tag)) {
return ResultSuccess; return ResultSuccess;
} }
return Service::Audio::ResultBufferCountReached; return Service::Audio::ResultBufferCountReached;
@@ -55,20 +54,20 @@ Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
void In::ReleaseAndRegisterBuffers() { void In::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
if (audio_system.GetState() == State::Started) { if (system.GetState() == State::Started) {
audio_system.ReleaseBuffers(); system.ReleaseBuffers();
audio_system.RegisterBuffers(); system.RegisterBuffers();
} }
} }
bool In::FlushAudioInBuffers() { bool In::FlushAudioInBuffers() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.FlushAudioInBuffers(); return system.FlushAudioInBuffers();
} }
u32 In::GetReleasedBuffers(std::span<u64> tags) { u32 In::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetReleasedBuffers(tags); return system.GetReleasedBuffers(tags);
} }
Kernel::KReadableEvent& In::GetBufferEvent() { Kernel::KReadableEvent& In::GetBufferEvent() {
@@ -78,27 +77,27 @@ Kernel::KReadableEvent& In::GetBufferEvent() {
f32 In::GetVolume() const { f32 In::GetVolume() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetVolume(); return system.GetVolume();
} }
void In::SetVolume(f32 volume) { void In::SetVolume(f32 volume) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
audio_system.SetVolume(volume); system.SetVolume(volume);
} }
bool In::ContainsAudioBuffer(u64 tag) const { bool In::ContainsAudioBuffer(u64 tag) const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.ContainsAudioBuffer(tag); return system.ContainsAudioBuffer(tag);
} }
u32 In::GetBufferCount() const { u32 In::GetBufferCount() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetBufferCount(); return system.GetBufferCount();
} }
u64 In::GetPlayedSampleCount() const { u64 In::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetPlayedSampleCount(); return system.GetPlayedSampleCount();
} }
} // namespace AudioCore::AudioIn } // namespace AudioCore::AudioIn
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,7 +30,7 @@ public:
/** /**
* Free this audio in from the audio in manager. * Free this audio in from the audio in manager.
*/ */
void Free(Core::System& system); void Free();
/** /**
* Get this audio in's system. * Get this audio in's system.
@@ -144,7 +141,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released /// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event; Kernel::KEvent* event;
/// Main audio in system /// Main audio in system
System audio_system; System system;
}; };
} // namespace AudioCore::AudioIn } // namespace AudioCore::AudioIn
+4 -4
View File
@@ -14,14 +14,16 @@
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
namespace AudioCore::AudioIn {
// See texture_cache/util.h // See texture_cache/util.h
template<typename T, size_t N> template<typename T, size_t N>
#if BOOST_VERSION >= 108100 || __GNUC__ > 12 #if BOOST_VERSION >= 108100 || __GNUC__ > 12
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) { [[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
return v; return v;
} }
#else #else
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) { [[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
std::vector<T> u; std::vector<T> u;
for (auto const& e : v) for (auto const& e : v)
u.push_back(e); u.push_back(e);
@@ -29,8 +31,6 @@ template<typename T, size_t N>
} }
#endif #endif
namespace AudioCore::AudioIn {
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_) System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
: system{system_}, buffer_event{event_}, : system{system_}, buffer_event{event_},
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {} session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
+20 -24
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,43 +8,42 @@
namespace AudioCore::AudioOut { namespace AudioCore::AudioOut {
Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_) Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_} : manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
, audio_system{system_, event, session_id_} session_id_} {}
{}
void Out::Free(Core::System& system) { void Out::Free() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system, audio_system.GetSessionId()); manager.ReleaseSessionId(system.GetSessionId());
} }
System& Out::GetSystem() { System& Out::GetSystem() {
return audio_system; return system;
} }
AudioOut::State Out::GetState() { AudioOut::State Out::GetState() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetState(); return system.GetState();
} }
Result Out::StartSystem() { Result Out::StartSystem() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.Start(); return system.Start();
} }
void Out::StartSession() { void Out::StartSession() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
audio_system.StartSession(); system.StartSession();
} }
Result Out::StopSystem() { Result Out::StopSystem() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.Stop(); return system.Stop();
} }
Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) { Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
if (audio_system.AppendBuffer(buffer, tag)) { if (system.AppendBuffer(buffer, tag)) {
return ResultSuccess; return ResultSuccess;
} }
return Service::Audio::ResultBufferCountReached; return Service::Audio::ResultBufferCountReached;
@@ -55,20 +51,20 @@ Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
void Out::ReleaseAndRegisterBuffers() { void Out::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
if (audio_system.GetState() == State::Started) { if (system.GetState() == State::Started) {
audio_system.ReleaseBuffers(); system.ReleaseBuffers();
audio_system.RegisterBuffers(); system.RegisterBuffers();
} }
} }
bool Out::FlushAudioOutBuffers() { bool Out::FlushAudioOutBuffers() {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.FlushAudioOutBuffers(); return system.FlushAudioOutBuffers();
} }
u32 Out::GetReleasedBuffers(std::span<u64> tags) { u32 Out::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetReleasedBuffers(tags); return system.GetReleasedBuffers(tags);
} }
Kernel::KReadableEvent& Out::GetBufferEvent() { Kernel::KReadableEvent& Out::GetBufferEvent() {
@@ -78,27 +74,27 @@ Kernel::KReadableEvent& Out::GetBufferEvent() {
f32 Out::GetVolume() const { f32 Out::GetVolume() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetVolume(); return system.GetVolume();
} }
void Out::SetVolume(const f32 volume) { void Out::SetVolume(const f32 volume) {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
audio_system.SetVolume(volume); system.SetVolume(volume);
} }
bool Out::ContainsAudioBuffer(const u64 tag) const { bool Out::ContainsAudioBuffer(const u64 tag) const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.ContainsAudioBuffer(tag); return system.ContainsAudioBuffer(tag);
} }
u32 Out::GetBufferCount() const { u32 Out::GetBufferCount() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetBufferCount(); return system.GetBufferCount();
} }
u64 Out::GetPlayedSampleCount() const { u64 Out::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex}; std::scoped_lock l{parent_mutex};
return audio_system.GetPlayedSampleCount(); return system.GetPlayedSampleCount();
} }
} // namespace AudioCore::AudioOut } // namespace AudioCore::AudioOut
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,7 +30,7 @@ public:
/** /**
* Free this audio out from the audio out manager. * Free this audio out from the audio out manager.
*/ */
void Free(Core::System& system); void Free();
/** /**
* Get this audio out's system. * Get this audio out's system.
@@ -144,7 +141,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released /// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event; Kernel::KEvent* event;
/// Main audio out system /// Main audio out system
System audio_system; System system;
}; };
} // namespace AudioCore::AudioOut } // namespace AudioCore::AudioOut
+3 -4
View File
@@ -14,14 +14,15 @@
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
namespace AudioCore::AudioOut {
// See texture_cache/util.h // See texture_cache/util.h
template<typename T, size_t N> template<typename T, size_t N>
#if BOOST_VERSION >= 108100 || __GNUC__ > 12 #if BOOST_VERSION >= 108100 || __GNUC__ > 12
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) { [[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
return v; return v;
} }
#else #else
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) { [[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
std::vector<T> u; std::vector<T> u;
for (auto const& e : v) for (auto const& e : v)
u.push_back(e); u.push_back(e);
@@ -29,8 +30,6 @@ template<typename T, size_t N>
} }
#endif #endif
namespace AudioCore::AudioOut {
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_) System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
: system{system_}, buffer_event{event_}, : system{system_}, buffer_event{event_},
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {} session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
+23 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,48 +13,56 @@
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event) Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event)
: system{system_}, manager{manager_} : core{system_}, manager{manager_}, system{system_, rendered_event} {}
, audio_system{system_, rendered_event}
{}
Result Renderer::Initialize(const AudioRendererParameterInternal& params, Kernel::KTransferMemory* transfer_memory, const u64 transfer_memory_size, Kernel::KProcess* process_handle, const u64 applet_resource_user_id, const s32 session_id) { Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
const u64 applet_resource_user_id, const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) { if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(audio_system)) { if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio, "Both Audio Render sessions are in use, cannot create any more"); LOG_ERROR(Service_Audio,
"Both Audio Render sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions; return Service::Audio::ResultOutOfSessions;
} }
system_registered = true; system_registered = true;
} }
initialized = true; initialized = true;
audio_system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, applet_resource_user_id, session_id); system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
return ResultSuccess; return ResultSuccess;
} }
void Renderer::Finalize() { void Renderer::Finalize() {
auto const session_id{audio_system.GetSessionId()}; auto session_id{system.GetSessionId()};
audio_system.Finalize();
system.Finalize();
if (system_registered) { if (system_registered) {
manager.RemoveSystem(audio_system); manager.RemoveSystem(system);
system_registered = false; system_registered = false;
} }
manager.ReleaseSessionId(session_id); manager.ReleaseSessionId(session_id);
} }
System& Renderer::GetSystem() { System& Renderer::GetSystem() {
return audio_system; return system;
} }
void Renderer::Start() { void Renderer::Start() {
audio_system.Start(); system.Start();
} }
void Renderer::Stop() { void Renderer::Stop() {
audio_system.Stop(); system.Stop();
} }
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance, std::span<u8> output) { Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance,
return audio_system.Update(input, performance, output); std::span<u8> output) {
return system.Update(input, performance, output);
} }
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -87,7 +84,7 @@ public:
private: private:
/// System core /// System core
Core::System& system; Core::System& core;
/// Manager this renderer is registered with /// Manager this renderer is registered with
Manager& manager; Manager& manager;
/// Is the audio renderer initialized? /// Is the audio renderer initialized?
@@ -95,7 +92,7 @@ private:
/// Is the system registered with the manager? /// Is the system registered with the manager?
bool system_registered{}; bool system_registered{};
/// Audio render system, main driver of audio rendering /// Audio render system, main driver of audio rendering
System audio_system; System system;
}; };
} // namespace Renderer } // namespace Renderer
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -16,7 +16,7 @@ namespace AudioCore::Renderer {
* @param memory - Core memory for writing. * @param memory - Core memory for writing.
* @param aux_info - Memory address pointing to the AuxInfo to reset. * @param aux_info - Memory address pointing to the AuxInfo to reset.
*/ */
static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) { static void CaptureResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) {
if (aux_info == 0) { if (aux_info == 0) {
LOG_ERROR(Service_Audio, "Aux info is 0!"); LOG_ERROR(Service_Audio, "Aux info is 0!");
return; return;
@@ -134,7 +134,7 @@ void CaptureCommand::Process(const AudioRenderer::CommandListProcessor& processo
WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer, WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer,
processor.sample_count, write_offset, update_count); processor.sample_count, write_offset, update_count);
} else { } else {
ResetAuxBufferDsp(*processor.memory, send_buffer_info); CaptureResetAuxBufferDsp(*processor.memory, send_buffer_info);
} }
} }
+1 -1
View File
@@ -145,7 +145,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
PoolMapper pool_mapper(process_handle, false); PoolMapper pool_mapper(process_handle, false);
pool_mapper.InitializeSystemPool(memory_pool_info, workbuffer.get(), workbuffer_size); pool_mapper.InitializeSystemPool(memory_pool_info, workbuffer.get(), workbuffer_size);
WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size}); WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size}, workbuffer_size);
samples_workbuffer = samples_workbuffer =
allocator.Allocate<s32>((voice_channels + mix_buffer_count) * sample_count, 0x10); allocator.Allocate<s32>((voice_channels + mix_buffer_count) * sample_count, 0x10);
+9 -8
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2011 Google, Inc. // SPDX-FileCopyrightText: 2011 Google, Inc.
// SPDX-FileContributor: Geoff Pike // SPDX-FileContributor: Geoff Pike
// SPDX-FileContributor: Jyrki Alakuijala // SPDX-FileContributor: Jyrki Alakuijala
@@ -27,8 +30,6 @@
#define WORDS_BIGENDIAN 1 #define WORDS_BIGENDIAN 1
#endif #endif
using namespace std;
namespace Common { namespace Common {
static u64 unaligned_load64(const char* p) { static u64 unaligned_load64(const char* p) {
@@ -135,18 +136,18 @@ static u64 HashLen17to32(const char* s, size_t len) {
// Return a 16-byte hash for 48 bytes. Quick and dirty. // Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b. // Callers do best to use "random-looking" values for a and b.
static pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) { static std::pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
a += w; a += w;
b = Rotate(b + a + z, 21); b = Rotate(b + a + z, 21);
u64 c = a; u64 c = a;
a += x; a += x;
a += y; a += y;
b += Rotate(a, 44); b += Rotate(a, 44);
return make_pair(a + z, b + c); return std::make_pair(a + z, b + c);
} }
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) { static std::pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a, return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
b); b);
} }
@@ -189,8 +190,8 @@ u64 CityHash64(const char* s, size_t len) {
u64 x = Fetch64(s + len - 40); u64 x = Fetch64(s + len - 40);
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56); u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z); std::pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); std::pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s); x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@@ -258,7 +259,7 @@ u128 CityHash128WithSeed(const char* s, size_t len, u128 seed) {
// We expect len >= 128 to be the common case. Keep 56 bytes of state: // We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z. // v, w, x, y, and z.
pair<u64, u64> v, w; std::pair<u64, u64> v, w;
u64 x = seed[0]; u64 x = seed[0];
u64 y = seed[1]; u64 y = seed[1];
u64 z = len * k1; u64 z = len * k1;
+2
View File
@@ -16,3 +16,5 @@
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#undef INVALID_SOCKET
+4 -4
View File
@@ -11,14 +11,14 @@
namespace Common::Net { namespace Common::Net {
struct Asset { typedef struct {
std::string name; std::string name;
std::string url; std::string url;
std::string path; std::string path;
std::string filename; std::string filename;
}; } Asset;
struct Release { typedef struct Release {
std::string title; std::string title;
std::string body; std::string body;
std::string tag; std::string tag;
@@ -39,7 +39,7 @@ struct Release {
static std::optional<Release> FromJson(const std::string_view& json, const std::string &host, const std::string& repo); static std::optional<Release> FromJson(const std::string_view& json, const std::string &host, const std::string& repo);
static std::vector<Release> ListFromJson(const nlohmann::json &json, const std::string &host, const std::string &repo); static std::vector<Release> ListFromJson(const nlohmann::json &json, const std::string &host, const std::string &repo);
static std::vector<Release> ListFromJson(const std::string_view &json, const std::string &host, const std::string &repo); static std::vector<Release> ListFromJson(const std::string_view &json, const std::string &host, const std::string &repo);
}; } Release;
// Make a request via httplib, and return the response body if applicable. // Make a request via httplib, and return the response body if applicable.
std::optional<std::string> MakeRequest(const std::string &url, const std::string &path); std::optional<std::string> MakeRequest(const std::string &url, const std::string &path);
+7 -8
View File
@@ -7,19 +7,18 @@
#pragma once #pragma once
#include <dynarmic/interface/halt_reason.h> #include <dynarmic/interface/halt_reason.h>
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
namespace Core { namespace Core {
constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step; inline constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort; inline constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2; inline constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3; inline constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4; inline constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6; inline constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) { [[nodiscard]] inline constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
static_assert(u64(HaltReason::StepThread) == u64(StepThread)); static_assert(u64(HaltReason::StepThread) == u64(StepThread));
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort)); static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop)); static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop));
+6 -34
View File
@@ -4,7 +4,6 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <unordered_map>
#include <utility> #include <utility>
#include "game_settings.h" #include "game_settings.h"
@@ -249,30 +248,12 @@ struct System::Impl {
} }
} }
void NotifyNVDECChannelOpen(u64 process_id) { void SetNVDECActive(bool is_nvdec_active) {
std::scoped_lock lock{nvdec_active_mutex}; nvdec_active = is_nvdec_active;
++nvdec_active_channels[process_id];
}
void NotifyNVDECChannelClose(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
const auto it = nvdec_active_channels.find(process_id);
if (it == nvdec_active_channels.end()) {
return;
}
if (--it->second == 0) {
nvdec_active_channels.erase(it);
}
} }
bool GetNVDECActive() { bool GetNVDECActive() {
std::scoped_lock lock{nvdec_active_mutex}; return nvdec_active;
return !nvdec_active_channels.empty();
}
bool IsNVDECActiveForProcess(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
return nvdec_active_channels.contains(process_id);
} }
void InitializeDebugger(System& system, u16 port) { void InitializeDebugger(System& system, u16 port) {
@@ -524,8 +505,6 @@ struct System::Impl {
mutable std::mutex suspend_guard; mutable std::mutex suspend_guard;
std::mutex general_channel_mutex; std::mutex general_channel_mutex;
std::mutex nvdec_active_mutex;
std::unordered_map<u64, u32> nvdec_active_channels;
std::atomic_bool is_paused{}; std::atomic_bool is_paused{};
std::atomic_bool is_shutting_down{}; std::atomic_bool is_shutting_down{};
std::atomic_bool is_powered_on{}; std::atomic_bool is_powered_on{};
@@ -533,6 +512,7 @@ struct System::Impl {
bool extended_memory_layout : 1 = false; bool extended_memory_layout : 1 = false;
bool exit_locked : 1 = false; bool exit_locked : 1 = false;
bool exit_requested : 1 = false; bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;
void EnsureGeneralChannelInitialized(System& system) { void EnsureGeneralChannelInitialized(System& system) {
if (!general_channel_event) { if (!general_channel_event) {
@@ -596,22 +576,14 @@ void System::UnstallApplication() {
impl->UnstallApplication(); impl->UnstallApplication();
} }
void System::NotifyNVDECChannelOpen(u64 process_id) { void System::SetNVDECActive(bool is_nvdec_active) {
impl->NotifyNVDECChannelOpen(process_id); impl->SetNVDECActive(is_nvdec_active);
}
void System::NotifyNVDECChannelClose(u64 process_id) {
impl->NotifyNVDECChannelClose(process_id);
} }
bool System::GetNVDECActive() { bool System::GetNVDECActive() {
return impl->GetNVDECActive(); return impl->GetNVDECActive();
} }
bool System::IsNVDECActiveForProcess(u64 process_id) {
return impl->IsNVDECActiveForProcess(process_id);
}
void System::InitializeDebugger() { void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
} }
+1 -3
View File
@@ -191,10 +191,8 @@ public:
std::unique_lock<std::mutex> StallApplication(); std::unique_lock<std::mutex> StallApplication();
void UnstallApplication(); void UnstallApplication();
void NotifyNVDECChannelOpen(u64 process_id); void SetNVDECActive(bool is_nvdec_active);
void NotifyNVDECChannelClose(u64 process_id);
[[nodiscard]] bool GetNVDECActive(); [[nodiscard]] bool GetNVDECActive();
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
/** /**
* Initialize the debugger. * Initialize the debugger.
+1
View File
@@ -38,6 +38,7 @@ constexpr u32 CpuClockTargetMhz(Settings::CpuClock clock) {
} }
} }
#undef CreateEvent
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
return std::make_shared<EventType>(std::move(callback), std::move(name)); return std::make_shared<EventType>(std::move(callback), std::move(name));
} }
+5 -5
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -185,13 +185,13 @@ static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size."
static_assert(std::is_trivially_copyable_v<SaveDataFilter>, static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
"Data type must be trivially copyable."); "Data type must be trivially copyable.");
struct HashSalt { struct SaveDataHashSalt {
static constexpr size_t Size = 32; static constexpr size_t Size = 32;
std::array<u8, Size> value; std::array<u8, Size> value;
}; };
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable."); static_assert(std::is_trivially_copyable_v<SaveDataHashSalt>, "Data type must be trivially copyable.");
static_assert(sizeof(HashSalt) == HashSalt::Size); static_assert(sizeof(SaveDataHashSalt) == SaveDataHashSalt::Size);
struct SaveDataCreationInfo2 { struct SaveDataCreationInfo2 {
@@ -210,7 +210,7 @@ struct SaveDataCreationInfo2 {
u8 reserved1; u8 reserved1;
bool is_hash_salt_enabled; bool is_hash_salt_enabled;
u8 reserved2; u8 reserved2;
HashSalt hash_salt; SaveDataHashSalt hash_salt;
SaveDataMetaType meta_type; SaveDataMetaType meta_type;
u8 reserved3; u8 reserved3;
s32 meta_size; s32 meta_size;
+4 -1
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,7 +14,7 @@
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_vector.h" #include "core/file_sys/vfs/vfs_vector.h"
namespace FileSys { namespace FileSys::RomFSBuilder {
constexpr u64 FS_MAX_PATH = 0x301; constexpr u64 FS_MAX_PATH = 0x301;
+4 -1
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,7 +12,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
namespace FileSys { namespace FileSys::RomFSBuilder {
struct RomFSBuildDirectoryContext; struct RomFSBuildDirectoryContext;
struct RomFSBuildFileContext; struct RomFSBuildFileContext;
+10 -10
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -38,7 +38,7 @@ struct RomFSHeader {
}; };
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
struct DirectoryEntry { struct RomFSDirectoryEntry {
u32_le parent; u32_le parent;
u32_le sibling; u32_le sibling;
u32_le child_dir; u32_le child_dir;
@@ -46,9 +46,9 @@ struct DirectoryEntry {
u32_le hash; u32_le hash;
u32_le name_length; u32_le name_length;
}; };
static_assert(sizeof(DirectoryEntry) == 0x18, "DirectoryEntry has incorrect size."); static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size.");
struct FileEntry { struct RomFSFileEntry {
u32_le parent; u32_le parent;
u32_le sibling; u32_le sibling;
u64_le offset; u64_le offset;
@@ -56,7 +56,7 @@ struct FileEntry {
u32_le hash; u32_le hash;
u32_le name_length; u32_le name_length;
}; };
static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size.");
struct RomFSTraversalContext { struct RomFSTraversalContext {
RomFSHeader header; RomFSHeader header;
@@ -84,14 +84,14 @@ std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, siz
return {entry, std::move(name)}; return {entry, std::move(name)};
} }
std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx, std::pair<RomFSDirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
size_t directory_offset) { size_t directory_offset) {
return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset); return GetEntry<RomFSDirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
} }
std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx, std::pair<RomFSFileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
size_t file_offset) { size_t file_offset) {
return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset); return GetEntry<RomFSFileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
} }
void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset, void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
@@ -163,7 +163,7 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
if (dir == nullptr) if (dir == nullptr)
return nullptr; return nullptr;
RomFSBuildContext ctx{dir, ext}; RomFSBuilder::RomFSBuildContext ctx{dir, ext};
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build()); return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
} }
+7 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -10,6 +10,12 @@
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
#undef CreateFile
#undef DeleteFile
#undef CreateDirectory
#undef CopyFile
#undef MoveFile
namespace FileSys { namespace FileSys {
VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {} VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
+5 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -99,6 +99,10 @@ private:
std::string name; std::string name;
}; };
#undef CreateFile
#undef DeleteFile
#undef CreateDirectory
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files. // An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
// Vector data is supplied upon construction. // Vector data is supplied upon construction.
class VectorVfsDirectory : public VfsDirectory { class VectorVfsDirectory : public VfsDirectory {
+2 -2
View File
@@ -1216,7 +1216,7 @@ Result KServerSession::ReceiveRequest(KernelCore& kernel, uintptr_t server_messa
} }
Result KServerSession::SendReply(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size, Result KServerSession::SendReply(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr, bool is_hle, bool session_closed) { KPhysicalAddress server_message_paddr, bool is_hle) {
// Lock the session. // Lock the session.
KScopedLightLock lk{m_lock}; KScopedLightLock lk{m_lock};
@@ -1248,7 +1248,7 @@ Result KServerSession::SendReply(KernelCore& kernel, uintptr_t server_message, u
KEvent* event = request->GetEvent(); KEvent* event = request->GetEvent();
// Check whether we're closed. // Check whether we're closed.
const bool closed = (client_thread == nullptr || m_parent->IsClientClosed() || session_closed); const bool closed = (client_thread == nullptr || m_parent->IsClientClosed());
Result result = ResultSuccess; Result result = ResultSuccess;
if (!closed) { if (!closed) {
+3 -3
View File
@@ -54,14 +54,14 @@ public:
Result OnRequest(KernelCore& kernel, KSessionRequest* request); Result OnRequest(KernelCore& kernel, KSessionRequest* request);
Result SendReply(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size, Result SendReply(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr, bool is_hle = false, bool session_closed = false); KPhysicalAddress server_message_paddr, bool is_hle = false);
Result ReceiveRequest(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size, Result ReceiveRequest(KernelCore& kernel, uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr, KPhysicalAddress server_message_paddr,
std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
std::weak_ptr<Service::SessionRequestManager> manager = {}); std::weak_ptr<Service::SessionRequestManager> manager = {});
Result SendReplyHLE(KernelCore& kernel, bool session_closed = false) { Result SendReplyHLE(KernelCore& kernel) {
R_RETURN(this->SendReply(kernel, 0, 0, 0, true, session_closed)); R_RETURN(this->SendReply(kernel, 0, 0, 0, true));
} }
Result ReceiveRequestHLE(KernelCore& kernel, std::shared_ptr<Service::HLERequestContext>* out_context, Result ReceiveRequestHLE(KernelCore& kernel, std::shared_ptr<Service::HLERequestContext>* out_context,
+5 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-late // SPDX-License-Identifier: GPL-2.0-or-late
@@ -13,6 +13,10 @@
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc.h"
#undef OutputDebugString
#undef GetObject
#undef CreateProcess
namespace Kernel::Svc { namespace Kernel::Svc {
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) { static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
+10 -10
View File
@@ -11,7 +11,11 @@
namespace Kernel::Svc { namespace Kernel::Svc {
namespace { namespace {
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { [[nodiscard]] inline constexpr bool IsValidSetAddressRange(u64 address, u64 size) {
return address + size > address;
}
[[nodiscard]] inline constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
switch (perm) { switch (perm) {
case MemoryPermission::None: case MemoryPermission::None:
case MemoryPermission::Read: case MemoryPermission::Read:
@@ -22,13 +26,6 @@ constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
} }
} }
// Checks if address + size is greater than the given address
// This can return false if the size causes an overflow of a 64-bit type
// or if the given size is zero.
constexpr bool IsValidAddressRange(u64 address, u64 size) {
return address + size > address;
}
// Helper function that performs the common sanity checks for svcMapMemory // Helper function that performs the common sanity checks for svcMapMemory
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing // and svcUnmapMemory. This is doable, as both functions perform their sanitizing
// in the same order. // in the same order.
@@ -53,14 +50,17 @@ Result MapUnmapMemorySanityChecks(const KProcessPageTable& manager, u64 dst_addr
R_THROW(ResultInvalidSize); R_THROW(ResultInvalidSize);
} }
if (!IsValidAddressRange(dst_addr, size)) { // Checks if address + size is greater than the given address
// This can return false if the size causes an overflow of a 64-bit type
// or if the given size is zero.
if (!IsValidSetAddressRange(dst_addr, size)) {
LOG_ERROR(Kernel_SVC, LOG_ERROR(Kernel_SVC,
"Destination is not a valid address range, addr={:#016x}, size={:#016x}", "Destination is not a valid address range, addr={:#016x}, size={:#016x}",
dst_addr, size); dst_addr, size);
R_THROW(ResultInvalidCurrentMemory); R_THROW(ResultInvalidCurrentMemory);
} }
if (!IsValidAddressRange(src_addr, size)) { if (!IsValidSetAddressRange(src_addr, size)) {
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr={:#016x}, size={:#016x}", LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr={:#016x}, size={:#016x}",
src_addr, size); src_addr, size);
R_THROW(ResultInvalidCurrentMemory); R_THROW(ResultInvalidCurrentMemory);
@@ -11,11 +11,11 @@
namespace Kernel::Svc { namespace Kernel::Svc {
namespace { namespace {
constexpr bool IsValidAddressRange(u64 address, u64 size) { [[nodiscard]] inline constexpr bool IsValidAddressRange(u64 address, u64 size) {
return address + size > address; return address + size > address;
} }
constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { [[nodiscard]] inline constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) { switch (perm) {
case Svc::MemoryPermission::None: case Svc::MemoryPermission::None:
case Svc::MemoryPermission::Read: case Svc::MemoryPermission::Read:
+6 -7
View File
@@ -9,13 +9,12 @@
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
namespace Service::Audio { namespace Service::Audio {
using namespace AudioCore::AudioIn;
IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id, IAudioIn::IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager, size_t session_id,
const std::string& device_name, const AudioInParameter& in_params, const std::string& device_name, const AudioCore::AudioIn::AudioInParameter& in_params,
Kernel::KProcess* handle, u64 applet_resource_user_id) Kernel::KProcess* handle, u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"}, : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_, event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<AudioCore::AudioIn::In>(system_,
manager, event, manager, event,
session_id)} { session_id)} {
// clang-format off // clang-format off
@@ -50,7 +49,7 @@ IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
} }
IAudioIn::~IAudioIn() { IAudioIn::~IAudioIn() {
impl->Free(system); impl->Free();
service_context.CloseEvent(event); service_context.CloseEvent(event);
process->Close(system.Kernel()); process->Close(system.Kernel());
} }
@@ -71,12 +70,12 @@ Result IAudioIn::Stop() {
R_RETURN(impl->StopSystem()); R_RETURN(impl->StopSystem());
} }
Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer, Result IAudioIn::AppendAudioInBuffer(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
u64 buffer_client_ptr) { u64 buffer_client_ptr) {
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr)); R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
} }
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer, Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
u64 buffer_client_ptr) { u64 buffer_client_ptr) {
if (buffer.empty()) { if (buffer.empty()) {
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!"); LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
+10 -11
View File
@@ -10,7 +10,6 @@
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
namespace Service::Audio { namespace Service::Audio {
using namespace AudioCore::AudioIn;
IAudioInManager::IAudioInManager(Core::System& system_) IAudioInManager::IAudioInManager(Core::System& system_)
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
@@ -37,11 +36,11 @@ Result IAudioInManager::ListAudioIns(
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count)); R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
} }
Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal, Result IAudioInManager::OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
Out<SharedPointer<IAudioIn>> out_audio_in, Out<SharedPointer<IAudioIn>> out_audio_in,
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
AudioInParameter parameter, AudioCore::AudioIn::AudioInParameter parameter,
InCopyHandle<Kernel::KProcess> process_handle, InCopyHandle<Kernel::KProcess> process_handle,
ClientAppletResourceUserId aruid) { ClientAppletResourceUserId aruid) {
LOG_DEBUG(Service_Audio, "called"); LOG_DEBUG(Service_Audio, "called");
@@ -56,9 +55,9 @@ Result IAudioInManager::ListAudioInsAuto(
} }
Result IAudioInManager::OpenAudioInAuto( Result IAudioInManager::OpenAudioInAuto(
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter, InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioIn::AudioInParameter parameter,
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
LOG_DEBUG(Service_Audio, "called"); LOG_DEBUG(Service_Audio, "called");
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name, R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
@@ -68,15 +67,15 @@ Result IAudioInManager::OpenAudioInAuto(
Result IAudioInManager::ListAudioInsAutoFiltered( Result IAudioInManager::ListAudioInsAutoFiltered(
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) { OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
LOG_DEBUG(Service_Audio, "called"); LOG_DEBUG(Service_Audio, "called");
*out_count = impl->GetDeviceNames(system, out_audio_ins, true); *out_count = impl->GetDeviceNames(out_audio_ins, true);
R_SUCCEED(); R_SUCCEED();
} }
Result IAudioInManager::OpenAudioInProtocolSpecified( Result IAudioInManager::OpenAudioInProtocolSpecified(
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol, InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle, AudioCore::AudioIn::AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
ClientAppletResourceUserId aruid) { ClientAppletResourceUserId aruid) {
LOG_DEBUG(Service_Audio, "called"); LOG_DEBUG(Service_Audio, "called");
@@ -93,8 +92,8 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
size_t new_session_id{}; size_t new_session_id{};
R_TRY(impl->LinkToManager(system)); R_TRY(impl->LinkToManager());
R_TRY(impl->AcquireSessionId(system, new_session_id)); R_TRY(impl->AcquireSessionId(new_session_id));
LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id, LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
impl->num_free_sessions); impl->num_free_sessions);
@@ -107,7 +106,7 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
auto& out_system = impl->sessions[new_session_id]->GetSystem(); auto& out_system = impl->sessions[new_session_id]->GetSystem();
*out_parameter_internal = *out_parameter_internal =
AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(), AudioCore::AudioIn::AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
.channel_count = out_system.GetChannelCount(), .channel_count = out_system.GetChannelCount(),
.sample_format = static_cast<u32>(out_system.GetSampleFormat()), .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
.state = static_cast<u32>(out_system.GetState())}; .state = static_cast<u32>(out_system.GetState())};
+5 -6
View File
@@ -13,10 +13,9 @@
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Service::Audio { namespace Service::Audio {
using namespace AudioCore::AudioOut;
IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id, IAudioOut::IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, size_t session_id,
const std::string& device_name, const AudioOutParameter& in_params, const std::string& device_name, const AudioCore::AudioOut::AudioOutParameter& in_params,
Kernel::KProcess* handle, u64 applet_resource_user_id) Kernel::KProcess* handle, u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
@@ -46,7 +45,7 @@ IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
} }
IAudioOut::~IAudioOut() { IAudioOut::~IAudioOut() {
impl->Free(system); impl->Free();
service_context.CloseEvent(event); service_context.CloseEvent(event);
process->Close(system.Kernel()); process->Close(system.Kernel());
} }
@@ -68,12 +67,12 @@ Result IAudioOut::Stop() {
} }
Result IAudioOut::AppendAudioOutBuffer( Result IAudioOut::AppendAudioOutBuffer(
InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) { InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr)); R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
} }
Result IAudioOut::AppendAudioOutBufferAuto( Result IAudioOut::AppendAudioOutBufferAuto(
InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) { InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
if (audio_out_buffer.empty()) { if (audio_out_buffer.empty()) {
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!"); LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
R_THROW(Audio::ResultInsufficientBuffer); R_THROW(Audio::ResultInsufficientBuffer);
@@ -11,7 +11,6 @@
#include "core/memory.h" #include "core/memory.h"
namespace Service::Audio { namespace Service::Audio {
using namespace AudioCore::AudioOut;
IAudioOutManager::IAudioOutManager(Core::System& system_) IAudioOutManager::IAudioOutManager(Core::System& system_)
: ServiceFramework{system_, "audout:u"} : ServiceFramework{system_, "audout:u"}
@@ -36,11 +35,11 @@ Result IAudioOutManager::ListAudioOuts(
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count)); R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
} }
Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal, Result IAudioOutManager::OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
Out<SharedPointer<IAudioOut>> out_audio_out, Out<SharedPointer<IAudioOut>> out_audio_out,
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
AudioOutParameter parameter, AudioCore::AudioOut::AudioOutParameter parameter,
InCopyHandle<Kernel::KProcess> process_handle, InCopyHandle<Kernel::KProcess> process_handle,
ClientAppletResourceUserId aruid) { ClientAppletResourceUserId aruid) {
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name, R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
@@ -62,10 +61,10 @@ Result IAudioOutManager::ListAudioOutsAuto(
} }
Result IAudioOutManager::OpenAudioOutAuto( Result IAudioOutManager::OpenAudioOutAuto(
Out<AudioOutParameterInternal> out_parameter_internal, Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
Out<SharedPointer<IAudioOut>> out_audio_out, Out<SharedPointer<IAudioOut>> out_audio_out,
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter, InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioOut::AudioOutParameter parameter,
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
if (!process_handle) { if (!process_handle) {
LOG_ERROR(Service_Audio, "Failed to get process handle"); LOG_ERROR(Service_Audio, "Failed to get process handle");
@@ -77,8 +76,8 @@ Result IAudioOutManager::OpenAudioOutAuto(
} }
size_t new_session_id{}; size_t new_session_id{};
R_TRY(impl->LinkToManager(system)); R_TRY(impl->LinkToManager());
R_TRY(impl->AcquireSessionId(system, new_session_id)); R_TRY(impl->AcquireSessionId(new_session_id));
const auto device_name = Common::StringFromBuffer(name[0].name); const auto device_name = Common::StringFromBuffer(name[0].name);
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
@@ -95,7 +94,7 @@ Result IAudioOutManager::OpenAudioOutAuto(
auto& out_system = impl->sessions[new_session_id]->GetSystem(); auto& out_system = impl->sessions[new_session_id]->GetSystem();
*out_parameter_internal = *out_parameter_internal =
AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(), AudioCore::AudioOut::AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
.channel_count = out_system.GetChannelCount(), .channel_count = out_system.GetChannelCount(),
.sample_format = static_cast<u32>(out_system.GetSampleFormat()), .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
.state = static_cast<u32>(out_system.GetState())}; .state = static_cast<u32>(out_system.GetState())};
@@ -4,21 +4,20 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/renderer/audio_renderer.h"
#include "core/hle/service/audio/audio_renderer.h" #include "core/hle/service/audio/audio_renderer.h"
#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/cmif_serialization.h"
namespace Service::Audio { namespace Service::Audio {
using namespace AudioCore::Renderer;
IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_, IAudioRenderer::IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
AudioCore::AudioRendererParameterInternal& params, AudioCore::AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
Kernel::KProcess* process_handle_, u64 applet_resource_user_id, Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
s32 session_id) s32 session_id)
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{ impl{std::make_unique<AudioCore::Renderer::Renderer>(system_, manager, rendered_event)}, process_handle{process_handle_} {
process_handle_} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"}, {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
@@ -14,16 +14,13 @@
#include <cstring> #include <cstring>
namespace Service::News { namespace Service::News {
namespace {
std::string_view ToStringView(std::span<const char> buf) { [[nodiscard]] inline std::string_view ToStringViewNDS(std::span<const char> buf) {
const std::string_view sv{buf.data(), buf.size()}; const std::string_view sv{buf.data(), buf.size()};
const auto nul = sv.find('\0'); const auto nul = sv.find('\0');
return nul == std::string_view::npos ? sv : sv.substr(0, nul); return nul == std::string_view::npos ? sv : sv.substr(0, nul);
} }
} // namespace
INewsDataService::INewsDataService(Core::System& system_) INewsDataService::INewsDataService(Core::System& system_)
: ServiceFramework{system_, "INewsDataService"} { : ServiceFramework{system_, "INewsDataService"} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
@@ -55,7 +52,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
const auto list = NewsStorage::Instance().ListAll(); const auto list = NewsStorage::Instance().ListAll();
if (!list.empty()) { if (!list.empty()) {
if (auto found = NewsStorage::Instance().FindByNewsId(ToStringView(list.front().news_id))) { if (auto found = NewsStorage::Instance().FindByNewsId(ToStringViewNDS(list.front().news_id))) {
opened_payload = std::move(found->payload); opened_payload = std::move(found->payload);
return true; return true;
} }
@@ -67,7 +64,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) { Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
EnsureBuiltinNewsLoaded(); EnsureBuiltinNewsLoaded();
const auto key = ToStringView({reinterpret_cast<const char*>(name.data()), name.size()}); const auto key = ToStringViewNDS({reinterpret_cast<const char*>(name.data()), name.size()});
if (TryOpen(key, {})) { if (TryOpen(key, {})) {
R_SUCCEED(); R_SUCCEED();
@@ -79,8 +76,8 @@ Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) { Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
EnsureBuiltinNewsLoaded(); EnsureBuiltinNewsLoaded();
const auto key = ToStringView(record.news_id); const auto key = ToStringViewNDS(record.news_id);
const auto user = ToStringView(record.user_id); const auto user = ToStringViewNDS(record.user_id);
if (TryOpen(key, user)) { if (TryOpen(key, user)) {
R_SUCCEED(); R_SUCCEED();
@@ -92,8 +89,8 @@ Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
Result INewsDataService::OpenWithNewsRecord(NewsRecord record) { Result INewsDataService::OpenWithNewsRecord(NewsRecord record) {
EnsureBuiltinNewsLoaded(); EnsureBuiltinNewsLoaded();
const auto key = ToStringView(record.news_id); const auto key = ToStringViewNDS(record.news_id);
const auto user = ToStringView(record.user_id); const auto user = ToStringViewNDS(record.user_id);
if (TryOpen(key, user)) { if (TryOpen(key, user)) {
R_SUCCEED(); R_SUCCEED();
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -15,13 +15,13 @@
namespace Service::News { namespace Service::News {
namespace { namespace {
std::string_view ToStringView(std::span<const u8> buf) { [[nodiscard]] inline std::string_view ToStringView(std::span<const u8> buf) {
if (buf.empty()) return {}; if (buf.empty()) return {};
auto data = reinterpret_cast<const char*>(buf.data()); auto data = reinterpret_cast<const char*>(buf.data());
return {data, strnlen(data, buf.size())}; return {data, strnlen(data, buf.size())};
} }
std::string_view ToStringView(std::span<const char> buf) { [[nodiscard]] inline std::string_view ToStringView(std::span<const char> buf) {
if (buf.empty()) return {}; if (buf.empty()) return {};
return {buf.data(), strnlen(buf.data(), buf.size())}; return {buf.data(), strnlen(buf.data(), buf.size())};
} }
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@@ -6,6 +9,8 @@
namespace Service::News { namespace Service::News {
#undef CreateEvent
IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_) IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
: ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_, : ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
"IOverwriteEventHolder"} { "IOverwriteEventHolder"} {
@@ -18,6 +18,8 @@
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#undef GetCurrentTime
namespace Service::Capture { namespace Service::Capture {
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {} AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
+2
View File
@@ -19,6 +19,8 @@
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/reporter.h" #include "core/reporter.h"
#undef far
namespace Service::Fatal { namespace Service::Fatal {
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
@@ -32,6 +32,10 @@
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#undef CreateFile
#undef DeleteFile
#undef CreateDirectory
namespace Service::FileSystem { namespace Service::FileSystem {
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
@@ -227,13 +231,12 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
std::string src_path(Common::FS::SanitizePath(src_path_)); std::string src_path(Common::FS::SanitizePath(src_path_));
std::string dest_path(Common::FS::SanitizePath(dest_path_)); std::string dest_path(Common::FS::SanitizePath(dest_path_));
auto src = GetDirectoryRelativeWrapped(backing, src_path); auto src = GetDirectoryRelativeWrapped(backing, src_path);
if (src == nullptr)
return FileSys::ResultPathNotFound;
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
std::string full_src_path = backing->GetFullPath() + "/" + src_path; // Use more-optimized vfs implementation rename.
std::string full_dest_path = backing->GetFullPath() + "/" + dest_path; if (src == nullptr)
if (!Common::FS::RenameDir(full_src_path, full_dest_path)) { return FileSys::ResultPathNotFound;
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
// TODO(DarkLordZach): Find a better error code for this
return ResultUnknown; return ResultUnknown;
} }
return ResultSuccess; return ResultSuccess;
@@ -24,7 +24,7 @@ IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGe
{3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"}, {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
{4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"}, {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
{5, D<&IFileSystem::RenameFile>, "RenameFile"}, {5, D<&IFileSystem::RenameFile>, "RenameFile"},
{6, D<&IFileSystem::RenameDirectory>, "RenameDirectory"}, {6, nullptr, "RenameDirectory"},
{7, D<&IFileSystem::GetEntryType>, "GetEntryType"}, {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
{8, D<&IFileSystem::OpenFile>, "OpenFile"}, {8, D<&IFileSystem::OpenFile>, "OpenFile"},
{9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"}, {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
@@ -88,14 +88,6 @@ Result IFileSystem::RenameFile(
R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str))); R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
} }
Result IFileSystem::RenameDirectory(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
LOG_DEBUG(Service_FS, "called. directory '{}' to directory '{}'", old_path->str, new_path->str);
R_RETURN(backend->RenameDirectory(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
}
Result IFileSystem::OpenFile(OutInterface<IFile> out_interface, Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
u32 mode) { u32 mode) {
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -39,8 +36,6 @@ public:
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path, Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path); const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
Result RenameDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
Result OpenFile(OutInterface<IFile> out_interface, Result OpenFile(OutInterface<IFile> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode); const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
Result OpenDirectory(OutInterface<IDirectory> out_interface, Result OpenDirectory(OutInterface<IDirectory> out_interface,
+2
View File
@@ -27,6 +27,8 @@
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/memory.h" #include "core/memory.h"
#undef SendMessage
namespace Service { namespace Service {
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_) SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
+2 -1
View File
@@ -212,8 +212,9 @@ struct NifmNetworkProfileData {
NifmWirelessSettingData wireless_setting_data{}; NifmWirelessSettingData wireless_setting_data{};
IpSettingData ip_setting_data{}; IpSettingData ip_setting_data{};
}; };
static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
"NifmNetworkProfileData has incorrect size.");
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size.");
struct PendingProfile { struct PendingProfile {
std::array<char, 0x21> ssid{}; std::array<char, 0x21> ssid{};
@@ -8,7 +8,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging.h" #include "common/logging.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
@@ -72,23 +71,17 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started"); LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id; sessions[fd] = session_id;
if (const auto* session = core.GetSession(session_id);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelOpen(session->process->GetId());
}
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint); host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
} }
void nvhost_nvdec::OnClose(DeviceFD fd) { void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec); host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd); auto it = sessions.find(fd);
if (it != sessions.end()) { if (it != sessions.end()) {
if (const auto* session = core.GetSession(it->second);
session != nullptr && session->process != nullptr) {
system.NotifyNVDECChannelClose(session->process->GetId());
}
sessions.erase(it); sessions.erase(it);
} }
} }
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,6 +13,8 @@
namespace Service::PSC::Time { namespace Service::PSC::Time {
class ContextWriter; class ContextWriter;
#undef GetCurrentTime
class SystemClockCore { class SystemClockCore {
public: public:
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {} explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
@@ -19,6 +19,8 @@ class System;
namespace Service::PSC::Time { namespace Service::PSC::Time {
#undef GetCurrentTime
class SystemClock final : public ServiceFramework<SystemClock> { class SystemClock final : public ServiceFramework<SystemClock> {
public: public:
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock); explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock);
+1 -1
View File
@@ -393,7 +393,7 @@ Result ServerManager::CompleteSyncRequest(Session* session) {
} }
// Send the reply. // Send the reply.
res = server_session->SendReplyHLE(m_system.Kernel(), service_res == IPC::ResultSessionClosed); res = server_session->SendReplyHLE(m_system.Kernel());
// If the session has been closed, we're done. // If the session has been closed, we're done.
if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) { if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) {
+1 -15
View File
@@ -4,16 +4,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include <string_view>
#include <thread>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging.h" #include "common/logging.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/ipc.h" #include "core/hle/ipc.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
@@ -37,7 +33,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
: SessionRequestHandler(system_.Kernel(), service_name_) : SessionRequestHandler(system_.Kernel(), service_name_)
, system{system_} , system{system_}
, service_name{service_name_} , service_name{service_name_}
, is_i_storage{std::string_view{service_name_} == "IStorage"}
, handler_invoker{handler_invoker_} , handler_invoker{handler_invoker_}
, max_sessions{max_sessions_} , max_sessions{max_sessions_}
{} {}
@@ -82,22 +77,13 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
} }
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) { void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
const auto command = ctx.GetCommand(); auto it = handlers.find(ctx.GetCommand());
auto it = handlers.find(command);
const bool is_cmd_read = command == 0;
FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second; FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second;
if (info == nullptr || info->handler_callback == nullptr) if (info == nullptr || info->handler_callback == nullptr)
return ReportUnimplementedFunction(ctx, info); return ReportUnimplementedFunction(ctx, info);
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
handler_invoker(this, info->handler_callback, ctx); handler_invoker(this, info->handler_callback, ctx);
if (is_i_storage && is_cmd_read) {
const auto* const process = ctx.GetThread().GetOwnerProcess();
if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) {
std::this_thread::sleep_for(std::chrono::microseconds{600});
}
}
} }
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) { void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
-2
View File
@@ -107,8 +107,6 @@ protected:
Core::System& system; Core::System& system;
/// Identifier string used to connect to the service. /// Identifier string used to connect to the service.
const char* service_name; const char* service_name;
/// Whether this is the IStorage service.
const bool is_i_storage;
/// Function used to safely up-cast pointers to the derived class before invoking a handler. /// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker; InvokerFn* handler_invoker;
/// Maximum number of concurrent sessions that this service can handle. /// Maximum number of concurrent sessions that this service can handle.
+90 -90
View File
@@ -54,11 +54,11 @@ void PutValue(std::span<u8> buffer, const T& t) {
} // Anonymous namespace } // Anonymous namespace
void BSD::PollWork::Execute(BSD* bsd) { void NetworkBSD::PollWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout); std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
} }
void BSD::PollWork::Response(HLERequestContext& ctx) { void NetworkBSD::PollWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) { if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer); ctx.WriteBuffer(write_buffer);
} }
@@ -69,11 +69,11 @@ void BSD::PollWork::Response(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::AcceptWork::Execute(BSD* bsd) { void NetworkBSD::AcceptWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer); std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
} }
void BSD::AcceptWork::Response(HLERequestContext& ctx) { void NetworkBSD::AcceptWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) { if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer); ctx.WriteBuffer(write_buffer);
} }
@@ -85,22 +85,22 @@ void BSD::AcceptWork::Response(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size())); rb.Push<u32>(static_cast<u32>(write_buffer.size()));
} }
void BSD::ConnectWork::Execute(BSD* bsd) { void NetworkBSD::ConnectWork::Execute(NetworkBSD* bsd) {
bsd_errno = bsd->ConnectImpl(fd, addr); bsd_errno = bsd->ConnectImpl(fd, addr);
} }
void BSD::ConnectWork::Response(HLERequestContext& ctx) { void NetworkBSD::ConnectWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1); rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::RecvWork::Execute(BSD* bsd) { void NetworkBSD::RecvWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message); std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
} }
void BSD::RecvWork::Response(HLERequestContext& ctx) { void NetworkBSD::RecvWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message); ctx.WriteBuffer(message);
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
@@ -109,11 +109,11 @@ void BSD::RecvWork::Response(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::RecvFromWork::Execute(BSD* bsd) { void NetworkBSD::RecvFromWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr); std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
} }
void BSD::RecvFromWork::Response(HLERequestContext& ctx) { void NetworkBSD::RecvFromWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message, 0); ctx.WriteBuffer(message, 0);
if (!addr.empty()) { if (!addr.empty()) {
ctx.WriteBuffer(addr, 1); ctx.WriteBuffer(addr, 1);
@@ -126,29 +126,29 @@ void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(addr.size())); rb.Push<u32>(static_cast<u32>(addr.size()));
} }
void BSD::SendWork::Execute(BSD* bsd) { void NetworkBSD::SendWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message); std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
} }
void BSD::SendWork::Response(HLERequestContext& ctx) { void NetworkBSD::SendWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push<s32>(ret); rb.Push<s32>(ret);
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::SendToWork::Execute(BSD* bsd) { void NetworkBSD::SendToWork::Execute(NetworkBSD* bsd) {
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr); std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
} }
void BSD::SendToWork::Response(HLERequestContext& ctx) { void NetworkBSD::SendToWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push<s32>(ret); rb.Push<s32>(ret);
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::RegisterClient(HLERequestContext& ctx) { void NetworkBSD::RegisterClient(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called"); LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
@@ -157,7 +157,7 @@ void BSD::RegisterClient(HLERequestContext& ctx) {
rb.Push<s32>(0); // bsd errno rb.Push<s32>(0); // bsd errno
} }
void BSD::StartMonitoring(HLERequestContext& ctx) { void NetworkBSD::StartMonitoring(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called"); LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -165,7 +165,7 @@ void BSD::StartMonitoring(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void BSD::Socket(HLERequestContext& ctx) { void NetworkBSD::Socket(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const u32 domain = rp.Pop<u32>(); const u32 domain = rp.Pop<u32>();
const u32 type = rp.Pop<u32>(); const u32 type = rp.Pop<u32>();
@@ -200,7 +200,7 @@ void BSD::SocketExempt(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::Select(HLERequestContext& ctx) { void NetworkBSD::Select(HLERequestContext& ctx) {
LOG_DEBUG(Service, "(STUBBED) called"); LOG_DEBUG(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
@@ -210,7 +210,7 @@ void BSD::Select(HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno rb.Push<u32>(0); // bsd errno
} }
void BSD::Poll(HLERequestContext& ctx) { void NetworkBSD::Poll(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 nfds = rp.Pop<s32>(); const s32 nfds = rp.Pop<s32>();
const s32 timeout = rp.Pop<s32>(); const s32 timeout = rp.Pop<s32>();
@@ -225,7 +225,7 @@ void BSD::Poll(HLERequestContext& ctx) {
}); });
} }
void BSD::Accept(HLERequestContext& ctx) { void NetworkBSD::Accept(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -237,7 +237,7 @@ void BSD::Accept(HLERequestContext& ctx) {
}); });
} }
void BSD::Bind(HLERequestContext& ctx) { void NetworkBSD::Bind(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -245,7 +245,7 @@ void BSD::Bind(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer())); BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
} }
void BSD::Connect(HLERequestContext& ctx) { void NetworkBSD::Connect(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -257,7 +257,7 @@ void BSD::Connect(HLERequestContext& ctx) {
}); });
} }
void BSD::GetPeerName(HLERequestContext& ctx) { void NetworkBSD::GetPeerName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -275,7 +275,7 @@ void BSD::GetPeerName(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size())); rb.Push<u32>(static_cast<u32>(write_buffer.size()));
} }
void BSD::GetSockName(HLERequestContext& ctx) { void NetworkBSD::GetSockName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -293,7 +293,7 @@ void BSD::GetSockName(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size())); rb.Push<u32>(static_cast<u32>(write_buffer.size()));
} }
void BSD::GetSockOpt(HLERequestContext& ctx) { void NetworkBSD::GetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>(); const u32 level = rp.Pop<u32>();
@@ -315,7 +315,7 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(optval.size())); rb.Push<u32>(static_cast<u32>(optval.size()));
} }
void BSD::Listen(HLERequestContext& ctx) { void NetworkBSD::Listen(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const s32 backlog = rp.Pop<s32>(); const s32 backlog = rp.Pop<s32>();
@@ -325,7 +325,7 @@ void BSD::Listen(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ListenImpl(fd, backlog)); BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
} }
void BSD::Fcntl(HLERequestContext& ctx) { void NetworkBSD::Fcntl(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const s32 cmd = rp.Pop<s32>(); const s32 cmd = rp.Pop<s32>();
@@ -341,7 +341,7 @@ void BSD::Fcntl(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::SetSockOpt(HLERequestContext& ctx) { void NetworkBSD::SetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -355,7 +355,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
} }
void BSD::Shutdown(HLERequestContext& ctx) { void NetworkBSD::Shutdown(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -366,7 +366,7 @@ void BSD::Shutdown(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ShutdownImpl(fd, how)); BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
} }
void BSD::Recv(HLERequestContext& ctx) { void NetworkBSD::Recv(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -381,7 +381,7 @@ void BSD::Recv(HLERequestContext& ctx) {
}); });
} }
void BSD::RecvFrom(HLERequestContext& ctx) { void NetworkBSD::RecvFrom(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -398,7 +398,7 @@ void BSD::RecvFrom(HLERequestContext& ctx) {
}); });
} }
void BSD::Send(HLERequestContext& ctx) { void NetworkBSD::Send(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -413,7 +413,7 @@ void BSD::Send(HLERequestContext& ctx) {
}); });
} }
void BSD::SendTo(HLERequestContext& ctx) { void NetworkBSD::SendTo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const u32 flags = rp.Pop<u32>(); const u32 flags = rp.Pop<u32>();
@@ -429,7 +429,7 @@ void BSD::SendTo(HLERequestContext& ctx) {
}); });
} }
void BSD::Write(HLERequestContext& ctx) { void NetworkBSD::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -442,7 +442,7 @@ void BSD::Write(HLERequestContext& ctx) {
}); });
} }
void BSD::Read(HLERequestContext& ctx) { void NetworkBSD::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -454,7 +454,7 @@ void BSD::Read(HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno rb.Push<u32>(0); // bsd errno
} }
void BSD::Close(HLERequestContext& ctx) { void NetworkBSD::Close(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
@@ -464,7 +464,7 @@ void BSD::Close(HLERequestContext& ctx) {
} }
/// @brief Only bsd:s is able to dup() /// @brief Only bsd:s is able to dup()
void BSD::DuplicateSocket(HLERequestContext& ctx) { void NetworkBSD::DuplicateSocket(HLERequestContext& ctx) {
struct InputParameters { struct InputParameters {
s32 fd; s32 fd;
u64 reserved; u64 reserved;
@@ -505,7 +505,7 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
} }
} }
void BSD::EventFd(HLERequestContext& ctx) { void NetworkBSD::EventFd(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const u64 initval = rp.Pop<u64>(); const u64 initval = rp.Pop<u64>();
const u32 flags = rp.Pop<u32>(); const u32 flags = rp.Pop<u32>();
@@ -516,12 +516,12 @@ void BSD::EventFd(HLERequestContext& ctx) {
} }
template <typename Work> template <typename Work>
void BSD::ExecuteWork(HLERequestContext& ctx, Work work) { void NetworkBSD::ExecuteWork(HLERequestContext& ctx, Work work) {
work.Execute(this); work.Execute(this);
work.Response(ctx); work.Response(ctx);
} }
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) { std::pair<s32, Errno> NetworkBSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW // user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) { if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) { if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
@@ -565,7 +565,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
return {fd, Errno::SUCCESS}; return {fd, Errno::SUCCESS};
} }
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, std::pair<s32, Errno> NetworkBSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) { s32 nfds, s32 timeout) {
if (nfds <= 0) { if (nfds <= 0) {
// When no entries are provided, -1 is returned with errno zero // When no entries are provided, -1 is returned with errno zero
@@ -632,7 +632,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
return Translate(result); return Translate(result);
} }
std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { std::pair<s32, Errno> NetworkBSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
} }
@@ -660,7 +660,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
return {new_fd, Errno::SUCCESS}; return {new_fd, Errno::SUCCESS};
} }
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { Errno NetworkBSD::BindImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -675,7 +675,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
} }
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { Errno NetworkBSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -698,7 +698,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
return result; return result;
} }
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { Errno NetworkBSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -720,7 +720,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
return Translate(bsd_errno); return Translate(bsd_errno);
} }
Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) { Errno NetworkBSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -742,7 +742,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
return Translate(bsd_errno); return Translate(bsd_errno);
} }
Errno BSD::ListenImpl(s32 fd, s32 backlog) { Errno NetworkBSD::ListenImpl(s32 fd, s32 backlog) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -753,7 +753,7 @@ Errno BSD::ListenImpl(s32 fd, s32 backlog) {
return Translate(file_descriptors[fd]->socket->Listen(backlog)); return Translate(file_descriptors[fd]->socket->Listen(backlog));
} }
std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) { std::pair<s32, Errno> NetworkBSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
} }
@@ -783,7 +783,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
} }
} }
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) { Errno NetworkBSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -818,7 +818,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
} }
} }
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) { Errno NetworkBSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -872,7 +872,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8
} }
} }
Errno BSD::ShutdownImpl(s32 fd, s32 how) { Errno NetworkBSD::ShutdownImpl(s32 fd, s32 how) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -884,7 +884,7 @@ Errno BSD::ShutdownImpl(s32 fd, s32 how) {
return Translate(file_descriptors[fd]->socket->Shutdown(host_how)); return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
} }
std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) { std::pair<s32, Errno> NetworkBSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
} }
@@ -911,7 +911,7 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
return {ret, bsd_errno}; return {ret, bsd_errno};
} }
std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::pair<s32, Errno> NetworkBSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
std::vector<u8>& addr) { std::vector<u8>& addr) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
@@ -958,7 +958,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
return {ret, bsd_errno}; return {ret, bsd_errno};
} }
std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) { std::pair<s32, Errno> NetworkBSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
} }
@@ -969,7 +969,7 @@ std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> messa
return Translate(file_descriptors[fd]->socket->Send(message, flags)); return Translate(file_descriptors[fd]->socket->Send(message, flags));
} }
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, std::pair<s32, Errno> NetworkBSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
std::span<const u8> addr) { std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF}; return {-1, Errno::BADF};
@@ -991,7 +991,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in)); return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
} }
Errno BSD::CloseImpl(s32 fd) { Errno NetworkBSD::CloseImpl(s32 fd) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -1011,7 +1011,7 @@ Errno BSD::CloseImpl(s32 fd) {
return bsd_errno; return bsd_errno;
} }
std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) { std::variant<s32, Errno> NetworkBSD::DuplicateSocketImpl(s32 fd) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; return Errno::BADF;
} }
@@ -1030,7 +1030,7 @@ std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
return new_fd; return new_fd;
} }
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) { std::optional<std::shared_ptr<Network::SocketBase>> NetworkBSD::GetSocket(s32 fd) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return std::nullopt; return std::nullopt;
} }
@@ -1041,7 +1041,7 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
return file_descriptors[fd]->socket; return file_descriptors[fd]->socket;
} }
s32 BSD::FindFreeFileDescriptorHandle() noexcept { s32 NetworkBSD::FindFreeFileDescriptorHandle() noexcept {
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) { for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
if (!file_descriptors[fd]) { if (!file_descriptors[fd]) {
return fd; return fd;
@@ -1050,7 +1050,7 @@ s32 BSD::FindFreeFileDescriptorHandle() noexcept {
return -1; return -1;
} }
bool BSD::IsFileDescriptorValid(s32 fd) const noexcept { bool NetworkBSD::IsFileDescriptorValid(s32 fd) const noexcept {
if (fd > static_cast<s32>(MAX_FD) || fd < 0) { if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd); LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
return false; return false;
@@ -1062,7 +1062,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
return true; return true;
} }
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept { void NetworkBSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@@ -1070,7 +1070,7 @@ void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noex
rb.PushEnum(bsd_errno); rb.PushEnum(bsd_errno);
} }
void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) { void NetworkBSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
for (auto& optional_descriptor : file_descriptors) { for (auto& optional_descriptor : file_descriptors) {
if (!optional_descriptor.has_value()) { if (!optional_descriptor.has_value()) {
continue; continue;
@@ -1080,43 +1080,43 @@ void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
} }
} }
BSD::BSD(Core::System& system_, const char* name, bool is_user_) NetworkBSD::NetworkBSD(Core::System& system_, const char* name, bool is_user_)
: ServiceFramework{system_, name} : ServiceFramework{system_, name}
, is_user{is_user_} { , is_user{is_user_} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"}, {0, &NetworkBSD::RegisterClient, "RegisterClient"},
{1, &BSD::StartMonitoring, "StartMonitoring"}, {1, &NetworkBSD::StartMonitoring, "StartMonitoring"},
{2, &BSD::Socket, "Socket"}, {2, &NetworkBSD::Socket, "Socket"},
{3, &BSD::SocketExempt, "SocketExempt"}, {3, &NetworkBSD::SocketExempt, "SocketExempt"},
{4, nullptr, "Open"}, {4, nullptr, "Open"},
{5, &BSD::Select, "Select"}, {5, &NetworkBSD::Select, "Select"},
{6, &BSD::Poll, "Poll"}, {6, &NetworkBSD::Poll, "Poll"},
{7, nullptr, "Sysctl"}, {7, nullptr, "Sysctl"},
{8, &BSD::Recv, "Recv"}, {8, &NetworkBSD::Recv, "Recv"},
{9, &BSD::RecvFrom, "RecvFrom"}, {9, &NetworkBSD::RecvFrom, "RecvFrom"},
{10, &BSD::Send, "Send"}, {10, &NetworkBSD::Send, "Send"},
{11, &BSD::SendTo, "SendTo"}, {11, &NetworkBSD::SendTo, "SendTo"},
{12, &BSD::Accept, "Accept"}, {12, &NetworkBSD::Accept, "Accept"},
{13, &BSD::Bind, "Bind"}, {13, &NetworkBSD::Bind, "Bind"},
{14, &BSD::Connect, "Connect"}, {14, &NetworkBSD::Connect, "Connect"},
{15, &BSD::GetPeerName, "GetPeerName"}, {15, &NetworkBSD::GetPeerName, "GetPeerName"},
{16, &BSD::GetSockName, "GetSockName"}, {16, &NetworkBSD::GetSockName, "GetSockName"},
{17, &BSD::GetSockOpt, "GetSockOpt"}, {17, &NetworkBSD::GetSockOpt, "GetSockOpt"},
{18, &BSD::Listen, "Listen"}, {18, &NetworkBSD::Listen, "Listen"},
{19, nullptr, "Ioctl"}, {19, nullptr, "Ioctl"},
{20, &BSD::Fcntl, "Fcntl"}, {20, &NetworkBSD::Fcntl, "Fcntl"},
{21, &BSD::SetSockOpt, "SetSockOpt"}, {21, &NetworkBSD::SetSockOpt, "SetSockOpt"},
{22, &BSD::Shutdown, "Shutdown"}, {22, &NetworkBSD::Shutdown, "Shutdown"},
{23, nullptr, "ShutdownAllSockets"}, {23, nullptr, "ShutdownAllSockets"},
{24, &BSD::Write, "Write"}, {24, &NetworkBSD::Write, "Write"},
{25, &BSD::Read, "Read"}, {25, &NetworkBSD::Read, "Read"},
{26, &BSD::Close, "Close"}, {26, &NetworkBSD::Close, "Close"},
{27, &BSD::DuplicateSocket, "DuplicateSocket"}, {27, &NetworkBSD::DuplicateSocket, "DuplicateSocket"},
{28, nullptr, "GetResourceStatistics"}, {28, nullptr, "GetResourceStatistics"},
{29, nullptr, "RecvMMsg"}, //3.0.0+ {29, nullptr, "RecvMMsg"}, //3.0.0+
{30, nullptr, "SendMMsg"}, //3.0.0+ {30, nullptr, "SendMMsg"}, //3.0.0+
{31, &BSD::EventFd, "EventFd"}, //7.0.0+ {31, &NetworkBSD::EventFd, "EventFd"}, //7.0.0+
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+ {32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
{33, nullptr, "RegisterClientShared"}, //10.0.0+ {33, nullptr, "RegisterClientShared"}, //10.0.0+
{34, nullptr, "GetSocketStatistics"}, //15.0.0+ {34, nullptr, "GetSocketStatistics"}, //15.0.0+
@@ -1144,13 +1144,13 @@ BSD::BSD(Core::System& system_, const char* name, bool is_user_)
} }
} }
BSD::~BSD() { NetworkBSD::~NetworkBSD() {
if (auto room_member = Network::GetRoomMember().lock()) { if (auto room_member = Network::GetRoomMember().lock()) {
room_member->Unbind(proxy_packet_received); room_member->Unbind(proxy_packet_received);
} }
} }
std::unique_lock<std::mutex> BSD::LockService() noexcept { std::unique_lock<std::mutex> NetworkBSD::LockService() noexcept {
return {}; return {};
} }
+10 -10
View File
@@ -27,10 +27,10 @@ class Socket;
namespace Service::Sockets { namespace Service::Sockets {
class BSD final : public ServiceFramework<BSD> { class NetworkBSD final : public ServiceFramework<NetworkBSD> {
public: public:
explicit BSD(Core::System& system_, const char* name, bool is_user); explicit NetworkBSD(Core::System& system_, const char* name, bool is_user);
~BSD() override; ~NetworkBSD() override;
// These methods are called from SSL; the first two are also called from // These methods are called from SSL; the first two are also called from
// this class for the corresponding IPC methods. // this class for the corresponding IPC methods.
@@ -50,7 +50,7 @@ private:
}; };
struct PollWork { struct PollWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 nfds; s32 nfds;
@@ -62,7 +62,7 @@ private:
}; };
struct AcceptWork { struct AcceptWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
@@ -72,7 +72,7 @@ private:
}; };
struct ConnectWork { struct ConnectWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
@@ -81,7 +81,7 @@ private:
}; };
struct RecvWork { struct RecvWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
@@ -92,7 +92,7 @@ private:
}; };
struct RecvFromWork { struct RecvFromWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
@@ -104,7 +104,7 @@ private:
}; };
struct SendWork { struct SendWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
@@ -115,7 +115,7 @@ private:
}; };
struct SendToWork { struct SendToWork {
void Execute(BSD* bsd); void Execute(NetworkBSD* bsd);
void Response(HLERequestContext& ctx); void Response(HLERequestContext& ctx);
s32 fd; s32 fd;
+3 -3
View File
@@ -66,9 +66,9 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("ethc:c", std::make_shared<ETHC_C>(system)); server_manager->RegisterNamedService("ethc:c", std::make_shared<ETHC_C>(system));
server_manager->RegisterNamedService("ethc:i", std::make_shared<ETHC_I>(system)); server_manager->RegisterNamedService("ethc:i", std::make_shared<ETHC_I>(system));
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s", false)); server_manager->RegisterNamedService("bsd:s", std::make_shared<NetworkBSD>(system, "bsd:s", false));
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u", true)); server_manager->RegisterNamedService("bsd:u", std::make_shared<NetworkBSD>(system, "bsd:u", true));
server_manager->RegisterNamedService("bsd:a", std::make_shared<BSD>(system, "bsd:a", true)); server_manager->RegisterNamedService("bsd:a", std::make_shared<NetworkBSD>(system, "bsd:a", true));
server_manager->RegisterNamedService("bsd:nu", std::make_shared<BSD_NU>(system)); server_manager->RegisterNamedService("bsd:nu", std::make_shared<BSD_NU>(system));
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system, "bsdcfg")); server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system, "bsdcfg"));
server_manager->RegisterNamedService("ifcfg", std::make_shared<BSDCFG>(system, "ifcfg")); server_manager->RegisterNamedService("ifcfg", std::make_shared<BSDCFG>(system, "ifcfg"));
+2 -2
View File
@@ -129,7 +129,7 @@ public:
LOG_ERROR(Service_SSL, LOG_ERROR(Service_SSL,
"do_not_close_socket was changed after setting socket; is this right?"); "do_not_close_socket was changed after setting socket; is this right?");
} else { } else {
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u"); auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
if (bsd) { if (bsd) {
auto err = bsd->CloseImpl(fd); auto err = bsd->CloseImpl(fd);
if (err != Service::Sockets::Errno::SUCCESS) { if (err != Service::Sockets::Errno::SUCCESS) {
@@ -157,7 +157,7 @@ private:
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) { Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd); LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake); ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u"); auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; }); ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
auto const res_v = bsd->DuplicateSocketImpl(fd); auto const res_v = bsd->DuplicateSocketImpl(fd);
+4 -6
View File
@@ -17,11 +17,9 @@
namespace Loader { namespace Loader {
namespace { [[nodiscard]] inline constexpr u32 PageAlignSizeKIP(u32 size) {
constexpr u32 PageAlignSize(u32 size) { return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
} }
} // Anonymous namespace
AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_) AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
: AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {} : AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
@@ -76,11 +74,11 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
kip->GetKernelCapabilities()); kip->GetKernelCapabilities());
Kernel::CodeSet codeset; Kernel::CodeSet codeset;
codeset.memory.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); codeset.memory.resize(PageAlignSizeKIP(kip->GetBSSOffset()) + kip->GetBSSSize());
const auto load_segment = [&codeset](Kernel::CodeSet::Segment& segment, std::span<const u8> data, u32 offset) { const auto load_segment = [&codeset](Kernel::CodeSet::Segment& segment, std::span<const u8> data, u32 offset) {
segment.addr = offset; segment.addr = offset;
segment.offset = offset; segment.offset = offset;
segment.size = PageAlignSize(u32(data.size())); segment.size = PageAlignSizeKIP(u32(data.size()));
std::memcpy(codeset.memory.data() + offset, data.data(), data.size()); std::memcpy(codeset.memory.data() + offset, data.data(), data.size());
}; };
load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset()); load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
+7 -7
View File
@@ -148,8 +148,8 @@ bool AppLoader_NRO::IsHomebrew() {
nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W'); nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
} }
static constexpr u32 PageAlignSize(u32 size) { [[nodiscard]] inline constexpr u32 PageAlignSizeNRO(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
} }
static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process, static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
@@ -166,9 +166,9 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
} }
// Build program image // Build program image
std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); std::vector<u8> program_image(PageAlignSizeNRO(nro_header.file_size));
std::memcpy(program_image.data(), data.data(), program_image.size()); std::memcpy(program_image.data(), data.data(), program_image.size());
if (program_image.size() != PageAlignSize(nro_header.file_size)) { if (program_image.size() != PageAlignSizeNRO(nro_header.file_size)) {
return {}; return {};
} }
@@ -176,11 +176,11 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
for (std::size_t i = 0; i < nro_header.segments.size(); ++i) { for (std::size_t i = 0; i < nro_header.segments.size(); ++i) {
codeset.segments[i].addr = nro_header.segments[i].offset; codeset.segments[i].addr = nro_header.segments[i].offset;
codeset.segments[i].offset = nro_header.segments[i].offset; codeset.segments[i].offset = nro_header.segments[i].offset;
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size); codeset.segments[i].size = PageAlignSizeNRO(nro_header.segments[i].size);
} }
// Default .bss to NRO header bss size if MOD0 section doesn't exist // Default .bss to NRO header bss size if MOD0 section doesn't exist
u32 bss_size{PageAlignSize(nro_header.bss_size)}; u32 bss_size{PageAlignSizeNRO(nro_header.bss_size)};
// Read MOD header // Read MOD header
ModHeader mod_header{}; ModHeader mod_header{};
@@ -190,7 +190,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
if (has_mod_header) { if (has_mod_header) {
// Resize program image to include .bss section and page align each section // Resize program image to include .bss section and page align each section
bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); bss_size = PageAlignSizeNRO(mod_header.bss_end_offset - mod_header.bss_start_offset);
} }
codeset.DataSegment().size += bss_size; codeset.DataSegment().size += bss_size;
+4 -4
View File
@@ -41,8 +41,8 @@ struct MODHeader {
}; };
static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size."); static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
constexpr u32 PageAlignSize(u32 size) { [[nodiscard]] inline constexpr u32 PageAlignSizeNSO(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
} }
} // Anonymous namespace } // Anonymous namespace
@@ -128,11 +128,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
} }
codeset.DataSegment().size += nso_header.segments[2].bss_size; codeset.DataSegment().size += nso_header.segments[2].bss_size;
u32 image_size = PageAlignSize(u32(codeset.memory.size()) + nso_header.segments[2].bss_size); u32 image_size = PageAlignSizeNSO(u32(codeset.memory.size()) + nso_header.segments[2].bss_size);
codeset.memory.resize(image_size); codeset.memory.resize(image_size);
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
codeset.segments[i].size = PageAlignSize(codeset.segments[i].size); codeset.segments[i].size = PageAlignSizeNSO(codeset.segments[i].size);
} }
// Apply patches if necessary // Apply patches if necessary
+2
View File
@@ -21,6 +21,8 @@
#include "hid_core/resource_manager.h" #include "hid_core/resource_manager.h"
#include "hid_core/resources/npad/npad.h" #include "hid_core/resources/npad/npad.h"
#undef CreateEvent
namespace Core::Memory { namespace Core::Memory {
namespace { namespace {
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
+2
View File
@@ -28,6 +28,8 @@
#include "core/memory.h" #include "core/memory.h"
#include "core/reporter.h" #include "core/reporter.h"
#undef far
namespace { namespace {
std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) { std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
+2
View File
@@ -52,6 +52,8 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
} // Anonymous namespace } // Anonymous namespace
#undef CreateEvent
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
: core_timing{core_timing_}, memory{memory_} { : core_timing{core_timing_}, memory{memory_} {
event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback", event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
@@ -31,7 +31,7 @@ using namespace oaknut::util;
namespace { namespace {
bool IsOrdered(IR::AccType acctype) { [[nodiscard]] inline bool IsOrdered(IR::AccType acctype) {
return acctype == IR::AccType::ORDERED || acctype == IR::AccType::ORDEREDRW || acctype == IR::AccType::LIMITEDORDERED; return acctype == IR::AccType::ORDERED || acctype == IR::AccType::ORDEREDRW || acctype == IR::AccType::LIMITEDORDERED;
} }
@@ -247,7 +247,7 @@ void A32EmitX64::GenTerminalHandlers() {
calculate_location_descriptor(); calculate_location_descriptor();
code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)]); code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)]);
code.sub(eax, 1); code.sub(eax, 1);
code.and_(eax, u32(A32JitState::RSB_PTR_MASK)); code.and_(eax, u32(A32JitState::RSBPtrMask));
code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)], eax); 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)]); code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]);
if (conf.HasOptimization(OptimizationFlag::FastDispatch)) { if (conf.HasOptimization(OptimizationFlag::FastDispatch)) {
@@ -37,9 +37,9 @@ using namespace Backend::X64;
static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg, const A32::UserConfig& conf) { static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg, const A32::UserConfig& conf) {
return RunCodeCallbacks{ return RunCodeCallbacks{
ArgCallback(LookupBlock, reinterpret_cast<u64>(arg)), std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
ArgCallback(Devirtualize<&A32::UserCallbacks::AddTicks>(cb)), std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::AddTicks>(cb)),
ArgCallback(Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(cb)), std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(cb)),
conf.enable_cycle_counting, conf.enable_cycle_counting,
}; };
} }
@@ -79,7 +79,7 @@ struct Jit::Impl {
jit_interface->is_executing = true; jit_interface->is_executing = true;
const CodePtr current_codeptr = [this] { const CodePtr current_codeptr = [this] {
// RSB optimization // RSB optimization
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSB_PTR_MASK; const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) { if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
jit_state.rsb_ptr = new_rsb_ptr; jit_state.rsb_ptr = new_rsb_ptr;
return reinterpret_cast<CodePtr>(jit_state.rsb_codeptrs[new_rsb_ptr]); return reinterpret_cast<CodePtr>(jit_state.rsb_codeptrs[new_rsb_ptr]);
@@ -27,9 +27,6 @@ struct A32JitState {
A32JitState() { ResetRSB(); } A32JitState() { ResetRSB(); }
static constexpr std::size_t RSB_SIZE = 8; // MUST be a power of 2.
static constexpr std::size_t RSB_PTR_MASK = RSB_SIZE - 1;
std::array<u32, 16> Reg{}; // Current register file. std::array<u32, 16> Reg{}; // Current register file.
// TODO: Mode-specific register sets unimplemented. // TODO: Mode-specific register sets unimplemented.
@@ -39,9 +36,8 @@ struct A32JitState {
u32 cpsr_q = 0; u32 cpsr_q = 0;
u32 cpsr_nzcv = 0; u32 cpsr_nzcv = 0;
u32 cpsr_jaifm = 0; u32 cpsr_jaifm = 0;
u32 fpsr_exc = 0; u32 Cpsr() const;
u32 fpsr_qc = 0; void SetCpsr(u32 cpsr);
u32 fpsr_nzcv = 0;
alignas(16) std::array<u32, 64> ExtReg{}; // Extension registers. alignas(16) std::array<u32, 64> ExtReg{}; // Extension registers.
@@ -53,19 +49,21 @@ struct A32JitState {
// Exclusive state // Exclusive state
u32 exclusive_state = 0; u32 exclusive_state = 0;
static constexpr std::size_t RSBSize = 8; // MUST be a power of 2.
static constexpr std::size_t RSBPtrMask = RSBSize - 1;
u32 rsb_ptr = 0; u32 rsb_ptr = 0;
std::array<u64, RSB_SIZE> rsb_location_descriptors; std::array<u64, RSBSize> rsb_location_descriptors;
std::array<u64, RSB_SIZE> rsb_codeptrs; std::array<u64, RSBSize> rsb_codeptrs;
u32 Cpsr() const;
void SetCpsr(u32 cpsr);
void ResetRSB(); void ResetRSB();
u32 fpsr_exc = 0;
u32 fpsr_qc = 0;
u32 fpsr_nzcv = 0;
u32 Fpscr() const; u32 Fpscr() const;
void SetFpscr(u32 FPSCR); void SetFpscr(u32 FPSCR);
u64 GetUniqueHash() const noexcept { u64 GetUniqueHash() const noexcept {
return (u64(upper_location_descriptor) << 32) | (u64(Reg[15])); return (static_cast<u64>(upper_location_descriptor) << 32) | (static_cast<u64>(Reg[15]));
} }
void TransferJitState(const A32JitState& src, bool reset_rsb) { void TransferJitState(const A32JitState& src, bool reset_rsb) {
@@ -208,7 +208,7 @@ void A64EmitX64::GenTerminalHandlers() {
calculate_location_descriptor(); calculate_location_descriptor();
code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)]); code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)]);
code.sub(eax, 1); code.sub(eax, 1);
code.and_(eax, u32(A64JitState::RSB_PTR_MASK)); code.and_(eax, u32(A64JitState::RSBPtrMask));
code.mov(dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)], eax); code.mov(dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]); code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]);
if (conf.HasOptimization(OptimizationFlag::FastDispatch)) { if (conf.HasOptimization(OptimizationFlag::FastDispatch)) {
@@ -33,9 +33,9 @@ using namespace Backend::X64;
static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg, const A64::UserConfig& conf) { static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg, const A64::UserConfig& conf) {
return RunCodeCallbacks{ return RunCodeCallbacks{
ArgCallback(LookupBlock, reinterpret_cast<u64>(arg)), std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
ArgCallback(Devirtualize<&A64::UserCallbacks::AddTicks>(cb)), std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::AddTicks>(cb)),
ArgCallback(Devirtualize<&A64::UserCallbacks::GetTicksRemaining>(cb)), std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::GetTicksRemaining>(cb)),
conf.enable_cycle_counting, conf.enable_cycle_counting,
}; };
} }
@@ -78,7 +78,7 @@ public:
// TODO: Check code alignment // TODO: Check code alignment
const CodePtr current_code_ptr = [this] { const CodePtr current_code_ptr = [this] {
// RSB optimization // RSB optimization
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSB_PTR_MASK; const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSBPtrMask;
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) { if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
jit_state.rsb_ptr = new_rsb_ptr; jit_state.rsb_ptr = new_rsb_ptr;
return CodePtr(jit_state.rsb_codeptrs[new_rsb_ptr]); return CodePtr(jit_state.rsb_codeptrs[new_rsb_ptr]);
@@ -29,19 +29,18 @@ struct A64JitState {
A64JitState() { ResetRSB(); } A64JitState() { ResetRSB(); }
// Exclusive state stuff
static constexpr u64 RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFF0ull;
// Return stack buffer
static constexpr size_t RSB_SIZE = 8; // MUST be a power of 2.
static constexpr size_t RSB_PTR_MASK = RSB_SIZE - 1;
std::array<u64, 31> reg{}; std::array<u64, 31> reg{};
u64 sp = 0; u64 sp = 0;
u64 pc = 0; u64 pc = 0;
u32 cpsr_nzcv = 0; u32 cpsr_nzcv = 0;
u32 fpsr_exc = 0;
u32 fpsr_qc = 0; u32 GetPstate() const {
u32 fpcr = 0; return NZCV::FromX64(cpsr_nzcv);
}
void SetPstate(u32 new_pstate) {
cpsr_nzcv = NZCV::ToX64(new_pstate);
}
alignas(16) std::array<u64, 64> vec{}; // Extension registers. alignas(16) std::array<u64, 64> vec{}; // Extension registers.
@@ -51,31 +50,29 @@ struct A64JitState {
volatile u32 halt_reason = 0; volatile u32 halt_reason = 0;
// Exclusive state // Exclusive state
static constexpr u64 RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFF0ull;
u8 exclusive_state = 0; u8 exclusive_state = 0;
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
static constexpr size_t RSBPtrMask = RSBSize - 1;
u32 rsb_ptr = 0; u32 rsb_ptr = 0;
std::array<u64, RSB_SIZE> rsb_location_descriptors; std::array<u64, RSBSize> rsb_location_descriptors;
std::array<u64, RSB_SIZE> rsb_codeptrs; std::array<u64, RSBSize> rsb_codeptrs;
u32 GetPstate() const {
return NZCV::FromX64(cpsr_nzcv);
}
void SetPstate(u32 new_pstate) {
cpsr_nzcv = NZCV::ToX64(new_pstate);
}
void ResetRSB() { void ResetRSB() {
rsb_location_descriptors.fill(0xFFFFFFFFFFFFFFFFull); rsb_location_descriptors.fill(0xFFFFFFFFFFFFFFFFull);
rsb_codeptrs.fill(0); rsb_codeptrs.fill(0);
} }
u32 fpsr_exc = 0;
u32 fpsr_qc = 0;
u32 fpcr = 0;
u32 GetFpcr() const; u32 GetFpcr() const;
u32 GetFpsr() const; u32 GetFpsr() const;
void SetFpcr(u32 value); void SetFpcr(u32 value);
void SetFpsr(u32 value); void SetFpsr(u32 value);
u64 GetUniqueHash() const noexcept { u64 GetUniqueHash() const noexcept {
const u64 fpcr_u64 = u64(fpcr & A64::LocationDescriptor::fpcr_mask) << A64::LocationDescriptor::fpcr_shift; const u64 fpcr_u64 = static_cast<u64>(fpcr & A64::LocationDescriptor::fpcr_mask) << A64::LocationDescriptor::fpcr_shift;
const u64 pc_u64 = pc & A64::LocationDescriptor::pc_mask; const u64 pc_u64 = pc & A64::LocationDescriptor::pc_mask;
return pc_u64 | fpcr_u64; return pc_u64 | fpcr_u64;
} }
@@ -61,6 +61,73 @@ namespace {
constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024;
constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024; constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024;
class CustomXbyakAllocator : public Xbyak::Allocator {
public:
#ifdef _WIN32
uint8_t* alloc(size_t size) override {
void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (p == nullptr) {
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
return static_cast<uint8_t*>(p);
}
void free(uint8_t* p) override {
VirtualFree(static_cast<void*>(p), 0, MEM_RELEASE);
}
bool useProtect() const override { return false; }
#else
static constexpr size_t DYNARMIC_PAGE_SIZE = 4096;
// Can't subclass Xbyak::MmapAllocator because it is not a pure interface
// and doesn't expose its construtor
uint8_t* alloc(size_t size) override {
// Waste a page to store the size
size += DYNARMIC_PAGE_SIZE;
int mode = MAP_PRIVATE;
#if defined(MAP_ANONYMOUS)
mode |= MAP_ANONYMOUS;
#elif defined(MAP_ANON)
mode |= MAP_ANON;
#else
# error "not supported"
#endif
#ifdef MAP_JIT
mode |= MAP_JIT;
#endif
int prot = PROT_READ | PROT_WRITE;
#ifdef PROT_MPROTECT
// https://man.netbsd.org/mprotect.2 specifies that an mprotect() that is LESS
// restrictive than the original mapping MUST fail
prot |= PROT_MPROTECT(PROT_READ) | PROT_MPROTECT(PROT_WRITE) | PROT_MPROTECT(PROT_EXEC);
#endif
void* p = mmap(nullptr, size, prot, mode, -1, 0);
if (p == MAP_FAILED) {
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
std::memcpy(p, &size, sizeof(size_t));
return static_cast<uint8_t*>(p) + DYNARMIC_PAGE_SIZE;
}
void free(uint8_t* p) override {
size_t size;
std::memcpy(&size, p - DYNARMIC_PAGE_SIZE, sizeof(size_t));
munmap(p - DYNARMIC_PAGE_SIZE, size);
}
# ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
bool useProtect() const override { return false; }
# endif
#endif
};
// This is threadsafe as Xbyak::Allocator does not contain any state; it is a pure interface.
CustomXbyakAllocator s_allocator;
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
void ProtectMemory(const void* base, size_t size, bool is_executable) { void ProtectMemory(const void* base, size_t size, bool is_executable) {
# ifdef _WIN32 # ifdef _WIN32
@@ -78,9 +145,11 @@ void ProtectMemory(const void* base, size_t size, bool is_executable) {
HostFeature GetHostFeatures() { HostFeature GetHostFeatures() {
HostFeature features = {}; HostFeature features = {};
#ifdef DYNARMIC_ENABLE_CPU_FEATURE_DETECTION #ifdef DYNARMIC_ENABLE_CPU_FEATURE_DETECTION
using Cpu = Xbyak::util::Cpu; using Cpu = Xbyak::util::Cpu;
Xbyak::util::Cpu cpu_info{}; Xbyak::util::Cpu cpu_info;
if (cpu_info.has(Cpu::tSSSE3)) if (cpu_info.has(Cpu::tSSSE3))
features |= HostFeature::SSSE3; features |= HostFeature::SSSE3;
if (cpu_info.has(Cpu::tSSE41)) if (cpu_info.has(Cpu::tSSE41))
@@ -127,6 +196,7 @@ HostFeature GetHostFeatures() {
features |= HostFeature::GFNI; features |= HostFeature::GFNI;
if (cpu_info.has(Cpu::tWAITPKG)) if (cpu_info.has(Cpu::tWAITPKG))
features |= HostFeature::WAITPKG; features |= HostFeature::WAITPKG;
if (cpu_info.has(Cpu::tBMI2)) { if (cpu_info.has(Cpu::tBMI2)) {
// BMI2 instructions such as pdep and pext have been very slow up until Zen 3. // BMI2 instructions such as pdep and pext have been very slow up until Zen 3.
// Check for Zen 3 or newer by its family (0x19). // Check for Zen 3 or newer by its family (0x19).
@@ -144,6 +214,7 @@ HostFeature GetHostFeatures() {
} }
} }
#endif #endif
return features; return features;
} }
@@ -162,27 +233,23 @@ bool IsUnderRosetta() {
} // anonymous namespace } // anonymous namespace
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function<void(BlockOfCode&)> rcp)
: Xbyak::CodeGenerator(total_code_size
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
, Xbyak::DontSetProtectRWE static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
#else #else
, nullptr //Allow RWE static const auto default_cg_mode = nullptr; //Allow RWE
#endif #endif
, nullptr)
, constant_pool(*this, CONSTANT_POOL_SIZE) BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function<void(BlockOfCode&)> rcp)
, jsi(jsi) : Xbyak::CodeGenerator(total_code_size, default_cg_mode, &s_allocator)
, cb(std::move(cb)) , cb(std::move(cb))
{ , jsi(jsi)
, constant_pool(*this, CONSTANT_POOL_SIZE)
, host_features(GetHostFeatures()) {
EnableWriting(); EnableWriting();
EnsureMemoryCommitted(PRELUDE_COMMIT_SIZE); EnsureMemoryCommitted(PRELUDE_COMMIT_SIZE);
GenRunCode(rcp); GenRunCode(rcp);
} }
bool BlockOfCode::HasHostFeature(HostFeature feature) const noexcept {
return (GetHostFeatures() & feature) == feature;
}
void BlockOfCode::PreludeComplete() { void BlockOfCode::PreludeComplete() {
prelude_complete = true; prelude_complete = true;
code_begin = getCurr(); code_begin = getCurr();
@@ -274,7 +341,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register
if (cb.enable_cycle_counting) { if (cb.enable_cycle_counting) {
cb.GetTicksRemaining.EmitCall(*this); cb.GetTicksRemaining->EmitCall(*this);
mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], ABI_RETURN); mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], ABI_RETURN);
mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], ABI_RETURN); mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], ABI_RETURN);
} }
@@ -321,7 +388,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0);
jng(return_to_caller); jng(return_to_caller);
} }
cb.LookupBlock.EmitCall(*this); cb.LookupBlock->EmitCall(*this);
jmp(ABI_RETURN); jmp(ABI_RETURN);
align(); align();
@@ -334,7 +401,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
jng(return_to_caller_mxcsr_already_exited); jng(return_to_caller_mxcsr_already_exited);
} }
SwitchMxcsrOnEntry(); SwitchMxcsrOnEntry();
cb.LookupBlock.EmitCall(*this); cb.LookupBlock->EmitCall(*this);
jmp(ABI_RETURN); jmp(ABI_RETURN);
align(); align();
@@ -348,7 +415,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
L(return_to_caller_mxcsr_already_exited); L(return_to_caller_mxcsr_already_exited);
if (cb.enable_cycle_counting) { if (cb.enable_cycle_counting) {
cb.AddTicks.EmitCall(*this, [this](RegList param) { cb.AddTicks->EmitCall(*this, [this](RegList param) {
mov(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)]); mov(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)]);
sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]); sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
}); });
@@ -388,18 +455,18 @@ void BlockOfCode::UpdateTicks() {
return; return;
} }
cb.AddTicks.EmitCall(*this, [this](RegList param) { cb.AddTicks->EmitCall(*this, [this](RegList param) {
mov(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)]); mov(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)]);
sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]); sub(param[0], qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)]);
}); });
cb.GetTicksRemaining.EmitCall(*this); cb.GetTicksRemaining->EmitCall(*this);
mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], ABI_RETURN); mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], ABI_RETURN);
mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], ABI_RETURN); mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], ABI_RETURN);
} }
void BlockOfCode::LookupBlock() { void BlockOfCode::LookupBlock() {
cb.LookupBlock.EmitCall(*this); cb.LookupBlock->EmitCall(*this);
} }
void BlockOfCode::LoadRequiredFlagsForCondFromRax(IR::Cond cond) { void BlockOfCode::LoadRequiredFlagsForCondFromRax(IR::Cond cond) {
@@ -453,7 +520,7 @@ void BlockOfCode::LoadRequiredFlagsForCondFromRax(IR::Cond cond) {
} }
Xbyak::Address BlockOfCode::Const(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) { Xbyak::Address BlockOfCode::Const(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) {
return constant_pool.GetConstant(*this, frame, lower, upper); return constant_pool.GetConstant(frame, lower, upper);
} }
CodePtr BlockOfCode::GetCodeBegin() const { CodePtr BlockOfCode::GetCodeBegin() const {
@@ -31,9 +31,9 @@ namespace Dynarmic::Backend::X64 {
using CodePtr = const void*; using CodePtr = const void*;
struct RunCodeCallbacks { struct RunCodeCallbacks {
ArgCallback LookupBlock; std::unique_ptr<Callback> LookupBlock;
ArgCallback AddTicks; std::unique_ptr<Callback> AddTicks;
ArgCallback GetTicksRemaining; std::unique_ptr<Callback> GetTicksRemaining;
bool enable_cycle_counting; bool enable_cycle_counting;
}; };
@@ -166,24 +166,27 @@ public:
JitStateInfo GetJitStateInfo() const { return jsi; } JitStateInfo GetJitStateInfo() const { return jsi; }
bool HasHostFeature(HostFeature feature) const noexcept; bool HasHostFeature(HostFeature feature) const {
return (host_features & feature) == feature;
}
private: private:
using RunCodeFuncType = HaltReason (*)(void*, CodePtr); using RunCodeFuncType = HaltReason (*)(void*, CodePtr);
static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0; static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0;
static constexpr size_t FORCE_RETURN = 1 << 1; static constexpr size_t FORCE_RETURN = 1 << 1;
ConstantPool constant_pool;
JitStateInfo jsi;
std::array<const void*, 4> return_from_run_code;
RunCodeFuncType run_code = nullptr;
RunCodeFuncType step_code = nullptr;
RunCodeCallbacks cb; RunCodeCallbacks cb;
JitStateInfo jsi;
CodePtr code_begin = nullptr; CodePtr code_begin = nullptr;
#ifdef _WIN32 #ifdef _WIN32
size_t committed_size = 0; size_t committed_size = 0;
#endif #endif
ConstantPool constant_pool;
RunCodeFuncType run_code = nullptr;
RunCodeFuncType step_code = nullptr;
std::array<const void*, 4> return_from_run_code;
bool prelude_complete = false; bool prelude_complete = false;
const HostFeature host_features;
void GenRunCode(std::function<void(BlockOfCode&)> rcp); void GenRunCode(std::function<void(BlockOfCode&)> rcp);
}; };
@@ -16,7 +16,8 @@
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {
ConstantPool::ConstantPool(BlockOfCode& code, size_t size) ConstantPool::ConstantPool(BlockOfCode& code, size_t size)
: insertion_point(0) : code(code)
, insertion_point(0)
{ {
code.EnsureMemoryCommitted(align_size + size); code.EnsureMemoryCommitted(align_size + size);
code.int3(); code.int3();
@@ -24,17 +25,17 @@ ConstantPool::ConstantPool(BlockOfCode& code, size_t size)
pool = std::span<ConstantT>(reinterpret_cast<ConstantT*>(code.AllocateFromCodeSpace(size)), size / align_size); pool = std::span<ConstantT>(reinterpret_cast<ConstantT*>(code.AllocateFromCodeSpace(size)), size / align_size);
} }
Xbyak::Address ConstantPool::GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper) { Xbyak::Address ConstantPool::GetConstant(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) {
const auto constant = ConstantT(lower, upper); const auto constant = ConstantT(lower, upper);
auto it = constant_info.find(constant); auto iter = constant_info.find(constant);
if (it == constant_info.end()) { if (iter == constant_info.end()) {
ASSERT(insertion_point < pool.size()); ASSERT(insertion_point < pool.size());
ConstantT& target_constant = pool[insertion_point]; ConstantT& target_constant = pool[insertion_point];
target_constant = constant; target_constant = constant;
it = constant_info.insert({constant, &target_constant}).first; iter = constant_info.insert({constant, &target_constant}).first;
++insertion_point; ++insertion_point;
} }
return frame[code.rip + it->second]; return frame[code.rip + iter->second];
} }
} // namespace Dynarmic::Backend::X64 } // namespace Dynarmic::Backend::X64
@@ -29,7 +29,7 @@ class ConstantPool final {
public: public:
ConstantPool(BlockOfCode& code, size_t size); ConstantPool(BlockOfCode& code, size_t size);
Xbyak::Address GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0); Xbyak::Address GetConstant(const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0);
private: private:
static constexpr size_t align_size = 16; // bytes static constexpr size_t align_size = 16; // bytes
@@ -45,6 +45,7 @@ private:
ankerl::unordered_dense::map<ConstantT, void*, ConstantHash> constant_info; ankerl::unordered_dense::map<ConstantT, void*, ConstantHash> constant_info;
std::span<ConstantT> pool; std::span<ConstantT> pool;
BlockOfCode& code;
std::size_t insertion_point; std::size_t insertion_point;
}; };
@@ -12,7 +12,7 @@
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {
enum class HostFeature : u32 { enum class HostFeature : u64 {
SSSE3 = 1ULL << 0, SSSE3 = 1ULL << 0,
SSE41 = 1ULL << 1, SSE41 = 1ULL << 1,
SSE42 = 1ULL << 2, SSE42 = 1ULL << 2,
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage * Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
@@ -18,7 +15,7 @@ struct JitStateInfo {
: offsetof_guest_MXCSR(offsetof(JitStateType, guest_MXCSR)) : offsetof_guest_MXCSR(offsetof(JitStateType, guest_MXCSR))
, offsetof_asimd_MXCSR(offsetof(JitStateType, asimd_MXCSR)) , offsetof_asimd_MXCSR(offsetof(JitStateType, asimd_MXCSR))
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr)) , offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
, rsb_ptr_mask(JitStateType::RSB_PTR_MASK) , rsb_ptr_mask(JitStateType::RSBPtrMask)
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors)) , offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors))
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs)) , offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv)) , offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
+4 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -6,7 +9,6 @@
#include "hid_core/hidbus/starlink.h" #include "hid_core/hidbus/starlink.h"
namespace Service::HID { namespace Service::HID {
constexpr u8 DEVICE_ID = 0x28;
Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_) Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
: HidbusBase(system_, service_context_) {} : HidbusBase(system_, service_context_) {}
@@ -35,7 +37,7 @@ void Starlink::OnUpdate() {
} }
u8 Starlink::GetDeviceId() const { u8 Starlink::GetDeviceId() const {
return DEVICE_ID; return 0x28;
} }
u64 Starlink::GetReply(std::span<u8> out_data) const { u64 Starlink::GetReply(std::span<u8> out_data) const {
+4 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -6,7 +9,6 @@
#include "hid_core/hidbus/stubbed.h" #include "hid_core/hidbus/stubbed.h"
namespace Service::HID { namespace Service::HID {
constexpr u8 DEVICE_ID = 0xFF;
HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_) HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
: HidbusBase(system_, service_context_) {} : HidbusBase(system_, service_context_) {}
@@ -35,7 +37,7 @@ void HidbusStubbed::OnUpdate() {
} }
u8 HidbusStubbed::GetDeviceId() const { u8 HidbusStubbed::GetDeviceId() const {
return DEVICE_ID; return 0xFF;
} }
u64 HidbusStubbed::GetReply(std::span<u8> out_data) const { u64 HidbusStubbed::GetReply(std::span<u8> out_data) const {
+12 -9
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@@ -8,9 +11,6 @@
#include "hid_core/irsensor/moment_processor.h" #include "hid_core/irsensor/moment_processor.h"
namespace Service::IRS { namespace Service::IRS {
static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size40x30;
static constexpr std::size_t ImageWidth = 40;
static constexpr std::size_t ImageHeight = 30;
MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format, MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
std::size_t npad_index) std::size_t npad_index)
@@ -80,9 +80,9 @@ void MomentProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type)
} }
u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const { u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
if ((y * ImageWidth) + x >= data.size()) { constexpr std::size_t ImageWidth = 40;
if ((y * ImageWidth) + x >= data.size())
return 0; return 0;
}
return data[(y * ImageWidth) + x]; return data[(y * ImageWidth) + x];
} }
@@ -92,9 +92,12 @@ MomentProcessor::MomentStatistic MomentProcessor::GetStatistic(const std::vector
std::size_t width, std::size_t width,
std::size_t height) const { std::size_t height) const {
// The actual implementation is always 320x240 // The actual implementation is always 320x240
static constexpr std::size_t RealWidth = 320; constexpr std::size_t RealWidth = 320;
static constexpr std::size_t RealHeight = 240; constexpr std::size_t RealHeight = 240;
static constexpr std::size_t Threshold = 30; constexpr std::size_t Threshold = 30;
constexpr std::size_t ImageWidth = 40;
constexpr std::size_t ImageHeight = 30;
MomentStatistic statistic{}; MomentStatistic statistic{};
std::size_t active_points{}; std::size_t active_points{};
@@ -143,7 +146,7 @@ void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig conf
static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess); static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold; current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
npad_device->SetCameraFormat(format); npad_device->SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat::Size40x30);
} }
} // namespace Service::IRS } // namespace Service::IRS
+6 -3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,14 +10,14 @@
#include "input_common/drivers/camera.h" #include "input_common/drivers/camera.h"
namespace InputCommon { namespace InputCommon {
constexpr PadIdentifier identifier = { constexpr PadIdentifier camera_identifier = {
.guid = Common::UUID{}, .guid = Common::UUID{},
.port = 0, .port = 0,
.pad = 0, .pad = 0,
}; };
Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) { Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
PreSetController(identifier); PreSetController(camera_identifier);
} }
void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) { void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) {
@@ -33,7 +36,7 @@ void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<cons
} }
} }
SetCamera(identifier, status); SetCamera(camera_identifier, status);
} }
std::size_t Camera::getImageWidth() const { std::size_t Camera::getImageWidth() const {
+16 -16
View File
@@ -26,7 +26,7 @@ constexpr int mouse_axis_x = 0;
constexpr int mouse_axis_y = 1; constexpr int mouse_axis_y = 1;
constexpr int wheel_axis_x = 2; constexpr int wheel_axis_x = 2;
constexpr int wheel_axis_y = 3; constexpr int wheel_axis_y = 3;
constexpr PadIdentifier identifier = { constexpr PadIdentifier mouse_identifier = {
.guid = Common::UUID{}, .guid = Common::UUID{},
.port = 0, .port = 0,
.pad = 0, .pad = 0,
@@ -51,16 +51,16 @@ constexpr PadIdentifier touch_identifier = {
}; };
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) { Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
PreSetController(identifier); PreSetController(mouse_identifier);
PreSetController(real_mouse_identifier); PreSetController(real_mouse_identifier);
PreSetController(touch_identifier); PreSetController(touch_identifier);
PreSetController(motion_identifier); PreSetController(motion_identifier);
// Initialize all mouse axis // Initialize all mouse axis
PreSetAxis(identifier, mouse_axis_x); PreSetAxis(mouse_identifier, mouse_axis_x);
PreSetAxis(identifier, mouse_axis_y); PreSetAxis(mouse_identifier, mouse_axis_y);
PreSetAxis(identifier, wheel_axis_x); PreSetAxis(mouse_identifier, wheel_axis_x);
PreSetAxis(identifier, wheel_axis_y); PreSetAxis(mouse_identifier, wheel_axis_y);
PreSetAxis(real_mouse_identifier, mouse_axis_x); PreSetAxis(real_mouse_identifier, mouse_axis_x);
PreSetAxis(real_mouse_identifier, mouse_axis_y); PreSetAxis(real_mouse_identifier, mouse_axis_y);
PreSetAxis(touch_identifier, mouse_axis_x); PreSetAxis(touch_identifier, mouse_axis_x);
@@ -88,8 +88,8 @@ void Mouse::UpdateStickInput() {
last_mouse_change *= maximum_stick_range; last_mouse_change *= maximum_stick_range;
} }
SetAxis(identifier, mouse_axis_x, last_mouse_change.x); SetAxis(mouse_identifier, mouse_axis_x, last_mouse_change.x);
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y); SetAxis(mouse_identifier, mouse_axis_y, -last_mouse_change.y);
// Decay input over time // Decay input over time
const float clamped_length = (std::min)(1.0f, length); const float clamped_length = (std::min)(1.0f, length);
@@ -165,8 +165,8 @@ void Mouse::Move(int x, int y, int center_x, int center_y) {
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
const float y_sensitivity = const float y_sensitivity =
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity); SetAxis(mouse_identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity); SetAxis(mouse_identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
last_motion_change = { last_motion_change = {
static_cast<float>(-mouse_move.y) * x_sensitivity, static_cast<float>(-mouse_move.y) * x_sensitivity,
@@ -192,7 +192,7 @@ void Mouse::TouchMove(f32 touch_x, f32 touch_y) {
} }
void Mouse::PressButton(int x, int y, MouseButton button) { void Mouse::PressButton(int x, int y, MouseButton button) {
SetButton(identifier, static_cast<int>(button), true); SetButton(mouse_identifier, static_cast<int>(button), true);
// Set initial analog parameters // Set initial analog parameters
mouse_origin = {x, y}; mouse_origin = {x, y};
@@ -211,13 +211,13 @@ void Mouse::PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button) {
} }
void Mouse::ReleaseButton(MouseButton button) { void Mouse::ReleaseButton(MouseButton button) {
SetButton(identifier, static_cast<int>(button), false); SetButton(mouse_identifier, static_cast<int>(button), false);
SetButton(real_mouse_identifier, static_cast<int>(button), false); SetButton(real_mouse_identifier, static_cast<int>(button), false);
SetButton(touch_identifier, static_cast<int>(button), false); SetButton(touch_identifier, static_cast<int>(button), false);
if (!IsMousePanningEnabled()) { if (!IsMousePanningEnabled()) {
SetAxis(identifier, mouse_axis_x, 0); SetAxis(mouse_identifier, mouse_axis_x, 0);
SetAxis(identifier, mouse_axis_y, 0); SetAxis(mouse_identifier, mouse_axis_y, 0);
} }
last_motion_change.x = 0; last_motion_change.x = 0;
@@ -230,8 +230,8 @@ void Mouse::MouseWheelChange(int x, int y) {
wheel_position.x += x; wheel_position.x += x;
wheel_position.y += y; wheel_position.y += y;
last_motion_change.z += static_cast<f32>(y); last_motion_change.z += static_cast<f32>(y);
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); SetAxis(mouse_identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); SetAxis(mouse_identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
} }
void Mouse::ReleaseAllButtons() { void Mouse::ReleaseAllButtons() {
+11 -8
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -6,14 +9,14 @@
namespace InputCommon { namespace InputCommon {
constexpr PadIdentifier identifier = { constexpr PadIdentifier touch_screen_identifier = {
.guid = Common::UUID{}, .guid = Common::UUID{},
.port = 0, .port = 0,
.pad = 0, .pad = 0,
}; };
TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
PreSetController(identifier); PreSetController(touch_screen_identifier);
ReleaseAllTouch(); ReleaseAllTouch();
} }
@@ -26,9 +29,9 @@ void TouchScreen::TouchMoved(float x, float y, std::size_t finger_id) {
} }
const auto i = index.value(); const auto i = index.value();
fingers[i].is_active = true; fingers[i].is_active = true;
SetButton(identifier, static_cast<int>(i), true); SetButton(touch_screen_identifier, static_cast<int>(i), true);
SetAxis(identifier, static_cast<int>(i * 2), x); SetAxis(touch_screen_identifier, static_cast<int>(i * 2), x);
SetAxis(identifier, static_cast<int>(i * 2 + 1), y); SetAxis(touch_screen_identifier, static_cast<int>(i * 2 + 1), y);
} }
void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) { void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) {
@@ -55,9 +58,9 @@ void TouchScreen::TouchReleased(std::size_t finger_id) {
} }
const auto i = index.value(); const auto i = index.value();
fingers[i].is_enabled = false; fingers[i].is_enabled = false;
SetButton(identifier, static_cast<int>(i), false); SetButton(touch_screen_identifier, static_cast<int>(i), false);
SetAxis(identifier, static_cast<int>(i * 2), 0.0f); SetAxis(touch_screen_identifier, static_cast<int>(i * 2), 0.0f);
SetAxis(identifier, static_cast<int>(i * 2 + 1), 0.0f); SetAxis(touch_screen_identifier, static_cast<int>(i * 2 + 1), 0.0f);
} }
std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const { std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const {
+7 -7
View File
@@ -600,7 +600,7 @@ void TestCommunication(const std::string& host, u16 port, const std::function<vo
} }
CalibrationConfigurationJob::CalibrationConfigurationJob( CalibrationConfigurationJob::CalibrationConfigurationJob(
const std::string& host, u16 port, std::function<void(Status)> status_callback, const std::string& host, u16 port, std::function<void(CalibrationStatus)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback) { std::function<void(u16, u16, u16, u16)> data_callback) {
std::thread([=, this] { std::thread([=, this] {
@@ -609,13 +609,13 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
u16 max_x{}; u16 max_x{};
u16 max_y{}; u16 max_y{};
Status current_status{Status::Initialized}; auto current_status = CalibrationStatus::Initialized;
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) { SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) {
constexpr u16 CALIBRATION_THRESHOLD = 100; constexpr u16 CALIBRATION_THRESHOLD = 100;
if (current_status == Status::Initialized) { if (current_status == CalibrationStatus::Initialized) {
// Receiving data means the communication is ready now // Receiving data means the communication is ready now
current_status = Status::Ready; current_status = CalibrationStatus::Ready;
status_callback(current_status); status_callback(current_status);
} }
if (data.touch[0].is_active == 0) { if (data.touch[0].is_active == 0) {
@@ -624,9 +624,9 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y); LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y);
min_x = (std::min)(min_x, u16(data.touch[0].x)); min_x = (std::min)(min_x, u16(data.touch[0].x));
min_y = (std::min)(min_y, u16(data.touch[0].y)); min_y = (std::min)(min_y, u16(data.touch[0].y));
if (current_status == Status::Ready) { if (current_status == CalibrationStatus::Ready) {
// First touch - min data (min_x/min_y) // First touch - min data (min_x/min_y)
current_status = Status::Stage1Completed; current_status = CalibrationStatus::Stage1Completed;
status_callback(current_status); status_callback(current_status);
} }
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
@@ -635,7 +635,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
// configuration // configuration
max_x = data.touch[0].x; max_x = data.touch[0].x;
max_y = data.touch[0].y; max_y = data.touch[0].y;
current_status = Status::Completed; current_status = CalibrationStatus::Completed;
data_callback(min_x, min_y, max_x, max_y); data_callback(min_x, min_y, max_x, max_y);
status_callback(current_status); status_callback(current_status);
+5 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2018 Citra Emulator Project // SPDX-FileCopyrightText: 2018 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -163,7 +166,7 @@ private:
/// An async job allowing configuration of the touchpad calibration. /// An async job allowing configuration of the touchpad calibration.
class CalibrationConfigurationJob { class CalibrationConfigurationJob {
public: public:
enum class Status { enum class CalibrationStatus {
Initialized, Initialized,
Ready, Ready,
Stage1Completed, Stage1Completed,
@@ -176,7 +179,7 @@ public:
* @param data_callback Called when calibration data is ready * @param data_callback Called when calibration data is ready
*/ */
explicit CalibrationConfigurationJob(const std::string& host, u16 port, explicit CalibrationConfigurationJob(const std::string& host, u16 port,
std::function<void(Status)> status_callback, std::function<void(CalibrationStatus)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback); std::function<void(u16, u16, u16, u16)> data_callback);
~CalibrationConfigurationJob(); ~CalibrationConfigurationJob();
void Stop(); void Stop();
+4 -4
View File
@@ -15,7 +15,7 @@
#include "input_common/drivers/virtual_amiibo.h" #include "input_common/drivers/virtual_amiibo.h"
namespace InputCommon { namespace InputCommon {
constexpr PadIdentifier identifier = { constexpr PadIdentifier virtual_amiibo_identifier = {
.guid = Common::UUID{}, .guid = Common::UUID{},
.port = 0, .port = 0,
.pad = 0, .pad = 0,
@@ -228,13 +228,13 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {
status.state = Common::Input::NfcState::NewAmiibo, status.state = Common::Input::NfcState::NewAmiibo,
memcpy(nfc_data.data(), data.data(), data.size_bytes()); memcpy(nfc_data.data(), data.data(), data.size_bytes());
memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length);
SetNfc(identifier, status); SetNfc(virtual_amiibo_identifier, status);
return Info::Success; return Info::Success;
} }
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
if (state == State::TagNearby) { if (state == State::TagNearby) {
SetNfc(identifier, status); SetNfc(virtual_amiibo_identifier, status);
return Info::Success; return Info::Success;
} }
@@ -248,7 +248,7 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
state = State::WaitingForAmiibo; state = State::WaitingForAmiibo;
status.state = Common::Input::NfcState::AmiiboRemoved; status.state = Common::Input::NfcState::AmiiboRemoved;
SetNfc(identifier, status); SetNfc(virtual_amiibo_identifier, status);
status.tag_type = 0; status.tag_type = 0;
return Info::Success; return Info::Success;
} }
+9 -10
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -5,6 +8,7 @@
#include <array> #include <array>
#include <vector> #include <vector>
#include <string>
#include "common/common_types.h" #include "common/common_types.h"
namespace Network { namespace Network {
@@ -118,26 +122,21 @@ private:
template <typename T> template <typename T>
Packet& Packet::Read(std::vector<T>& out_data) { Packet& Packet::Read(std::vector<T>& out_data) {
// First extract the size
u32 size = 0; u32 size = 0;
Read(size); Read(size);
out_data.resize(size); out_data.resize(size);
// Then extract the data for (auto& elem : out_data) {
for (std::size_t i = 0; i < out_data.size(); ++i) { Read(elem);
T character;
Read(character);
out_data[i] = character;
} }
return *this; return *this;
} }
template <typename T, std::size_t S> template <typename T, std::size_t S>
Packet& Packet::Read(std::array<T, S>& out_data) { Packet& Packet::Read(std::array<T, S>& out_data) {
for (std::size_t i = 0; i < out_data.size(); ++i) { for (auto& elem : out_data) {
T character; Read(elem);
Read(character);
out_data[i] = character;
} }
return *this; return *this;
} }

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