Compare commits

..

4 Commits

Author SHA1 Message Date
lizzie 8cd2940669 better logic 2026-09-01 10:18:43 +00:00
lizzie 21ca1564fd crossed page boundary now marked proper 2026-09-01 10:17:15 +00:00
lizzie e6e1bd374b unused var 2026-09-01 10:17:15 +00:00
lizzie d049d5cd66 [nce] invalidate split pages
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-01 10:17:15 +00:00
30 changed files with 633 additions and 303 deletions
-3
View File
@@ -63,6 +63,3 @@ artifacts
/install*
vulkansdk*.exe
*.tar.zst
# Build-time generated external sources
externals/generated
+3 -3
View File
@@ -214,6 +214,8 @@ if(MSVC)
endif()
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
set(EXT_DEFAULT OFF)
@@ -221,8 +223,6 @@ if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
endif()
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" ${EXT_DEFAULT})
# ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
@@ -238,7 +238,7 @@ option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
# FreeBSD 15+ has libusb, versions below should disable it
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
+2 -2
View File
@@ -22,9 +22,9 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc.
- For details on why, see the [detailed AI policy](docs/policies/AI.md).
- Usage of any form of profanity or otherwise unsavory language is prohibited.
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
- This is primarily because it rarely helps to actually understand what's going on.
- Remember that your comments should be focused and actually address what's happening.
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases.
- Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this.
- You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem.
+6
View File
@@ -186,6 +186,12 @@
"repo": "eden-emulator/oaknut",
"version": "v2.0.3"
},
"oboe": {
"bundled": true,
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
"repo": "google/oboe",
"version": "1.10.0"
},
"openssl": {
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
"min_version": "3.0.0",
+2 -2
View File
@@ -239,6 +239,6 @@ find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
## RedoxOS
Package installs randomly hang at times, you may need to restart it about 3-5 times to complete. Always do `sudo pkg update` or it will hang. Try installing each package individually.
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
When CMake invokes certain file syscalls - most of the time it causes crashes, and corruptions on the address space. Reboot if there's a freeze over 5 minutes.
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
+4 -4
View File
@@ -38,7 +38,7 @@ Pull requests are only to be merged by core developers when properly tested and
- The level of namespacing is generally left to the committer's choice.
- However, we never recommend going more than two levels *except* in `hle`, in which case you may go as many as four levels depending on the specificity of your changes.
- Occasionally, up to two additional namespaces may be provided for more clarity.
- Ocassionally, up to two additional namespaces may be provided for more clarity.
- Changes that affect the entire project (sans CMake changes) should be namespaced as `meta`.
- Maintainers are permitted to change namespaces at will.
- Commits within PRs are not required to be namespaced, but it is highly recommended.
@@ -51,8 +51,8 @@ When adding new settings, use `tr("Setting:")` if the setting is meant to be a f
- Debug settings must never be turned on by default.
- Provide reasonable bounds (for example, a setting controlling the amount of VRAM should never be 0).
- The description of the setting must be short and concise, if the setting "does a lot of things" consider splitting the setting into multiple if possible.
- Try to avoid excessive/redundant explanations "recommended for most users and games" can just be "(recommended)".
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behavior that result in different metrics across different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
- Try to avoid excessive/redundant explainations "recommended for most users and games" can just be "(recommended)".
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behaviour that result in different metrics accross different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
Some examples:
@@ -91,7 +91,7 @@ You may additionally need the `Qt Extension Pack` extension if building Qt.
# Build speedup
If you have an HDD, use ramdisk (build in RAM); you need about 4GB for a `RelWithDebInfo` build:
If you have an HDD, use ramdisk (build in RAM), approximately you need 4GB for a full build with debug symbols:
```sh
mkdir /tmp/ramdisk
+1 -1
View File
@@ -76,7 +76,7 @@ The following options are desktop only.
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
- Unavailable on Windows/ARM64 and on Android
- Unavailable on Windows/ARM64
- You probably shouldn't turn this off.
### Qt
+2 -2
View File
@@ -3,9 +3,9 @@
> [!WARNING]
> This guide is intended for developers ONLY. If you're looking for configuring the emulator itself, read **[the user handbook](./user/README.md)**.
Settings have their own dedicated subsystem. Toggles can be added to gate features and fixes, as not all of them apply to every game.
Settings on the emulator are very important, toggles and such can be used to guard and/or add branches to paths where some games may crash while others won't, and viceversa.
However, this process can be tedious for those unfamiliar; this document serves as an outline for the settings subsystem.
However, this process can be tedious for those unfamiliar; this document serves as an outline/documentation for the settings subsystem.
## Index
+5 -5
View File
@@ -12,7 +12,7 @@ AMD64, aka x86_64, is the most tested and supported architecture for desktop tar
### Caveats
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow.
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow!
Computers on Linux will almost always run Eden strictly better than an equivalent machine on Windows. This is largely due to the way the Linux kernel handles memory management (and the lack of Microsoft spyware).
@@ -24,7 +24,7 @@ ARM64, aka aarch64, is the only supported architecture for Android, with limited
### Caveats
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it -- submit patches). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it--submit patches!). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
When NCE is enabled, do note that the GPU will almost always be the limiting factor. This is especially the case for Android, as well as desktops that lack dedicated GPUs; Adreno, Mali, PowerVR, etc. GPUs are generally significantly weaker relative to their respective CPUs.
@@ -44,7 +44,7 @@ Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution t
## Other
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it -- submit patches.
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it -- submit patches!
IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not run on IA-64 (assuming you can even find a supported Windows/Linux distribution)
@@ -106,14 +106,14 @@ Qualcomm Snapdragon SoCs are generally the most well supported.
* A good base to compare to is the Snapdragon 865--e.g. [Tensor vs SD865](https://archive.is/M1P58)
* Some benchmarks may be misleading due to thermal throttling OR RAM requirements.
- For example, a Pixel 6a (Tensor G1) performs about 1/3 as well as an 865 due to its lack of RAM and poor thermals.
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM.
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM!
- If you're not sure what SoC you have, check [GSMArena](https://www.gsmarena.com) - e.g. [Pixel 9 Pro](https://archive.ph/91VhA)
Custom ROMs are recommended, *as long as* you know what you're doing.
- For most devices, [LineageOS](https://lineageos.org/) is preferred.
- [CalyxOS](https://calyxos.org/) is available as well.
- For Google Pixel devices ONLY... and [soon another OEM](https://archive.ph/cPpMd)... [GrapheneOS](https://grapheneos.org/) is highly recommended.
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future.
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future!
* Keep checking the [FAQ page](https://grapheneos.org/faq#supported-devices) for news.
- Custom ROMs will likely be exclusively recommended in the future due to Google's upcoming [draconian](https://archive.is/hGIjZ), [anti-privacy, anti-user](https://archive.is/mc1CJ) verification requirements.
+43 -37
View File
@@ -136,50 +136,49 @@ if(ENABLE_CUBEB)
endif()
endif()
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
if (NOT ANDROID)
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
set(HIDAPI ON)
endif()
set(HIDAPI ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
AddJsonPackage(sdl3)
else()
message(STATUS "Using bundled SDL3")
AddJsonPackage(sdl3-ci)
# copy sdl java sources for consumption by Gradle
if (ANDROID)
file(COPY ${SDL3_SOURCE_DIR}/java DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/generated/sdl)
endif()
endif()
# Normalize SDL3 link target across package variants.
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
if (NOT TARGET SDL3::SDL3)
if (TARGET SDL3::SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
elseif (TARGET SDL3::SDL3-static)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
AddJsonPackage(sdl3)
else()
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
message(STATUS "Using bundled SDL3")
AddJsonPackage(sdl3-ci)
endif()
# Normalize SDL3 link target across package variants.
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
if (NOT TARGET SDL3::SDL3)
if (TARGET SDL3::SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
elseif (TARGET SDL3::SDL3-static)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
else()
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
endif()
endif()
endif()
set(BUILD_SHARED_LIBS OFF)
# SPIRV Headers
AddJsonPackage(spirv-headers)
@@ -386,6 +385,13 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
endif()
endif()
# oboe
if (ANDROID)
AddJsonPackage(oboe)
add_library(oboe::oboe ALIAS oboe)
endif()
if (APPLE)
# moltenvk
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
-7
View File
@@ -272,13 +272,6 @@ android {
resValue("string", "app_name_suffixed", "$currentName$suffix")
resValue("string", "app_name", "Eden$suffix")
}
sourceSets {
named("main") {
java.srcDir("${edenDir}/externals/generated/sdl/java")
kotlin.srcDir("${edenDir}/externals/generated/sdl/java")
}
}
}
idea {
-3
View File
@@ -9,9 +9,6 @@
-keep class org.ini4j.spi.IniBuilder
-keep class org.ini4j.spi.IniFormatter
-keep class org.libsdl.app.** { *; }
-keepclassmembers class org.libsdl.app.** { *; }
# Suppress warnings for R8
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
@@ -16,7 +16,6 @@ import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.libsdl.app.SDL
import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
@@ -53,8 +52,6 @@ object NativeLibrary {
init {
try {
System.loadLibrary("yuzu-android")
SDL.setupJNI()
initJvm()
} catch (ex: UnsatisfiedLinkError) {
error("[NativeLibrary] $ex")
}
@@ -370,7 +367,6 @@ object NativeLibrary {
NetPlayManager.clearChat()
}
external fun initJvm()
external fun initMultiplayer()
@Keep
+1 -1
View File
@@ -22,7 +22,7 @@ add_library(yuzu-android SHARED
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common video_core)
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log GLESv2)
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
if (ARCHITECTURE_arm64)
target_link_libraries(yuzu-android PRIVATE adrenotools)
endif()
-9
View File
@@ -1730,15 +1730,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_loadAmiibo(JNIEnv* env, jobject jobj,
return static_cast<jint>(info);
}
extern "C" JNIEXPORT void JNICALL
Java_org_yuzu_yuzu_1emu_NativeLibrary_initJvm(JNIEnv *env, jclass clazz) {
JavaVM *vm;
if (env->GetJavaVM(&vm) != JNI_OK)
return;
Common::Android::Initialize(vm, env);
}
JNIEXPORT void JNICALL
Java_org_yuzu_yuzu_1emu_NativeLibrary_initMultiplayer(
JNIEnv* env, [[maybe_unused]] jobject obj) {
@@ -800,6 +800,7 @@
<string name="theme_mode_dark">تاریک</string>
<!-- Audio output engines -->
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
@@ -465,13 +465,13 @@
<string-array name="outputEngineEntries">
<item>@string/auto</item>
<item>@string/sdl3</item>
<item>@string/oboe</item>
<item>@string/cubeb</item>
<item>@string/string_null</item>
</string-array>
<integer-array name="outputEngineValues">
<item>0</item>
<item>2</item>
<item>4</item>
<item>1</item>
<item>3</item>
</integer-array>
@@ -1240,7 +1240,7 @@
<string name="theme_mode_dark">Dark</string>
<!-- Audio output engines -->
<string name="sdl3" translatable="false">SDL3</string>
<string name="oboe" translatable="false">oboe</string>
<string name="cubeb" translatable="false">cubeb</string>
<!-- Anisotropic filtering options -->
+14 -5
View File
@@ -238,11 +238,20 @@ if (ENABLE_CUBEB)
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
endif()
target_sources(audio_core PRIVATE
sink/sdl3_sink.cpp
sink/sdl3_sink.h)
if(ANDROID)
target_sources(audio_core PRIVATE
sink/oboe_sink.cpp
sink/oboe_sink.h)
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
target_link_libraries(audio_core PRIVATE oboe)
target_compile_definitions(audio_core PUBLIC HAVE_OBOE)
else()
target_sources(audio_core PRIVATE
sink/sdl3_sink.cpp
sink/sdl3_sink.h)
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
endif()
create_target_directory_groups(audio_core)
+230
View File
@@ -0,0 +1,230 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <span>
#include <vector>
#include <oboe/Oboe.h>
#include "audio_core/common/common.h"
#include "audio_core/sink/oboe_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging.h"
#include "common/scope_exit.h"
#include "core/core.h"
namespace AudioCore::Sink {
class OboeSinkStream final : public SinkStream,
public oboe::AudioStreamDataCallback,
public oboe::AudioStreamErrorCallback {
public:
explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
u32 system_channels_)
: SinkStream(system_, type_) {
name = name_;
system_channels = system_channels_;
this->OpenStream();
}
~OboeSinkStream() override {
LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
}
void Finalize() override {
this->Stop();
m_stream.reset();
}
void Start(bool resume = false) override {
if (!m_stream || !paused) {
return;
}
paused = false;
if (m_stream->start() != oboe::Result::OK) {
LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
}
}
void Stop() override {
if (!m_stream || paused) {
return;
}
this->SignalPause();
if (m_stream->stop() != oboe::Result::OK) {
LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
}
}
public:
static s32 QueryChannelCount(oboe::Direction direction) {
std::shared_ptr<oboe::AudioStream> temp_stream;
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
if (result == oboe::Result::OK) {
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
}
LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
direction == oboe::Direction::Output ? "output" : "input");
return 2;
}
protected:
oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
s32 num_buffer_frames) override {
const size_t num_channels = this->GetDeviceChannels();
const size_t frame_size = num_channels;
const size_t num_frames = static_cast<size_t>(num_buffer_frames);
if (type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
num_frames * frame_size};
this->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
num_frames * frame_size};
this->ProcessAudioOutAndRender(output_buffer, num_frames);
}
return oboe::DataCallbackResult::Continue;
}
void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
if (this->OpenStream()) {
m_stream->start();
}
}
private:
static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
oboe::Direction direction) {
// TODO: investigate callback delay issues when using AAudio
return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
->setAudioApi(oboe::AudioApi::OpenSLES)
->setDirection(direction)
->setSampleRate(TargetSampleRate)
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
->setFormat(oboe::AudioFormat::I16)
->setFormatConversionAllowed(true)
->setUsage(oboe::Usage::Game)
->setBufferCapacityInFrames(TargetSampleCount * 2);
}
bool OpenStream() {
const auto direction = [&]() {
switch (type) {
case StreamType::In:
return oboe::Direction::Input;
case StreamType::Out:
case StreamType::Render:
return oboe::Direction::Output;
default:
ASSERT(false);
return oboe::Direction::Output;
}
}();
const auto expected_channels = QueryChannelCount(direction);
const auto expected_mask = [&]() {
switch (expected_channels) {
case 1:
return oboe::ChannelMask::Mono;
case 2:
return oboe::ChannelMask::Stereo;
case 6:
return oboe::ChannelMask::CM5Point1;
default:
ASSERT(false);
return oboe::ChannelMask::Unspecified;
}
}();
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)
->setChannelCount(expected_channels)
->setChannelMask(expected_mask)
->setChannelConversionAllowed(true)
->setDataCallback(this)
->setErrorCallback(this)
->openStream(m_stream);
ASSERT(result == oboe::Result::OK);
return result == oboe::Result::OK && this->SetStreamProperties();
}
bool SetStreamProperties() {
ASSERT(m_stream);
m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
device_channels = m_stream->getChannelCount();
const auto sample_rate = m_stream->getSampleRate();
const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
const auto stream_backend =
m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
stream_backend, device_channels, sample_rate, buffer_capacity);
return true;
}
std::shared_ptr<oboe::AudioStream> m_stream{};
};
OboeSink::OboeSink() {
// TODO: This is not generally knowable
// The channel count is distinct based on direction and can change
device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
}
OboeSink::~OboeSink() = default;
SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) {
SinkStreamPtr& stream = sink_streams.emplace_back(
std::make_unique<OboeSinkStream>(system, type, name, system_channels));
return stream.get();
}
void OboeSink::CloseStream(SinkStream* to_remove) {
sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
}
void OboeSink::CloseStreams() {
sink_streams.clear();
}
f32 OboeSink::GetDeviceVolume() const {
if (sink_streams.empty()) {
return 1.0f;
}
return sink_streams.front()->GetDeviceVolume();
}
void OboeSink::SetDeviceVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetDeviceVolume(volume);
}
}
void OboeSink::SetSystemVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetSystemVolume(volume);
}
}
} // namespace AudioCore::Sink
+75
View File
@@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include <string>
#include "audio_core/sink/sink.h"
namespace Core {
class System;
}
namespace AudioCore::Sink {
class SinkStream;
class OboeSink final : public Sink {
public:
explicit OboeSink();
~OboeSink() 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:
/// List of streams managed by this sink
std::list<SinkStreamPtr> sink_streams{};
};
} // namespace AudioCore::Sink
+19
View File
@@ -10,6 +10,9 @@
#include <vector>
#include "audio_core/sink/sink_details.h"
#ifdef HAVE_OBOE
#include "audio_core/sink/oboe_sink.h"
#endif
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
@@ -40,8 +43,24 @@ struct SinkDetails {
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
};
// NOTE TO PROBABLY FIX LATER FOR ANDROID - the return value "0u" for the first HAVE_OBOE
// section below was just copied from the null section so there's a somewhat valid value
// being returned, since the previous "true" value probably isn't compatible with the
// previous EA-3833 code. (HAVE_OBOE was introduced in a later release.) Eventually need
// to change "0u" for something else directly from the oboe_sink.cpp functions.
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef HAVE_OBOE
SinkDetails{
Settings::AudioEngine::Oboe,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<OboeSink>();
},
[](bool capture) { return std::vector<std::string>{"Default"}; },
[]() { return 0u; },
},
#endif
#ifdef HAVE_CUBEB
SinkDetails{
Settings::AudioEngine::Cubeb,
+4 -4
View File
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "android_common.h"
@@ -51,7 +51,7 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
}
double GetJDouble(JNIEnv* env, jobject jdouble) {
return env->CallDoubleMethod(jdouble, GetDoubleValueMethod());
return env->GetDoubleField(jdouble, GetDoubleValueField());
}
jobject ToJDouble(JNIEnv* env, double value) {
@@ -59,7 +59,7 @@ jobject ToJDouble(JNIEnv* env, double value) {
}
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
return env->CallIntMethod(jinteger, GetIntegerValueMethod());
return env->GetIntField(jinteger, GetIntegerValueField());
}
jobject ToJInteger(JNIEnv* env, s32 value) {
@@ -67,7 +67,7 @@ jobject ToJInteger(JNIEnv* env, s32 value) {
}
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
return env->CallBooleanMethod(jboolean, GetBooleanValueMethod());
return env->GetBooleanField(jboolean, GetBooleanValueField());
}
jobject ToJBoolean(JNIEnv* env, bool value) {
+192 -188
View File
@@ -63,15 +63,15 @@ static jfieldID s_patch_title_id_field;
static jclass s_double_class;
static jmethodID s_double_constructor;
static jmethodID s_double_value_method;
static jfieldID s_double_value_field;
static jclass s_integer_class;
static jmethodID s_integer_constructor;
static jmethodID s_integer_value_method;
static jfieldID s_integer_value_field;
static jclass s_boolean_class;
static jmethodID s_boolean_constructor;
static jmethodID s_boolean_value_method;
static jfieldID s_boolean_value_field;
static jclass s_player_input_class;
static jmethodID s_player_input_constructor;
@@ -103,6 +103,7 @@ static jmethodID s_clear_chat;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace Common::Android {
JNIEnv *GetEnvForThread() {
thread_local static struct OwnedEnv {
OwnedEnv() {
@@ -298,8 +299,8 @@ namespace Common::Android {
return s_double_constructor;
}
jmethodID GetDoubleValueMethod() {
return s_double_value_method;
jfieldID GetDoubleValueField() {
return s_double_value_field;
}
jclass GetIntegerClass() {
@@ -310,8 +311,8 @@ namespace Common::Android {
return s_integer_constructor;
}
jmethodID GetIntegerValueMethod() {
return s_integer_value_method;
jfieldID GetIntegerValueField() {
return s_integer_value_field;
}
jclass GetBooleanClass() {
@@ -322,8 +323,8 @@ namespace Common::Android {
return s_boolean_constructor;
}
jmethodID GetBooleanValueMethod() {
return s_boolean_value_method;
jfieldID GetBooleanValueField() {
return s_boolean_value_field;
}
jclass GetPlayerInputClass() {
@@ -428,6 +429,188 @@ namespace Common::Android {
jint InitFFmpegOnLoad(JavaVM *vm);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
s_java_vm = vm;
InitFFmpegOnLoad(vm);
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
return JNI_ERR;
// Initialize Java classes
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
"(Ljava/lang/String;Z)V");
env->DeleteLocalRef(game_dir_class);
// Initialize methods
s_exit_emulation_activity =
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
s_disk_cache_load_progress =
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
"(Ljava/lang/String;Ljava/lang/String;)Z");
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
"(Ljava/lang/String;)Z");
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
"(Ljava/lang/String;)Ljava/lang/String;");
s_on_emulation_started =
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
s_on_emulation_stopped =
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
s_on_program_changed =
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
s_game_constructor = env->GetMethodID(game_class, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
env->DeleteLocalRef(game_class);
const jclass string_class = env->FindClass("java/lang/String");
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
env->DeleteLocalRef(string_class);
const jclass pair_class = env->FindClass("kotlin/Pair");
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
s_pair_constructor =
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
env->DeleteLocalRef(pair_class);
const jclass overlay_control_data_class =
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
s_overlay_control_data_class =
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
s_overlay_control_data_constructor =
env->GetMethodID(overlay_control_data_class, "<init>",
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
s_overlay_control_data_id_field =
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
s_overlay_control_data_enabled_field =
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
s_overlay_control_data_landscape_position_field =
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
s_overlay_control_data_portrait_position_field =
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
s_overlay_control_data_foldable_position_field =
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
s_overlay_control_data_individual_scale_field =
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
env->DeleteLocalRef(overlay_control_data_class);
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
s_patch_constructor = env->GetMethodID(
patch_class, "<init>",
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
env->DeleteLocalRef(patch_class);
const jclass double_class = env->FindClass("java/lang/Double");
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
s_double_value_field = env->GetFieldID(double_class, "value", "D");
env->DeleteLocalRef(double_class);
const jclass int_class = env->FindClass("java/lang/Integer");
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
s_integer_value_field = env->GetFieldID(int_class, "value", "I");
env->DeleteLocalRef(int_class);
const jclass boolean_class = env->FindClass("java/lang/Boolean");
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z");
env->DeleteLocalRef(boolean_class);
const jclass player_input_class =
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
s_player_input_constructor = env->GetMethodID(
player_input_class, "<init>",
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
s_player_input_buttons_field =
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
s_player_input_analogs_field =
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
s_player_input_motions_field =
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
s_player_input_vibration_enabled_field =
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
s_player_input_vibration_strength_field =
env->GetFieldID(player_input_class, "vibrationStrength", "I");
s_player_input_body_color_left_field =
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
s_player_input_body_color_right_field =
env->GetFieldID(player_input_class, "bodyColorRight", "J");
s_player_input_button_color_left_field =
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
s_player_input_button_color_right_field =
env->GetFieldID(player_input_class, "buttonColorRight", "J");
s_player_input_profile_name_field =
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
s_player_input_use_system_vibrator_field =
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
env->DeleteLocalRef(player_input_class);
const jclass yuzu_input_device_interface =
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
s_yuzu_input_device_interface =
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
s_yuzu_input_device_get_name =
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
s_yuzu_input_device_get_guid =
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
"()I");
s_yuzu_input_device_get_supports_vibration =
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
"(F)V");
s_yuzu_input_device_get_axes =
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
s_yuzu_input_device_has_keys =
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
env->DeleteLocalRef(yuzu_input_device_interface);
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
"(ILjava/lang/String;)V");
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
// Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
// Initialize applets
Common::Android::SoftwareKeyboard::InitJNI(env);
Common::Android::WebBrowser::InitJNI(env);
return JNI_VERSION;
}
void JNI_OnUnload(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
@@ -462,183 +645,4 @@ namespace Common::Android {
}
#endif
void Initialize(JavaVM* vm, JNIEnv *env) {
s_java_vm = vm;
InitFFmpegOnLoad(vm);
if (env->ExceptionCheck()) {
env->ExceptionClear();
}
// Initialize Java classes
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
"(Ljava/lang/String;Z)V");
env->DeleteLocalRef(game_dir_class);
// Initialize methods
s_exit_emulation_activity =
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
s_disk_cache_load_progress =
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
"(Ljava/lang/String;Ljava/lang/String;)Z");
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
"(Ljava/lang/String;)Z");
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
"(Ljava/lang/String;)Ljava/lang/String;");
s_on_emulation_started =
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
s_on_emulation_stopped =
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
s_on_program_changed =
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
s_game_constructor = env->GetMethodID(game_class, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
env->DeleteLocalRef(game_class);
const jclass string_class = env->FindClass("java/lang/String");
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
env->DeleteLocalRef(string_class);
const jclass pair_class = env->FindClass("kotlin/Pair");
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
s_pair_constructor =
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
env->DeleteLocalRef(pair_class);
const jclass overlay_control_data_class =
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
s_overlay_control_data_class =
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
s_overlay_control_data_constructor =
env->GetMethodID(overlay_control_data_class, "<init>",
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
s_overlay_control_data_id_field =
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
s_overlay_control_data_enabled_field =
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
s_overlay_control_data_landscape_position_field =
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
s_overlay_control_data_portrait_position_field =
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
s_overlay_control_data_foldable_position_field =
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
s_overlay_control_data_individual_scale_field =
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
env->DeleteLocalRef(overlay_control_data_class);
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
s_patch_constructor = env->GetMethodID(
patch_class, "<init>",
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
env->DeleteLocalRef(patch_class);
const jclass double_class = env->FindClass("java/lang/Double");
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
env->DeleteLocalRef(double_class);
const jclass int_class = env->FindClass("java/lang/Integer");
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
env->DeleteLocalRef(int_class);
const jclass boolean_class = env->FindClass("java/lang/Boolean");
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
env->DeleteLocalRef(boolean_class);
const jclass player_input_class =
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
s_player_input_constructor = env->GetMethodID(
player_input_class, "<init>",
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
s_player_input_buttons_field =
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
s_player_input_analogs_field =
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
s_player_input_motions_field =
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
s_player_input_vibration_enabled_field =
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
s_player_input_vibration_strength_field =
env->GetFieldID(player_input_class, "vibrationStrength", "I");
s_player_input_body_color_left_field =
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
s_player_input_body_color_right_field =
env->GetFieldID(player_input_class, "bodyColorRight", "J");
s_player_input_button_color_left_field =
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
s_player_input_button_color_right_field =
env->GetFieldID(player_input_class, "buttonColorRight", "J");
s_player_input_profile_name_field =
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
s_player_input_use_system_vibrator_field =
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
env->DeleteLocalRef(player_input_class);
const jclass yuzu_input_device_interface =
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
s_yuzu_input_device_interface =
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
s_yuzu_input_device_get_name =
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
s_yuzu_input_device_get_guid =
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
"()I");
s_yuzu_input_device_get_supports_vibration =
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
"(F)V");
s_yuzu_input_device_get_axes =
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
s_yuzu_input_device_has_keys =
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
env->DeleteLocalRef(yuzu_input_device_interface);
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
"(ILjava/lang/String;)V");
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
// Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
// Initialize applets
Common::Android::SoftwareKeyboard::InitJNI(env);
Common::Android::WebBrowser::InitJNI(env);
}
} // namespace Common::Android
+3 -4
View File
@@ -11,7 +11,6 @@
namespace Common::Android {
void Initialize(JavaVM* vm, JNIEnv *env);
JNIEnv* GetEnvForThread();
/**
@@ -81,15 +80,15 @@ jfieldID GetPatchTitleIdField();
jclass GetDoubleClass();
jmethodID GetDoubleConstructor();
jmethodID GetDoubleValueMethod();
jfieldID GetDoubleValueField();
jclass GetIntegerClass();
jmethodID GetIntegerConstructor();
jmethodID GetIntegerValueMethod();
jfieldID GetIntegerValueField();
jclass GetBooleanClass();
jmethodID GetBooleanConstructor();
jmethodID GetBooleanValueMethod();
jfieldID GetBooleanValueField();
jclass GetPlayerInputClass();
jmethodID GetPlayerInputConstructor();
+3 -3
View File
@@ -92,14 +92,14 @@ struct EnumMetadata {
// AudioEngine must be specified discretely due to having existing but slightly different
// canonicalizations
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, };
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
template<>
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto},
{"cubeb", AudioEngine::Cubeb},
{"sdl3", AudioEngine::Sdl3},
{"null", AudioEngine::Null},
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
};
}
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
@@ -113,7 +113,7 @@ inline AudioEngine EnumMetadata<AudioEngine>::GetFirst() {
}
template<>
inline AudioEngine EnumMetadata<AudioEngine>::GetLast() {
return AudioEngine::Null;
return AudioEngine::Oboe;
}
ENUM(AudioMode, Mono, Stereo, Surround);
+18 -8
View File
@@ -160,16 +160,26 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info,
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto* info = static_cast<siginfo_t*>(raw_info);
// Try to handle an invalid access.
// TODO: handle accesses which split a page?
const Common::ProcessAddress addr =
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
// We handled the access successfully and are returning to guest code.
return true;
}
// Try to handle an invalid access.
auto const acc_size = 16; // Max architectural access size
// Please note accesses can be wider than 16-bytes
// This should handle **most** of the fragant issues with cases like 128-bit vector
// ld/st or GPU writes.
// This computes the addr for the (first) page corresponding to the access (if not crossing)
auto const addr_c1 = Common::ProcessAddress(u64(info->si_addr) & ~Memory::YUZU_PAGEMASK);
if (!(acc_size > 1 && (addr_c1 & Memory::YUZU_PAGEMASK) + acc_size > Memory::YUZU_PAGESIZE)) {
if (memory.InvalidateNCE(addr_c1, Memory::YUZU_PAGESIZE))
return true;
} else {
// Corresponds to the 2nd page, this means the access is split between two pages
auto const addr_c2 = (addr_c1 & ~Memory::YUZU_PAGEMASK) + Memory::YUZU_PAGESIZE;
// Always invalidate 2nd page, but only account if 1st page was invalidated properly
memory.InvalidateNCE(addr_c2, Memory::YUZU_PAGESIZE);
if (memory.InvalidateNCE(addr_c1, Memory::YUZU_PAGESIZE))
return true;
}
// We couldn't handle the access.
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
}
+1 -1
View File
@@ -358,7 +358,7 @@ private:
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
: client_socket{std::move(client_socket_)}
, signal_pipe{std::move(signal_pipe_)}
, signal_pipe{signal_pipe_}
, active_thread{kernel, nullptr}
{}
-3
View File
@@ -1021,9 +1021,6 @@ Result KProcess::Run(KernelCore& kernel, s32 priority, size_t stack_size) {
// Suspend for debug, if we should.
if (kernel.System().DebuggerEnabled()) {
LOG_INFO(Debug_GDBStub,
"GDB stub enabled; suspending guest process until a debugger continues execution on port {}",
Settings::values.gdbstub_port.GetValue());
main_thread->RequestSuspend(kernel, SuspendType::Debug);
}
+1 -1
View File
@@ -114,7 +114,7 @@ std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const {
std::set<s32> axes;
for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
jobject axis = env->GetObjectArrayElement(j_axes, i);
axes.insert(env->CallIntMethod(axis, Common::Android::GetIntegerValueMethod()));
axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField()));
}
return axes;
}