Compare commits

..

3 Commits

Author SHA1 Message Date
lizzie 6a7c069824 fix linking issues 2026-09-02 11:37:51 +00:00
lizzie 86df49bbc9 remove latency func 2026-09-02 10:58:33 +00:00
lizzie 4e59b71c59 [audio] Nuke cubeb and use SDL3 exclusively
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-02 10:55:54 +00:00
30 changed files with 175 additions and 1058 deletions
-7
View File
@@ -52,7 +52,6 @@ if (YUZU_STATIC_ROOM)
# disable e v e r y t h i n g
set(ENABLE_QT OFF)
set(YUZU_CMD OFF)
set(ENABLE_CUBEB OFF)
set(ENABLE_UPDATE_CHECKER OFF)
set(USE_DISCORD_PRESENCE OFF)
set(BUILD_TESTING OFF)
@@ -214,8 +213,6 @@ if(MSVC)
endif()
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
set(EXT_DEFAULT OFF)
if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
@@ -574,10 +571,6 @@ if (NOT YUZU_STATIC_ROOM)
find_package(DiscordRPC)
endif()
if (ENABLE_CUBEB)
find_package(cubeb)
endif()
if (YUZU_TESTS OR DYNARMIC_TESTS)
find_package(Catch2)
endif()
-12
View File
@@ -54,18 +54,6 @@
"repo": "arun11299/cpp-jwt",
"version": "7f24eb4c32"
},
"cubeb": {
"find_args": "CONFIG",
"hash": "8a4bcb2f83ba590f52c66626e895304a73eb61928dbc57777e1822e55378e3568366f17f9da4b80036cc2ef4ea9723c32abf6e7d9bbe00fb03654f0991596ab0",
"options": [
"USE_SANITIZERS OFF",
"BUILD_TESTS OFF",
"BUILD_TOOLS OFF",
"BUNDLE_SPEEX ON"
],
"repo": "mozilla/cubeb",
"version": "fa02160712"
},
"discord-rpc": {
"find_args": "MODULE",
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
-2
View File
@@ -100,8 +100,6 @@ For reasons unberknownst to any human being, `glslangValidator` will crash upon
For this reason this patch is NOT applied to default on all platforms (for obvious reasons) - instead this is a HaikuOS specific patch, apply with `git apply <absolute path to patch>` after cloning SPIRV-Tools then `make -C build` and add the resulting binary (in `build/StandAlone/glslang`) into PATH.
`cubeb_devel` will also not work, either disable cubeb or uninstall it.
Still will not run flawlessly until `mesa-24` is available. Modify CMakeCache.txt with the `.so` of libGL and libGLESv2 by doing the incredibly difficult task of copy pasting them (`cp /boot/system/lib/libGL.so .`)
If you have `quazip1_qt6_devel`, uninstall it. It may call `Core5Compat` on CMake which is wrongly packaged.
+2 -3
View File
@@ -73,7 +73,6 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
* [SimpleIni](https://github.com/brofield/simpleini)
* [DiscordRPC](https://github.com/eden-emulator/discord-rpc)
* [cubeb](https://github.com/mozilla/cubeb)
* [libusb](https://github.com/libusb/libusb)
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
* [sirit](https://github.com/eden-emulator/sirit)
@@ -122,7 +121,7 @@ sudo emerge -a \
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
dev-util/vulkan-utility-libraries dev-util/glslang \
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
media-libs/VulkanMemoryAllocator media-libs/libsdl3 media-libs/cubeb \
media-libs/VulkanMemoryAllocator media-libs/libsdl3 \
net-libs/enet \
sys-libs/zlib \
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
@@ -356,7 +355,7 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel simpleini quazip_qt6_devel
```
[Caveats](./Caveats.md#haikuos).
+1 -1
View File
@@ -4,7 +4,7 @@ Modern game consoles require heavy power to be emulated appropriately. This is w
For example, take a disk write, instead of emulating a proper SD card we instead use the C++ standard library for I/O. Additionally we use the abstractions provided by the `fs` service to "lie" to programs about certain SD card properties. Notably this includes making up sizes for the fake SD card, giving "realistic" values or expected outputs for a given card, and so on. And instead of writing to an actual SD card, the emulator simply writes to a file.
This also means grand part of the emulator consists of just re-implementing firmware but using HLE primitives; for example audio doesn't go to an emulated audio device, but rather gets processed on the fly by a dedicated service and then passed to SDL3/cubeb/etc.
This also means grand part of the emulator consists of just re-implementing firmware but using HLE primitives; for example audio doesn't go to an emulated audio device, but rather gets processed on the fly by a dedicated service and then passed to SDL3 or null backend.
As such, many of the systems implemented are not 100% accurate to the original software, but they're "good enough" to pass as being so. While we do strive to maintain high compatibility (especially with homebrew), there are realistic limitations to these approaches.
-2
View File
@@ -35,8 +35,6 @@ These options control dependencies.
- `ENABLE_WEB_SERVICE` (ON) Enable multiplayer service
- `ENABLE_WIFI_SCAN` (OFF) Enable WiFi scanning (requires iw on Linux) - experimental
- `ENABLE_CUBEB` (ON) Enables the cubeb audio backend
- This option is subject for removal.
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
- `ENABLE_LTO` (OFF) Enable link-time optimization
- Not recommended on Windows
-30
View File
@@ -106,36 +106,6 @@ endif()
# SimpleIni
AddJsonPackage(simpleini)
# Most linux distros don't package cubeb, so enable regardless of cpm settings
if(ENABLE_CUBEB)
AddJsonPackage(cubeb)
if (cubeb_ADDED)
if (NOT MSVC)
if (TARGET speex)
target_compile_options(speex PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-compare>)
endif()
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
target_compile_options(cubeb INTERFACE
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-const-int-float-conversion>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-declarations>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-return-type>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-uninitialized>
)
else()
target_compile_options(cubeb PRIVATE
/wd4456
/wd4458
)
endif()
endif()
if (NOT TARGET cubeb::cubeb)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
endif()
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
+1 -1
View File
@@ -15,7 +15,7 @@ pkgs.mkShellNoCC {
enet libopus vulkan-headers vulkan-utility-libraries
spirv-tools spirv-headers vulkan-loader unzip
glslang python3 httplib cpp-jwt ffmpeg-headless
libusb1 cubeb
libusb1
# eden
qt6.qtbase qt6.qtmultimedia qt6.qtwayland qt6.qttools
qt6.qtwebengine qt6.qt5compat
@@ -58,13 +58,6 @@ class LicensesFragment : Fragment() {
R.string.license_fidelityfx_fsr_copyright,
R.string.license_fidelityfx_fsr_text
),
License(
R.string.license_cubeb,
R.string.license_cubeb_description,
R.string.license_cubeb_link,
R.string.license_cubeb_copyright,
R.string.license_cubeb_text
),
License(
R.string.license_dynarmic,
R.string.license_dynarmic_description,
@@ -799,9 +799,6 @@
<string name="theme_mode_light">روشن</string>
<string name="theme_mode_dark">تاریک</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_x2">x2</string>
<string name="multiplier_x4">x4</string>
@@ -466,13 +466,11 @@
<string-array name="outputEngineEntries">
<item>@string/auto</item>
<item>@string/sdl3</item>
<item>@string/cubeb</item>
<item>@string/string_null</item>
</string-array>
<integer-array name="outputEngineValues">
<item>0</item>
<item>2</item>
<item>1</item>
<item>3</item>
</integer-array>
@@ -1241,7 +1241,6 @@
<!-- Audio output engines -->
<string name="sdl3" translatable="false">SDL3</string>
<string name="cubeb" translatable="false">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_x2" translatable="false">x2</string>
@@ -1381,23 +1380,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<string name="license_cubeb" translatable="false">cubeb</string>
<string name="license_cubeb_description" translatable="false">Cross platform audio library</string>
<string name="license_cubeb_link" translatable="false">https://github.com/mozilla/cubeb</string>
<string name="license_cubeb_copyright" translatable="false">Copyright © 2011 Mozilla Foundation</string>
<string name="license_cubeb_text" translatable="false">
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.\n\n
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</string>
<string name="license_dynarmic" translatable="false">Dynarmic</string>
<string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string>
+4 -9
View File
@@ -229,15 +229,6 @@ endif()
target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS})
target_link_libraries(audio_core PUBLIC common core Opus::opus)
if (ENABLE_CUBEB)
target_sources(audio_core PRIVATE
sink/cubeb_sink.cpp
sink/cubeb_sink.h)
target_link_libraries(audio_core PRIVATE cubeb::cubeb)
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
endif()
target_sources(audio_core PRIVATE
sink/sdl3_sink.cpp
sink/sdl3_sink.h)
@@ -245,4 +236,8 @@ target_sources(audio_core PRIVATE
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
if (ANDROID)
target_link_libraries(audio_core PRIVATE OpenSLES)
endif()
create_target_directory_groups(audio_core)
-450
View File
@@ -1,450 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <span>
#include <vector>
#include "audio_core/common/common.h"
#include "audio_core/sink/cubeb_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging.h"
#include "common/scope_exit.h"
#include "core/core.h"
#ifdef _WIN32
#include <objbase.h>
#undef CreateEvent
#endif
namespace AudioCore::Sink {
/**
* Cubeb sink stream, responsible for sinking samples to hardware.
*/
class CubebSinkStream final : public SinkStream {
public:
/**
* Create a new sink stream.
*
* @param ctx_ - Cubeb context to create this stream with.
* @param device_channels_ - Number of channels supported by the hardware.
* @param system_channels_ - Number of channels the audio systems expect.
* @param output_device - Cubeb output device id.
* @param input_device - Cubeb input device id.
* @param name_ - Name of this stream.
* @param type_ - Type of this stream.
* @param system_ - Core system.
* @param event - Event used only for audio renderer, signalled on buffer consume.
*/
CubebSinkStream(cubeb* ctx_, u32 device_channels_, u32 system_channels_,
cubeb_devid output_device, cubeb_devid input_device, const std::string& name_,
StreamType type_, Core::System& system_)
: SinkStream(system_, type_), ctx{ctx_} {
#ifdef _WIN32
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
name = name_;
device_channels = device_channels_;
system_channels = system_channels_;
cubeb_stream_params params{};
params.rate = TargetSampleRate;
params.channels = device_channels;
params.format = CUBEB_SAMPLE_S16LE;
params.prefs = CUBEB_STREAM_PREF_NONE;
switch (params.channels) {
case 1:
params.layout = CUBEB_LAYOUT_MONO;
break;
case 2:
params.layout = CUBEB_LAYOUT_STEREO;
break;
case 6:
params.layout = CUBEB_LAYOUT_3F2_LFE;
break;
}
u32 minimum_latency{0};
const auto latency_error = cubeb_get_min_latency(ctx, &params, &minimum_latency);
if (latency_error != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error);
minimum_latency = TargetSampleCount * 2;
}
minimum_latency = (std::max)(minimum_latency, TargetSampleCount * 2);
LOG_INFO(Service_Audio,
"Opening cubeb stream {} type {} with: rate {} channels {} (system channels {}) "
"latency {}",
name, type, params.rate, params.channels, system_channels, minimum_latency);
auto init_error{0};
if (type == StreamType::In) {
init_error = cubeb_stream_init(ctx, &stream_backend, name.c_str(), input_device,
&params, output_device, nullptr, minimum_latency,
&CubebSinkStream::DataCallback,
&CubebSinkStream::StateCallback, this);
} else {
init_error = cubeb_stream_init(ctx, &stream_backend, name.c_str(), input_device,
nullptr, output_device, &params, minimum_latency,
&CubebSinkStream::DataCallback,
&CubebSinkStream::StateCallback, this);
}
if (init_error != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream, error: {}", init_error);
return;
}
}
/**
* Destroy the sink stream.
*/
~CubebSinkStream() override {
LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name);
if (!ctx) {
return;
}
Finalize();
#ifdef _WIN32
CoUninitialize();
#endif
}
/**
* Finalize the sink stream.
*/
void Finalize() override {
Stop();
cubeb_stream_destroy(stream_backend);
}
/**
* Start the sink stream.
*
* @param resume - Set to true if this is resuming the stream a previously-active stream.
* Default false.
*/
void Start(bool resume = false) override {
if (!ctx || !paused) {
return;
}
paused = false;
if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
}
}
/**
* Stop the sink stream.
*/
void Stop() override {
if (!ctx || paused) {
return;
}
SignalPause();
if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
}
}
private:
/**
* Main callback from Cubeb. Either expects samples from us (audio render/audio out), or will
* provide samples to be copied (audio in).
*
* @param stream - Cubeb-specific data about the stream.
* @param user_data - Custom data pointer passed along, points to a CubebSinkStream.
* @param in_buff - Input buffer to be used if the stream is an input type.
* @param out_buff - Output buffer to be used if the stream is an output type.
* @param num_frames_ - Number of frames of audio in the buffers. Note: Not number of samples.
*/
static long DataCallback([[maybe_unused]] cubeb_stream* stream, void* user_data,
[[maybe_unused]] const void* in_buff, void* out_buff,
long num_frames_) {
auto* impl = static_cast<CubebSinkStream*>(user_data);
if (!impl) {
return -1;
}
const std::size_t num_channels = impl->GetDeviceChannels();
const std::size_t frame_size = num_channels;
const std::size_t num_frames{static_cast<size_t>(num_frames_)};
if (impl->type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(in_buff),
num_frames * frame_size};
impl->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(out_buff), num_frames * frame_size};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
}
return num_frames_;
}
/**
* Cubeb callback for if a device state changes. Unused currently.
*
* @param stream - Cubeb-specific data about the stream.
* @param user_data - Custom data pointer passed along, points to a CubebSinkStream.
* @param state - New state of the device.
*/
static void StateCallback(cubeb_stream*, void*, cubeb_state) {}
/// Main Cubeb context
cubeb* ctx{};
/// Cubeb stream backend
cubeb_stream* stream_backend{};
};
CubebSink::CubebSink(std::string_view target_device_name) {
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
#ifdef _WIN32
com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
if (cubeb_init(&ctx, "Eden", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return;
}
if (target_device_name != auto_device_name && !target_device_name.empty()) {
cubeb_device_collection collection;
if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
} else {
const auto collection_end{collection.device + collection.count};
const auto device{
std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) {
return info.friendly_name != nullptr &&
target_device_name == std::string(info.friendly_name);
})};
if (device != collection_end) {
output_device = device->devid;
}
cubeb_device_collection_destroy(ctx, &collection);
}
}
cubeb_get_max_channel_count(ctx, &device_channels);
device_channels = device_channels >= 6U ? 6U : 2U;
}
CubebSink::~CubebSink() {
if (!ctx) {
return;
}
for (auto& sink_stream : sink_streams) {
sink_stream.reset();
}
cubeb_destroy(ctx);
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
}
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
const std::string& name, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
ctx, device_channels, system_channels, output_device, input_device, name, type, system));
return stream.get();
}
void CubebSink::CloseStream(SinkStream* stream) {
for (size_t i = 0; i < sink_streams.size(); i++) {
if (sink_streams[i].get() == stream) {
sink_streams[i].reset();
sink_streams.erase(sink_streams.begin() + i);
break;
}
}
}
void CubebSink::CloseStreams() {
sink_streams.clear();
}
f32 CubebSink::GetDeviceVolume() const {
if (sink_streams.empty()) {
return 1.0f;
}
return sink_streams[0]->GetDeviceVolume();
}
void CubebSink::SetDeviceVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetDeviceVolume(volume);
}
}
void CubebSink::SetSystemVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetSystemVolume(volume);
}
}
std::vector<std::string> ListCubebSinkDevices(bool capture) {
std::vector<std::string> device_list;
cubeb* ctx;
#ifdef _WIN32
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
if (cubeb_init(&ctx, "Eden Device Enumerator", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return {};
}
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
auto type{capture ? CUBEB_DEVICE_TYPE_INPUT : CUBEB_DEVICE_TYPE_OUTPUT};
cubeb_device_collection collection;
if (cubeb_enumerate_devices(ctx, type, &collection) != CUBEB_OK) {
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
} else {
for (std::size_t i = 0; i < collection.count; i++) {
const cubeb_device_info& device = collection.device[i];
if (device.friendly_name && device.friendly_name[0] != '\0' &&
device.state == CUBEB_DEVICE_STATE_ENABLED) {
device_list.emplace_back(device.friendly_name);
}
}
cubeb_device_collection_destroy(ctx, &collection);
}
cubeb_destroy(ctx);
return device_list;
}
/* REVERSION TO 3833 - function GetCubebLatency REINTRODUCED FROM 3833 - DIABLO 3 FIX */
u32 GetCubebLatency() {
cubeb* ctx;
#ifdef _WIN32
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
// Init cubeb
if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
// Return a large latency so we choose SDL instead.
return 10000u;
}
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
// Get min latency
cubeb_stream_params params{};
params.rate = TargetSampleRate;
params.channels = 2;
params.format = CUBEB_SAMPLE_S16LE;
params.prefs = CUBEB_STREAM_PREF_NONE;
params.layout = CUBEB_LAYOUT_STEREO;
u32 latency{0};
const auto latency_error = cubeb_get_min_latency(ctx, &params, &latency);
if (latency_error != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error);
latency = TargetSampleCount * 2;
}
latency = (std::max)(latency, TargetSampleCount * 2);
cubeb_destroy(ctx);
return latency;
}
// REVERTED back to 3833 - Below namespace section and function IsCubebSuitable() removed, reverting to GetCubebLatency() above. - DIABLO 3 FIX
/*
namespace {
static long TmpDataCallback(cubeb_stream*, void*, const void*, void*, long) {
return TargetSampleCount;
}
static void TmpStateCallback(cubeb_stream*, void*, cubeb_state) {}
} // namespace
bool IsCubebSuitable() {
#if !defined(HAVE_CUBEB)
return false;
#else
cubeb* ctx{nullptr};
#ifdef _WIN32
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
// Init cubeb
if (cubeb_init(&ctx, "Eden Latency Getter", nullptr) != CUBEB_OK) {
LOG_ERROR(Audio_Sink, "Cubeb failed to init, it is not suitable.");
return false;
}
SCOPE_EXIT {
cubeb_destroy(ctx);
};
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
// Get min latency
cubeb_stream_params params{};
params.rate = TargetSampleRate;
params.channels = 2;
params.format = CUBEB_SAMPLE_S16LE;
params.prefs = CUBEB_STREAM_PREF_NONE;
params.layout = CUBEB_LAYOUT_STEREO;
u32 latency{0};
const auto latency_error = cubeb_get_min_latency(ctx, &params, &latency);
if (latency_error != CUBEB_OK) {
LOG_ERROR(Audio_Sink, "Cubeb could not get min latency, it is not suitable.");
return false;
}
latency = (std::max)(latency, TargetSampleCount * 2);
// Test opening a device with standard parameters
cubeb_devid output_device{0};
cubeb_devid input_device{0};
std::string name{"Eden test"};
cubeb_stream* stream{nullptr};
if (cubeb_stream_init(ctx, &stream, name.c_str(), input_device, nullptr, output_device, &params,
latency, &TmpDataCallback, &TmpStateCallback, nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Cubeb could not open a device, it is not suitable.");
return false;
}
cubeb_stream_stop(stream);
cubeb_stream_destroy(stream);
return true;
#endif
}
*/
} // namespace AudioCore::Sink
-118
View File
@@ -1,118 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <vector>
#include <cubeb/cubeb.h>
#include "audio_core/sink/sink.h"
namespace Core {
class System;
}
namespace AudioCore::Sink {
class SinkStream;
/**
* Cubeb backend sink, holds multiple output streams and is responsible for sinking samples to
* hardware. Used by Audio Render, Audio In and Audio Out.
*/
class CubebSink final : public Sink {
public:
explicit CubebSink(std::string_view device_id);
~CubebSink() override;
/**
* Create a new sink stream.
*
* @param system - Core system.
* @param system_channels - Number of channels the audio system expects.
* May differ from the device's channel count.
* @param name - Name of this stream.
* @param type - Type of this stream, render/in/out.
*
* @return A pointer to the created SinkStream
*/
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) override;
/**
* Close a given stream.
*
* @param stream - The stream to close.
*/
void CloseStream(SinkStream* stream) override;
/**
* Close all streams.
*/
void CloseStreams() override;
/**
* Get the device volume. Set from calls to the IAudioDevice service.
*
* @return Volume of the device.
*/
f32 GetDeviceVolume() const override;
/**
* Set the device volume. Set from calls to the IAudioDevice service.
*
* @param volume - New volume of the device.
*/
void SetDeviceVolume(f32 volume) override;
/**
* Set the system volume. Comes from the audio system using this stream.
*
* @param volume - New volume of the system.
*/
void SetSystemVolume(f32 volume) override;
private:
/// Backend Cubeb context
cubeb* ctx{};
/// Cubeb id of the actual hardware output device
cubeb_devid output_device{};
/// Cubeb id of the actual hardware input device
cubeb_devid input_device{};
/// Vector of streams managed by this sink
std::vector<SinkStreamPtr> sink_streams{};
#ifdef _WIN32
/// Cubeb required COM to be initialized multi-threaded on Windows
u32 com_init_result = 0;
#endif
};
/**
* Get a list of connected devices from Cubeb.
*
* @param capture - Return input (capture) devices if true, otherwise output devices.
*/
std::vector<std::string> ListCubebSinkDevices(bool capture);
// REVERSION - function GetCubebLatency() reintroduced from EA-3833 - DIABLO 3 FIX
/**
* Get the reported latency for this sink.
*
* @return Minimum latency for this sink.
*/
u32 GetCubebLatency();
/**
* Check if this backend is suitable for use.
* Checks if enabled, its latency, whether it opens successfully, etc.
*
* @return True is this backend is suitable, false otherwise.
*/
// bool IsCubebSuitable(); // REVERTED BACK TO GetCubebLatency() FROM 3833
} // namespace AudioCore::Sink
+60 -138
View File
@@ -25,9 +25,10 @@ namespace {
// See https://github.com/PCSX2/pcsx2/pull/12312
// "SDL and cubeb backends previously resulted in different names for the output which
// caused them be identified as different applications by the OS."
//
// Keep in sync with cubeb_sink.cpp name.
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
SDL_SetHint("SDL_HINT_AUDIO_DEVICE_STREAM_ROLE", "Game");
// We do our own processing, so just have SDL copy our audio
SDL_SetHint("SDL_HINT_AUDIO_DEVICE_RAW_STREAM", "1");
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return false;
@@ -82,23 +83,18 @@ public:
SDL_AudioSpec spec{};
spec.freq = TargetSampleRate;
spec.channels = static_cast<u8>(device_channels);
spec.format = SDL_AUDIO_S16;
spec.channels = u8(device_channels);
spec.format = SDL_AUDIO_S16LE;
std::string device_name{output_device};
bool capture{false};
if (type == StreamType::In) {
device_name = input_device;
capture = true;
}
auto const is_capture = (type == StreamType::In);
std::string device_name = is_capture ? input_device : output_device;
const SDL_AudioDeviceID audio_device = device_name.empty()
? (is_capture
? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)
: FindAudioDeviceByName(device_name, is_capture);
const SDL_AudioDeviceID audio_device =
device_name.empty() ? (capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)
: FindAudioDeviceByName(device_name, capture);
stream = SDL_OpenAudioDeviceStream(audio_device, &spec, &SDLSinkStream::DataCallback,
this);
stream = SDL_OpenAudioDeviceStream(audio_device, &spec, &SDLSinkStream::DataCallback, this);
if (stream == nullptr) {
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
@@ -107,13 +103,12 @@ public:
SDL_AudioSpec stream_in{};
SDL_AudioSpec stream_out{};
static_cast<void>(SDL_GetAudioStreamFormat(stream, &stream_in, &stream_out));
void(SDL_GetAudioStreamFormat(stream, &stream_in, &stream_out));
LOG_INFO(Service_Audio,
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
" format {}",
static_cast<const void*>(stream), stream_out.freq, stream_out.channels,
system_channels, static_cast<int>(stream_out.format));
system_channels, int(stream_out.format));
}
/**
@@ -128,14 +123,12 @@ public:
* Finalize the sink stream.
*/
void Finalize() override {
if (stream == nullptr) {
return;
if (stream != nullptr) {
Stop();
SDL_ClearAudioStream(stream);
SDL_DestroyAudioStream(stream);
stream = nullptr;
}
Stop();
SDL_ClearAudioStream(stream);
SDL_DestroyAudioStream(stream);
stream = nullptr;
}
/**
@@ -148,9 +141,8 @@ public:
if (stream == nullptr || !paused) {
return;
}
paused = false;
static_cast<void>(SDL_ResumeAudioStreamDevice(stream));
void(SDL_ResumeAudioStreamDevice(stream));
}
/**
@@ -161,7 +153,7 @@ public:
return;
}
SignalPause();
static_cast<void>(SDL_PauseAudioStreamDevice(stream));
void(SDL_PauseAudioStreamDevice(stream));
}
private:
@@ -173,51 +165,34 @@ private:
* @param stream - Buffer of samples to be filled or read.
* @param len - Length of the stream in bytes.
*/
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
int total_amount) {
auto* impl = static_cast<SDLSinkStream*>(userdata);
if (!impl) {
return;
}
const std::size_t num_channels = impl->GetDeviceChannels();
const std::size_t frame_size = num_channels;
if (impl->type == StreamType::In) {
const int bytes_available = SDL_GetAudioStreamAvailable(stream);
if (bytes_available <= 0) {
return;
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount) {
if (auto* impl = static_cast<SDLSinkStream*>(userdata); impl) {
auto const num_channels = impl->GetDeviceChannels();
auto const frame_size = num_channels;
if (impl->type == StreamType::In) {
auto const bytes_available = SDL_GetAudioStreamAvailable(stream);
if (bytes_available > 0) {
std::vector<s16> input(bytes_available / int(sizeof(s16)));
auto const bytes_read = SDL_GetAudioStreamData(stream, input.data(), bytes_available);
if (bytes_read > 0) {
auto const num_frames = std::size_t(bytes_read) / sizeof(s16) / frame_size;
std::span<const s16> input_buffer{input.data(), std::size_t(bytes_read) / sizeof(s16)};
impl->ProcessAudioIn(input_buffer, num_frames);
}
}
} else if (additional_amount > 0 || total_amount > 0) {
auto const bytes_requested = additional_amount > 0 ? additional_amount : total_amount;
std::vector<s16> output(bytes_requested / int(sizeof(s16)));
auto const num_frames = std::size_t(bytes_requested) / sizeof(s16) / frame_size;
std::span<s16> output_buffer{output.data(), output.size()};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
void(SDL_PutAudioStreamData(stream, output.data(), bytes_requested));
}
std::vector<s16> input(bytes_available / static_cast<int>(sizeof(s16)));
const int bytes_read = SDL_GetAudioStreamData(stream, input.data(), bytes_available);
if (bytes_read <= 0) {
return;
}
const std::size_t num_frames =
static_cast<std::size_t>(bytes_read) / sizeof(s16) / frame_size;
std::span<const s16> input_buffer{input.data(),
static_cast<std::size_t>(bytes_read) / sizeof(s16)};
impl->ProcessAudioIn(input_buffer, num_frames);
} else {
if (additional_amount <= 0 && total_amount <= 0) {
return;
}
const int bytes_requested = additional_amount > 0 ? additional_amount : total_amount;
std::vector<s16> output(bytes_requested / static_cast<int>(sizeof(s16)));
const std::size_t num_frames =
static_cast<std::size_t>(bytes_requested) / sizeof(s16) / frame_size;
std::span<s16> output_buffer{output.data(), output.size()};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
static_cast<void>(SDL_PutAudioStreamData(stream, output.data(), bytes_requested));
}
}
/// SDL stream attached to an opened input/output device
SDL_AudioStream* stream{};
SDL_AudioStream* stream = nullptr;
};
SDLSink::SDLSink(std::string_view target_device_name) {
@@ -233,11 +208,9 @@ SDLSink::SDLSink(std::string_view target_device_name) {
SDLSink::~SDLSink() = default;
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
const std::string&, StreamType type) {
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_, const std::string&, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
device_channels, system_channels, output_device, input_device, type, system));
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(device_channels, system_channels, output_device, input_device, type, system));
return stream.get();
}
@@ -256,11 +229,7 @@ void SDLSink::CloseStreams() {
}
f32 SDLSink::GetDeviceVolume() const {
if (sink_streams.empty()) {
return 1.0f;
}
return sink_streams[0]->GetDeviceVolume();
return sink_streams.empty() ? 1.0f : sink_streams[0]->GetDeviceVolume();
}
void SDLSink::SetDeviceVolume(f32 volume) {
@@ -275,68 +244,21 @@ void SDLSink::SetSystemVolume(f32 volume) {
}
}
std::vector<std::string> ListSDLSinkDevices(bool capture) {
if (!InitializeAudio())
return {}; //no devices
std::vector<std::string> device_list;
int device_count = 0;
SDL_AudioDeviceID* devices =
capture ? SDL_GetAudioRecordingDevices(&device_count)
: SDL_GetAudioPlaybackDevices(&device_count);
if (devices == nullptr) {
return device_list;
}
for (int i = 0; i < device_count; ++i) {
if (const char* name = SDL_GetAudioDeviceName(devices[i])) {
device_list.emplace_back(name);
std::vector<std::string> ListSDLSinkDevices(bool is_capture) {
std::vector<std::string> device_list{};
if (InitializeAudio()) {
int device_count = 0;
SDL_AudioDeviceID* devices = is_capture ? SDL_GetAudioRecordingDevices(&device_count) : SDL_GetAudioPlaybackDevices(&device_count);
if (devices != nullptr) {
for (int i = 0; i < device_count; ++i) {
if (const char* name = SDL_GetAudioDeviceName(devices[i]); name) {
device_list.emplace_back(name);
}
}
SDL_free(devices);
}
}
SDL_free(devices);
return device_list;
}
/* REVERSION to 3833 - function GetSDLLatency() REINTRODUCED FROM 3833 - DIABLO 3 FIX */
u32 GetSDLLatency() {
return TargetSampleCount * 2;
}
// REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
/*
bool IsSDLSuitable() {
#if !defined(HAVE_SDL3)
return false;
#else
// Check SDL can init
if (!InitializeAudio()!
return false;
// We can set any latency frequency we want with SDL, so no need to check that.
// Check we can open a device with standard parameters
SDL_AudioSpec spec;
spec.freq = TargetSampleRate;
spec.channels = 2u;
spec.format = AUDIO_S16SYS;
spec.samples = TargetSampleCount * 2;
spec.callback = nullptr;
spec.userdata = nullptr;
SDL_AudioSpec obtained;
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
if (device == 0) {
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
SDL_GetError());
return false;
}
SDL_CloseAudioDevice(device);
return true;
#endif
}
*/
} // namespace AudioCore::Sink
-16
View File
@@ -90,20 +90,4 @@ private:
*/
std::vector<std::string> ListSDLSinkDevices(bool capture);
// REVERSION - function GetSDLLatency() reintroduced from EA-3833 - DIABLO 3 FIX
/**
* Get the reported latency for this sink.
*
* @return Minimum latency for this sink.
*/
u32 GetSDLLatency();
/** REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
* Check if this backend is suitable for use.
* Checks if enabled, its latency, whether it opens successfully, etc.
*
* @return True is this backend is suitable, false otherwise.
*/
//bool IsSDLSuitable(); // REVERTED for GetSDLLatency() from EA-3833
} // namespace AudioCore::Sink
+7 -62
View File
@@ -10,9 +10,6 @@
#include <vector>
#include "audio_core/sink/sink_details.h"
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
#ifdef HAVE_SDL3
#include "audio_core/sink/sdl3_sink.h"
#endif
@@ -34,24 +31,10 @@ struct SinkDetails {
FactoryFn factory;
/// A method to call to list available devices.
ListDevicesFn list_devices;
/// Method to get the latency of this backend - REINTRODUCED FROM 3833 - DIABLO 3 FIX
LatencyFn latency;
/// Check whether this backend is suitable to be used.
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
};
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef HAVE_CUBEB
SinkDetails{
Settings::AudioEngine::Cubeb,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<CubebSink>(device_id);
},
&ListCubebSinkDevices,
&GetCubebLatency,
},
#endif
static constexpr SinkDetails sink_details[] = {
#ifdef HAVE_SDL3
SinkDetails{
Settings::AudioEngine::Sdl3,
@@ -59,7 +42,6 @@ constexpr SinkDetails sink_details[] = {
return std::make_unique<SDLSink>(device_id);
},
&ListSDLSinkDevices,
&GetSDLLatency,
},
#endif
SinkDetails{
@@ -68,69 +50,32 @@ constexpr SinkDetails sink_details[] = {
return std::make_unique<NullSink>(device_id);
},
[](bool capture) { return std::vector<std::string>{"null"}; },
[]() { return 0u; },
},
};
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
const auto find_backend{[](Settings::AudioEngine id) {
return std::find_if(std::begin(sink_details), std::end(sink_details),
[&id](const auto& sink_detail) { return sink_detail.id == id; });
return std::ranges::find_if(std::begin(sink_details), std::end(sink_details), [&id](const auto& e) {
return e.id == id;
});
}};
auto iter = find_backend(sink_id);
if (sink_id == Settings::AudioEngine::Auto) {
// REVERTED TO 3833 BELOW - DIABLO 3 FIX
/*
// Auto-select a backend. Use the sink details ordering, preferring cubeb first, checking
// that the backend is available and suitable to use.
for (auto& details : sink_details) {
if (details.is_suitable()) {
iter = &details;
break;
}
}
*/ // END REVERTED CODE - DIABLO 3 FIX
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
// causes audio issues, in that case go with SDL.
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
iter = find_backend(Settings::AudioEngine::Cubeb);
if (iter->latency() > TargetSampleCount * 3) {
if (sink_id == Settings::AudioEngine::Cubeb || sink_id == Settings::AudioEngine::Auto) {
iter = find_backend(Settings::AudioEngine::Sdl3);
}
#else
iter = std::begin(sink_details);
#endif
// END REINTRODUCED SECTION FROM 3833 - DIABLO 3 FIX
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
Settings::CanonicalizeEnum(iter->id));
/* BEGIN REMOVED - REVERTING BACK TO 3833, this didn't exist at all. - DIABLO 3 FIX
} else {
if (iter != std::end(sink_details) && !iter->is_suitable()) {
LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null",
Settings::CanonicalizeEnum(iter->id));
iter = find_backend(Settings::AudioEngine::Null);
} */ // END REMOVED REVERT - DIABLO 3 FIX
LOG_INFO(Service_Audio, "Auto-selecting the {} backend", Settings::CanonicalizeEnum(iter->id));
}
if (iter == std::end(sink_details)) {
LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
iter = find_backend(Settings::AudioEngine::Null);
}
return *iter;
}
} // Anonymous namespace
std::vector<Settings::AudioEngine> GetSinkIDs() {
std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
[](const auto& sink) { return sink.id; });
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids), [](const auto& sink) { return sink.id; });
return sink_ids;
}
+72 -58
View File
@@ -10,15 +10,17 @@
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_version.h"
namespace Kernel::Svc {
/// Gets system/memory information for the current process
Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle, u64 info_sub_id) {
LOG_TRACE(Kernel_SVC, "called info_id={:#x}, info_sub_id={:#x}, handle={:#08x}", info_id_type, info_sub_id, handle);
u32 info_id = u32(info_id_type);
Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle,
u64 info_sub_id) {
LOG_TRACE(Kernel_SVC, "called info_id={:#x}, info_sub_id={:#x}, handle={:#08x}",
info_id_type, info_sub_id, handle);
u32 info_id = static_cast<u32>(info_id_type);
switch (info_id_type) {
case InfoType::CoreMask:
case InfoType::PriorityMask:
@@ -51,123 +53,152 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
case InfoType::CoreMask:
*result = process->GetCoreMask();
R_SUCCEED();
case InfoType::PriorityMask:
*result = process->GetPriorityMask();
R_SUCCEED();
case InfoType::AliasRegionAddress:
*result = GetInteger(process->GetPageTable().GetAliasRegionStart());
R_SUCCEED();
case InfoType::AliasRegionSize:
*result = process->GetPageTable().GetAliasRegionSize();
R_SUCCEED();
case InfoType::HeapRegionAddress:
*result = GetInteger(process->GetPageTable().GetHeapRegionStart());
R_SUCCEED();
case InfoType::HeapRegionSize:
*result = process->GetPageTable().GetHeapRegionSize();
R_SUCCEED();
case InfoType::AslrRegionAddress:
*result = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
R_SUCCEED();
case InfoType::AslrRegionSize:
*result = process->GetPageTable().GetAliasCodeRegionSize();
R_SUCCEED();
case InfoType::StackRegionAddress:
*result = GetInteger(process->GetPageTable().GetStackRegionStart());
R_SUCCEED();
case InfoType::StackRegionSize:
*result = process->GetPageTable().GetStackRegionSize();
R_SUCCEED();
case InfoType::TotalMemorySize:
*result = process->GetTotalUserPhysicalMemorySize(system.Kernel());
R_SUCCEED();
case InfoType::UsedMemorySize:
*result = process->GetUsedUserPhysicalMemorySize(system.Kernel());
R_SUCCEED();
case InfoType::SystemResourceSizeTotal:
*result = process->GetTotalSystemResourceSize();
R_SUCCEED();
case InfoType::SystemResourceSizeUsed:
*result = process->GetUsedSystemResourceSize();
R_SUCCEED();
case InfoType::ProgramId:
*result = process->GetProgramId();
R_SUCCEED();
case InfoType::UserExceptionContextAddress:
*result = GetInteger(process->GetProcessLocalRegionAddress());
R_SUCCEED();
case InfoType::TotalNonSystemMemorySize:
*result = process->GetTotalNonSystemUserPhysicalMemorySize(system.Kernel());
R_SUCCEED();
case InfoType::UsedNonSystemMemorySize:
*result = process->GetUsedNonSystemUserPhysicalMemorySize(system.Kernel());
R_SUCCEED();
case InfoType::IsApplication:
*result = process->IsApplication();
R_SUCCEED();
case InfoType::FreeThreadCount:
if (KResourceLimit* resource_limit = process->GetResourceLimit();
resource_limit != nullptr) {
const auto current_value = resource_limit->GetCurrentValue(Svc::LimitableResource::ThreadCountMax);
const auto limit_value = resource_limit->GetLimitValue(Svc::LimitableResource::ThreadCountMax);
const auto current_value =
resource_limit->GetCurrentValue(Svc::LimitableResource::ThreadCountMax);
const auto limit_value =
resource_limit->GetLimitValue(Svc::LimitableResource::ThreadCountMax);
*result = limit_value - current_value;
} else {
*result = 0;
}
R_SUCCEED();
case InfoType::AliasRegionExtraSize: {
R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
if (info_sub_id != 0) {
return ResultInvalidCombination;
}
KProcess* current_process = GetCurrentProcessPointer(system.Kernel());
*result = current_process->GetPageTable().GetAliasRegionExtraSize();
R_SUCCEED();
}
default:
break;
}
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id={:#016x}", info_id);
R_THROW(ResultInvalidEnumValue);
}
case InfoType::DebuggerAttached:
*result = 0;
R_SUCCEED();
case InfoType::ResourceLimit: {
R_UNLESS(handle == 0, ResultInvalidHandle);
R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
KProcess* const current_process = GetCurrentProcessPointer(system.Kernel());
KHandleTable& handle_table = current_process->GetHandleTable();
if (auto const resource_limit = current_process->GetResourceLimit(); resource_limit) {
Handle resource_handle{};
R_TRY(handle_table.Add(system.Kernel(), std::addressof(resource_handle), resource_limit));
*result = resource_handle;
} else {
const auto resource_limit = current_process->GetResourceLimit();
if (!resource_limit) {
*result = Svc::InvalidHandle;
// Yes, the kernel considers this a successful operation.
R_SUCCEED();
}
// Yes, the kernel considers this a successful operation either way.
Handle resource_handle{};
R_TRY(handle_table.Add(system.Kernel(), std::addressof(resource_handle), resource_limit));
*result = resource_handle;
R_SUCCEED();
}
case InfoType::RandomEntropy:
R_UNLESS(handle == 0, ResultInvalidHandle);
R_UNLESS(info_sub_id < 4, ResultInvalidCombination);
*result = GetCurrentProcess(system.Kernel()).GetRandomEntropy(info_sub_id);
R_SUCCEED();
case InfoType::InitialProcessIdRange: {
LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query privileged process id bounds, returned 0/64");
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
switch (InitialProcessIdRangeInfo(info_sub_id)) {
case InitialProcessIdRangeInfo::Minimum:
*result = 0; //todo
R_SUCCEED();
case InitialProcessIdRangeInfo::Maximum:
*result = 64; //todo
R_SUCCEED();
default:
R_THROW(ResultInvalidCombination);
}
}
case InfoType::InitialProcessIdRange:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
R_SUCCEED();
case InfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4;
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, info_sub_id);
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
info_sub_id);
R_THROW(ResultInvalidCombination);
}
@@ -175,7 +206,8 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
.GetHandleTable()
.GetObject<KThread>(system.Kernel(), Handle(handle));
if (thread.IsNull()) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle={:#08x}", Handle(handle));
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle={:#08x}",
static_cast<Handle>(handle));
R_THROW(ResultInvalidHandle);
}
@@ -188,6 +220,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
u64 out_ticks = 0;
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
const u64 thread_ticks = current_thread->GetCpuTime();
out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
@@ -197,40 +230,19 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED();
}
case InfoType::IdleTickCount: {
// Verify the requested core is valid.
const bool core_valid =
(info_sub_id == 0xFFFFFFFFFFFFFFFF)
|| (info_sub_id == u64(system.Kernel().CurrentPhysicalCoreIndex()));
R_UNLESS(core_valid, ResultInvalidCombination);
// Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
// Verify the requested core is valid.
const bool core_valid =
(info_sub_id == 0xFFFFFFFFFFFFFFFF) ||
(info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
R_UNLESS(core_valid, ResultInvalidCombination);
// Get the idle tick count.
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
R_SUCCEED();
}
case InfoType::MesosphereMeta: {
enum MesosphereMetaInfo : u64 {
KernelVersion = 0,
IsKTraceEnabled = 1,
IsSingleStepEnabled = 2,
};
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
switch (MesosphereMetaInfo(info_sub_id)) {
case MesosphereMetaInfo::KernelVersion:
*result = Kernel::Svc::SupportedKernelVersion;
R_SUCCEED();
case MesosphereMetaInfo::IsKTraceEnabled:
*result = 0;
R_SUCCEED();
case MesosphereMetaInfo::IsSingleStepEnabled:
*result = 0;
R_SUCCEED();
default:
R_THROW(ResultInvalidCombination);
}
}
case InfoType::MesosphereCurrentProcess: {
// Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
@@ -243,11 +255,13 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
KHandleTable& handle_table = current_process->GetHandleTable();
// Get a new handle for the current process.
Handle tmp{};
Handle tmp;
R_TRY(handle_table.Add(system.Kernel(), std::addressof(tmp), current_process));
// Set the output.
*result = tmp;
// We succeeded.
R_SUCCEED();
}
default:
-1
View File
@@ -1387,7 +1387,6 @@ public:
{5, &ACC_U1::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
{51, &ACC_U1::TrySelectUserWithoutInteractionDeprecated, "TrySelectUserWithoutInteractionDeprecated"},
{51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
{99, nullptr, "DebugActivateOpenContextRetention"},
-1
View File
@@ -154,7 +154,6 @@ enum class AppletMessage : u32 {
DetectLongPressingCaptureButton = 91,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93,
StartupLogoDisappeared = 95,
};
enum class LibraryAppletMode : u32 {
-1
View File
@@ -91,7 +91,6 @@ struct Applet {
// Common state
bool sleep_lock_enabled{};
bool vr_mode_enabled{};
bool vr_mode_enabled_3d{};
bool lcd_backlight_off_enabled{};
APM::CpuBoostMode boost_mode{};
bool request_exit_to_library_applet_at_execute_next_program_enabled{};
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -73,7 +73,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
Result IAllSystemAppletProxiesService::OpenOverlayAppletProxy(
Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle) {
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
LOG_WARNING(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
@@ -88,7 +89,8 @@ Result IAllSystemAppletProxiesService::OpenOverlayAppletProxy(
Result IAllSystemAppletProxiesService::OpenSystemApplicationProxy(
Out<SharedPointer<IApplicationProxy>> out_system_application_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle) {
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -36,13 +36,15 @@ private:
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result OpenOverlayAppletProxy(Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy,
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result OpenLibraryAppletProxyOld(
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle);
Result OpenSystemApplicationProxy(
Out<SharedPointer<IApplicationProxy>> out_system_application_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle);
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result GetSystemProcessCommonFunctions();
Result GetAppletAlternativeFunctions();
@@ -39,7 +39,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{14, nullptr, "GetWakeupCount"}, //11.0.0+
{15, nullptr, "Unknown15"}, //19.0.0+
{20, D<&ICommonStateGetter::PushToGeneralChannel>, "PushToGeneralChannel"},
{30, D<&ICommonStateGetter::GetHomeButtonReaderLockAccessor>, "GetHomeButtonReaderLockAccessor"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"}, //2.0.0+
{32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"}, //7.0.0+
{40, nullptr, "GetCradleFwVersion"}, //2.0.0+
@@ -65,7 +65,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{100, D<&ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{110, nullptr, "OpenMyGpuErrorHandler"},
{120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory"}, //13.0.0+
{130, D<&ICommonStateGetter::EnableStartupLogoDisappearedMessage>, "EnableStartupLogoDisappearedMessage"}, //21.0.0+
{130, nullptr, "Unknown130"}, //21.0.0+
{200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"},
{300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"},
@@ -74,17 +74,14 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{501, nullptr, "SuppressDisablingSleepTemporarily"},
{502, nullptr, "IsSleepEnabled"},
{503, nullptr, "IsDisablingSleepSuppressed"},
{600, nullptr, "SetHidInputMagnificationForApplication"}, //20.0.0+
{600, nullptr, "Unknown600"}, //20.0.0+
{610, D<&ICommonStateGetter::Unknown610>, "Unknown610"}, //21.0.0+
{611, D<&ICommonStateGetter::Unknown611>, "Unknown611"}, //22.0.0+
{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, //11.0.0+
{910, nullptr, "GetLaunchRequiredTick"}, //17.0.0+
{1000, D<&ICommonStateGetter::BeginVrMode3d>, "BeginVrMode3d"}, //19.0.0+
{1001, D<&ICommonStateGetter::EndVrMode3d>, "EndVrMode3d"}, //19.0.0+
{1002, D<&ICommonStateGetter::IsVrModeEnabled3d>, "IsVrModeEnabled3d"}, //19.0.0+
{1003, D<&ICommonStateGetter::GetVrLaboGoggleViewport>, "GetVrLaboGoggleViewport"}, //21.0.0+
{1004, D<&ICommonStateGetter::GetPanelPhysicalSizeForSpecificTitle>, "GetPanelPhysicalSizeForSpecificTitle"}, //21.0.0+
{1005, D<&ICommonStateGetter::GetPanelResolutionForSpecificTitle>, "GetPanelResolutionForSpecificTitle"}, //21.0.0+
{1000, nullptr, "BeginVrMode3d"}, //19.0.0+
{1001, nullptr, "EndVrMode3d"}, //19.0.0+
{1002, nullptr, "IsVrModeEnabled3d"}, //19.0.0+
};
// clang-format on
@@ -314,12 +311,6 @@ Result ICommonStateGetter::PerformSystemButtonPressingIfInFocus(SystemButtonType
R_SUCCEED();
}
Result ICommonStateGetter::EnableStartupLogoDisappearedMessage() {
LOG_WARNING(Service_AM, "(STUBBED) called");
m_applet->lifecycle_manager.PushUnorderedMessage(system.Kernel(), AppletMessage::StartupLogoDisappeared);
R_SUCCEED();
}
Result ICommonStateGetter::GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_operation_mode_system_info = 0;
@@ -364,12 +355,6 @@ Result ICommonStateGetter::PushToGeneralChannel(SharedPointer<IStorage> storage)
R_SUCCEED();
}
Result ICommonStateGetter::GetHomeButtonReaderLockAccessor(Out<SharedPointer<ILockAccessor>> out_lock_accessor) {
LOG_DEBUG(Service_AM, "called");
*out_lock_accessor = std::make_shared<ILockAccessor>(system);
R_SUCCEED();
}
Result ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled(bool enabled) {
LOG_DEBUG(Service_AM, "called, enabled={} applet_id={}", enabled, m_applet->applet_id);
@@ -378,58 +363,14 @@ Result ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled(bool enabled
R_SUCCEED();
}
Result ICommonStateGetter::Unknown610(u64 unk) {
Result ICommonStateGetter::Unknown610() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ICommonStateGetter::Unknown611(u8 unk) {
Result ICommonStateGetter::Unknown611() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ICommonStateGetter::BeginVrMode3d() {
std::scoped_lock lk{m_applet->lock};
m_applet->vr_mode_enabled_3d = true;
LOG_WARNING(Service_AM, "VR Mode is {}", m_applet->vr_mode_enabled_3d ? "on" : "off");
R_SUCCEED();
}
Result ICommonStateGetter::EndVrMode3d() {
std::scoped_lock lk{m_applet->lock};
m_applet->vr_mode_enabled_3d = false;
LOG_WARNING(Service_AM, "VR Mode is {}", m_applet->vr_mode_enabled_3d ? "on" : "off");
R_SUCCEED();
}
Result ICommonStateGetter::IsVrModeEnabled3d(Out<bool> out_is_vr_mode_enabled_3d) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
*out_is_vr_mode_enabled_3d = m_applet->vr_mode_enabled_3d;
R_SUCCEED();
}
Result ICommonStateGetter::GetVrLaboGoggleViewport(Out<s32> out_x, Out<s32> out_y, Out<s32> out_width, Out<s32> out_height) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_x = 0;
*out_y = 0;
*out_width = 1280;
*out_height = 720;
R_SUCCEED();
}
Result ICommonStateGetter::GetPanelPhysicalSizeForSpecificTitle(Out<f32> out_width, Out<f32> out_height) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_width = 137250.0f / 1000.0f;
*out_height = 77200.0f / 1000.0f;
R_SUCCEED();
}
Result ICommonStateGetter::GetPanelResolutionForSpecificTitle(Out<s32> out_width, Out<s32> out_height) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_width = 1280;
*out_height = 720;
R_SUCCEED();
}
} // namespace Service::AM
@@ -56,23 +56,15 @@ private:
Result GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height);
Result GetBuiltInDisplayType(Out<s32> out_display_type);
Result PerformSystemButtonPressingIfInFocus(SystemButtonType type);
Result EnableStartupLogoDisappearedMessage();
Result GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info);
Result GetAppletLaunchedHistory(Out<s32> out_count,
OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
Result GetSettingsPlatformRegion(Out<Set::PlatformRegion> out_settings_platform_region);
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
Result PushToGeneralChannel(SharedPointer<IStorage> storage); // cmd 20
Result GetHomeButtonReaderLockAccessor(Out<SharedPointer<ILockAccessor>> out_lock_accessor);
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
Result Unknown610(u64 unk);
Result Unknown611(u8 unk);
Result BeginVrMode3d();
Result EndVrMode3d();
Result IsVrModeEnabled3d(Out<bool> out_is_vr_mode_enabled_3d);
Result GetVrLaboGoggleViewport(Out<s32> out_x, Out<s32> out_y, Out<s32> out_width, Out<s32> out_height);
Result GetPanelPhysicalSizeForSpecificTitle(Out<f32> out_width, Out<f32> out_height);
Result GetPanelResolutionForSpecificTitle(Out<s32> out_width, Out<s32> out_height);
Result Unknown610();
Result Unknown611();
void SetCpuBoostMode(HLERequestContext& ctx);
+7 -25
View File
@@ -32,6 +32,7 @@ public:
RegisterHandlers(functions);
}
~I2CSession() override = default;
Result Send(InBuffer<BufferAttr_HipcMapAlias> in_data, u32 transaction_option) {
LOG_WARNING(Service, "(stubbed) topt={}", transaction_option);
R_THROW(ResultUnknown);
@@ -49,40 +50,21 @@ public:
: ServiceFramework{system_, "i2c"}
{
static const FunctionInfo functions[] = {
{0, C<&I2C::OpenSessionForDev>, "OpenSessionForDev"},
{0, nullptr, "OpenSessionForDev"},
{1, C<&I2C::OpenSession>, "OpenSession"},
{2, C<&I2C::HasDevice>, "HasDevice"},
{3, C<&I2C::HasDeviceForDev>, "HasDeviceForDev"},
{4, C<&I2C::OpenSession2>, "OpenSession2"},
{2, nullptr, "HasDevice"},
{3, nullptr, "HasDeviceForDev"},
{4, nullptr, "OpenSession2"},
};
RegisterHandlers(functions);
}
~I2C() override = default;
Result OpenSessionForDev(OutInterface<I2CSession> out_session, s32 bus_idx, u32 slave_address, u32 addressing_mode, u32 speed_mode) {
Result OpenSession(I2CDevice device, OutInterface<I2CSession> out_session) {
LOG_DEBUG(Service, "(stubbed)");
*out_session = std::make_shared<I2CSession>(system);
R_SUCCEED();
}
Result OpenSession(OutInterface<I2CSession> out_session, I2CDevice device) {
LOG_DEBUG(Service, "(stubbed)");
*out_session = std::make_shared<I2CSession>(system);
R_SUCCEED();
}
Result HasDevice(Out<bool> out_has_device, I2CDevice device) {
LOG_DEBUG(Service, "(stubbed)");
*out_has_device = false;
R_SUCCEED();
}
Result HasDeviceForDev(Out<bool> out_has_device, I2CDevice device) {
LOG_DEBUG(Service, "(stubbed)");
*out_has_device = false;
R_SUCCEED();
}
Result OpenSession2(OutInterface<I2CSession> out_session, u32 device_code) {
LOG_DEBUG(Service, "(stubbed) device_code={}", device_code);
*out_session = std::make_shared<I2CSession>(system);
R_SUCCEED();
}
};
void LoopProcess(Core::System& system) {
@@ -13,7 +13,6 @@
#include "core/hle/service/vi/manager_display_service.h"
#include "core/hle/service/vi/system_display_service.h"
#include "core/hle/service/vi/vi_results.h"
#include "service_creator.h"
namespace Service::VI {
@@ -39,7 +38,6 @@ IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
{2031, C<&IApplicationDisplayService::DestroyStrayLayer>, "DestroyStrayLayer"},
{2101, C<&IApplicationDisplayService::SetLayerScalingMode>, "SetLayerScalingMode"},
{2102, C<&IApplicationDisplayService::ConvertScalingMode>, "ConvertScalingMode"},
{2103, C<&IApplicationDisplayService::Cmd2103>, "Cmd2103"},
{2450, C<&IApplicationDisplayService::GetIndirectLayerImageMap>, "GetIndirectLayerImageMap"},
{2451, nullptr, "GetIndirectLayerImageCropMap"},
{2460, C<&IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo>, "GetIndirectLayerImageRequiredMemoryInfo"},
@@ -291,11 +289,6 @@ Result IApplicationDisplayService::ConvertScalingMode(Out<ConvertedScaleMode> ou
}
}
Result IApplicationDisplayService::Cmd2103(Out<std::array<u8, 0x18>> out_unk18) {
LOG_WARNING(Service_VI, "(stubbed)");
R_SUCCEED();
}
Result IApplicationDisplayService::GetIndirectLayerImageMap(
Out<u64> out_size, Out<u64> out_stride,
OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
@@ -64,7 +64,6 @@ public:
Result GetDisplayVsyncEvent(OutCopyHandle<Kernel::KReadableEvent> out_vsync_event,
u64 display_id);
Result ConvertScalingMode(Out<ConvertedScaleMode> out_scaling_mode, NintendoScaleMode mode);
Result Cmd2103(Out<std::array<u8, 0x18>> out_unk18);
Result GetIndirectLayerImageMap(
Out<u64> out_size, Out<u64> out_stride,
OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
+1
View File
@@ -191,6 +191,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include <windows.h>
#ifdef _MSC_VER
#pragma comment(lib, "Dwmapi.lib")
#pragma comment(lib, "winmm.lib")
#endif
static inline void ApplyWindowsTitleBarDarkMode(HWND hwnd, bool enabled) {