mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	android: native: Add support for custom Vulkan driver loading.
This commit is contained in:
		@@ -181,6 +181,8 @@ public final class NativeLibrary {
 | 
			
		||||
 | 
			
		||||
    public static native void SetAppDirectory(String directory);
 | 
			
		||||
 | 
			
		||||
    public static native void SetGpuDriverParameters(String hookLibDir, String customDriverDir, String customDriverName, String fileRedirectDir);
 | 
			
		||||
 | 
			
		||||
    public static native boolean ReloadKeys();
 | 
			
		||||
 | 
			
		||||
    // Create the config.ini file.
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,6 @@ 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)
 | 
			
		||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log)
 | 
			
		||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics adrenotools log)
 | 
			
		||||
 | 
			
		||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} yuzu-android)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,61 +7,62 @@
 | 
			
		||||
#include "jni/emu_window/emu_window.h"
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
 | 
			
		||||
    render_window = surface;
 | 
			
		||||
    m_render_window = surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
 | 
			
		||||
    const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
 | 
			
		||||
    input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
 | 
			
		||||
    m_input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnTouchMoved(int id, float x, float y) {
 | 
			
		||||
    const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
 | 
			
		||||
    input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
 | 
			
		||||
    m_input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnTouchReleased(int id) {
 | 
			
		||||
    input_subsystem->GetTouchScreen()->TouchReleased(id);
 | 
			
		||||
    m_input_subsystem->GetTouchScreen()->TouchReleased(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnGamepadButtonEvent(int player_index, int button_id, bool pressed) {
 | 
			
		||||
    input_subsystem->GetVirtualGamepad()->SetButtonState(player_index, button_id, pressed);
 | 
			
		||||
    m_input_subsystem->GetVirtualGamepad()->SetButtonState(player_index, button_id, pressed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y) {
 | 
			
		||||
    input_subsystem->GetVirtualGamepad()->SetStickPosition(player_index, stick_id, x, y);
 | 
			
		||||
    m_input_subsystem->GetVirtualGamepad()->SetStickPosition(player_index, stick_id, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmuWindow_Android::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x,
 | 
			
		||||
                                             float gyro_y, float gyro_z, float accel_x,
 | 
			
		||||
                                             float accel_y, float accel_z) {
 | 
			
		||||
    input_subsystem->GetVirtualGamepad()->SetMotionState(player_index, delta_timestamp, gyro_x,
 | 
			
		||||
                                                         gyro_y, gyro_z, accel_x, accel_y, accel_z);
 | 
			
		||||
    m_input_subsystem->GetVirtualGamepad()->SetMotionState(
 | 
			
		||||
        player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_,
 | 
			
		||||
                                     ANativeWindow* surface_)
 | 
			
		||||
    : input_subsystem{input_subsystem_} {
 | 
			
		||||
EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem,
 | 
			
		||||
                                     ANativeWindow* surface,
 | 
			
		||||
                                     std::shared_ptr<Common::DynamicLibrary> driver_library)
 | 
			
		||||
    : m_input_subsystem{input_subsystem}, m_driver_library{driver_library} {
 | 
			
		||||
    LOG_INFO(Frontend, "initializing");
 | 
			
		||||
 | 
			
		||||
    if (!surface_) {
 | 
			
		||||
    if (!surface) {
 | 
			
		||||
        LOG_CRITICAL(Frontend, "surface is nullptr");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window_width = ANativeWindow_getWidth(surface_);
 | 
			
		||||
    window_height = ANativeWindow_getHeight(surface_);
 | 
			
		||||
    m_window_width = ANativeWindow_getWidth(surface);
 | 
			
		||||
    m_window_height = ANativeWindow_getHeight(surface);
 | 
			
		||||
 | 
			
		||||
    // Ensures that we emulate with the correct aspect ratio.
 | 
			
		||||
    UpdateCurrentFramebufferLayout(window_width, window_height);
 | 
			
		||||
    UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
 | 
			
		||||
 | 
			
		||||
    host_window = surface_;
 | 
			
		||||
    m_host_window = surface;
 | 
			
		||||
    window_info.type = Core::Frontend::WindowSystemType::Android;
 | 
			
		||||
    window_info.render_surface = reinterpret_cast<void*>(host_window);
 | 
			
		||||
    window_info.render_surface = reinterpret_cast<void*>(m_host_window);
 | 
			
		||||
 | 
			
		||||
    input_subsystem->Initialize();
 | 
			
		||||
    m_input_subsystem->Initialize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EmuWindow_Android::~EmuWindow_Android() {
 | 
			
		||||
    input_subsystem->Shutdown();
 | 
			
		||||
    m_input_subsystem->Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,34 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
#include "core/frontend/graphics_context.h"
 | 
			
		||||
#include "input_common/main.h"
 | 
			
		||||
 | 
			
		||||
struct ANativeWindow;
 | 
			
		||||
 | 
			
		||||
class SharedContext_Android : public Core::Frontend::GraphicsContext {
 | 
			
		||||
class GraphicsContext_Android final : public Core::Frontend::GraphicsContext {
 | 
			
		||||
public:
 | 
			
		||||
    SharedContext_Android() = default;
 | 
			
		||||
    ~SharedContext_Android() = default;
 | 
			
		||||
    void MakeCurrent() override {}
 | 
			
		||||
    void DoneCurrent() override {}
 | 
			
		||||
    explicit GraphicsContext_Android(std::shared_ptr<Common::DynamicLibrary> driver_library)
 | 
			
		||||
        : m_driver_library{driver_library} {}
 | 
			
		||||
 | 
			
		||||
    ~GraphicsContext_Android() = default;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() override {
 | 
			
		||||
        return m_driver_library;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::shared_ptr<Common::DynamicLibrary> m_driver_library;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class EmuWindow_Android : public Core::Frontend::EmuWindow {
 | 
			
		||||
class EmuWindow_Android final : public Core::Frontend::EmuWindow {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, ANativeWindow* surface_);
 | 
			
		||||
    EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, ANativeWindow* surface,
 | 
			
		||||
                      std::shared_ptr<Common::DynamicLibrary> driver_library);
 | 
			
		||||
 | 
			
		||||
    ~EmuWindow_Android();
 | 
			
		||||
 | 
			
		||||
    void OnSurfaceChanged(ANativeWindow* surface);
 | 
			
		||||
@@ -29,18 +42,20 @@ public:
 | 
			
		||||
    void OnFrameDisplayed() override {}
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
 | 
			
		||||
        return {std::make_unique<SharedContext_Android>()};
 | 
			
		||||
        return {std::make_unique<GraphicsContext_Android>(m_driver_library)};
 | 
			
		||||
    }
 | 
			
		||||
    bool IsShown() const override {
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    InputCommon::InputSubsystem* input_subsystem{};
 | 
			
		||||
    InputCommon::InputSubsystem* m_input_subsystem{};
 | 
			
		||||
 | 
			
		||||
    ANativeWindow* render_window{};
 | 
			
		||||
    ANativeWindow* host_window{};
 | 
			
		||||
    ANativeWindow* m_render_window{};
 | 
			
		||||
    ANativeWindow* m_host_window{};
 | 
			
		||||
 | 
			
		||||
    float window_width{};
 | 
			
		||||
    float window_height{};
 | 
			
		||||
    float m_window_width{};
 | 
			
		||||
    float m_window_height{};
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Common::DynamicLibrary> m_driver_library;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,15 @@
 | 
			
		||||
#include <locale>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
#include <adrenotools/driver.h>
 | 
			
		||||
 | 
			
		||||
#include <android/api-level.h>
 | 
			
		||||
#include <android/native_window_jni.h>
 | 
			
		||||
 | 
			
		||||
#include "common/detached_tasks.h"
 | 
			
		||||
#include "common/dynamic_library.h"
 | 
			
		||||
#include "common/fs/path_util.h"
 | 
			
		||||
#include "common/logging/backend.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
@@ -70,6 +74,29 @@ public:
 | 
			
		||||
        m_native_window = m_native_window_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
 | 
			
		||||
                             const std::string& custom_driver_name,
 | 
			
		||||
                             const std::string& file_redirect_dir) {
 | 
			
		||||
        void* handle{};
 | 
			
		||||
 | 
			
		||||
        // Try to load a custom driver.
 | 
			
		||||
        if (custom_driver_name.size()) {
 | 
			
		||||
            handle = adrenotools_open_libvulkan(
 | 
			
		||||
                RTLD_NOW, ADRENOTOOLS_DRIVER_CUSTOM | ADRENOTOOLS_DRIVER_FILE_REDIRECT, nullptr,
 | 
			
		||||
                hook_lib_dir.c_str(), custom_driver_dir.c_str(), custom_driver_name.c_str(),
 | 
			
		||||
                file_redirect_dir.c_str(), nullptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Try to load the system driver.
 | 
			
		||||
        if (!handle) {
 | 
			
		||||
            handle = adrenotools_open_libvulkan(RTLD_NOW, ADRENOTOOLS_DRIVER_FILE_REDIRECT, nullptr,
 | 
			
		||||
                                                hook_lib_dir.c_str(), nullptr, nullptr,
 | 
			
		||||
                                                file_redirect_dir.c_str(), nullptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsRunning() const {
 | 
			
		||||
        std::scoped_lock lock(m_mutex);
 | 
			
		||||
        return m_is_running;
 | 
			
		||||
@@ -94,7 +121,8 @@ public:
 | 
			
		||||
        Config{};
 | 
			
		||||
 | 
			
		||||
        // Create the render window.
 | 
			
		||||
        m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window);
 | 
			
		||||
        m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
 | 
			
		||||
                                                       m_vulkan_library);
 | 
			
		||||
 | 
			
		||||
        // Initialize system.
 | 
			
		||||
        m_system.SetShuttingDown(false);
 | 
			
		||||
@@ -242,6 +270,9 @@ private:
 | 
			
		||||
    Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
 | 
			
		||||
    bool m_is_running{};
 | 
			
		||||
 | 
			
		||||
    // GPU driver parameters
 | 
			
		||||
    std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
 | 
			
		||||
 | 
			
		||||
    // Synchronization
 | 
			
		||||
    std::condition_variable_any m_cv;
 | 
			
		||||
    mutable std::mutex m_perf_stats_mutex;
 | 
			
		||||
@@ -327,6 +358,14 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env,
 | 
			
		||||
    Common::FS::SetAppDirectory(GetJString(env, j_directory));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver(
 | 
			
		||||
    JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
 | 
			
		||||
    jstring custom_driver_name, jstring file_redirect_dir) {
 | 
			
		||||
    EmulationSession::GetInstance().InitializeGpuDriver(
 | 
			
		||||
        GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
 | 
			
		||||
        GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
 | 
			
		||||
                                                          [[maybe_unused]] jclass clazz) {
 | 
			
		||||
    Core::Crypto::KeyManager::Instance().ReloadKeys();
 | 
			
		||||
@@ -363,7 +402,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unus
 | 
			
		||||
                                                                    [[maybe_unused]] jint j_device,
 | 
			
		||||
                                                                    jint j_button, jint action) {
 | 
			
		||||
    if (EmulationSession::GetInstance().IsRunning()) {
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device,j_button, action != 0);
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button,
 | 
			
		||||
                                                                      action != 0);
 | 
			
		||||
    }
 | 
			
		||||
    return static_cast<jboolean>(true);
 | 
			
		||||
}
 | 
			
		||||
@@ -373,31 +413,33 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_un
 | 
			
		||||
                                                                      jint j_device, jint stick_id,
 | 
			
		||||
                                                                      jfloat x, jfloat y) {
 | 
			
		||||
    if (EmulationSession::GetInstance().IsRunning()) {
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device,stick_id, x, y);
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y);
 | 
			
		||||
    }
 | 
			
		||||
    return static_cast<jboolean>(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent([[maybe_unused]] JNIEnv* env,
 | 
			
		||||
                                                                    [[maybe_unused]] jclass clazz, jint j_device,jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y,
 | 
			
		||||
                                                                    jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z){
 | 
			
		||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
 | 
			
		||||
    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
 | 
			
		||||
    jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
 | 
			
		||||
    jfloat accel_y, jfloat accel_z) {
 | 
			
		||||
    if (EmulationSession::GetInstance().IsRunning()) {
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadMotionEvent(j_device,delta_timestamp, gyro_x, gyro_y,gyro_z,accel_x,accel_y,accel_z);
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
 | 
			
		||||
            j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
 | 
			
		||||
    }
 | 
			
		||||
    return static_cast<jboolean>(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
 | 
			
		||||
                                                          [[maybe_unused]] jclass clazz, jint id, jfloat x,
 | 
			
		||||
                                                          jfloat y) {
 | 
			
		||||
                                                          [[maybe_unused]] jclass clazz, jint id,
 | 
			
		||||
                                                          jfloat x, jfloat y) {
 | 
			
		||||
    if (EmulationSession::GetInstance().IsRunning()) {
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
 | 
			
		||||
                                                        [[maybe_unused]] jclass clazz, jint id, jfloat x,
 | 
			
		||||
                                                        jfloat y) {
 | 
			
		||||
                                                        [[maybe_unused]] jclass clazz, jint id,
 | 
			
		||||
                                                        jfloat x, jfloat y) {
 | 
			
		||||
    if (EmulationSession::GetInstance().IsRunning()) {
 | 
			
		||||
        EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,11 @@ JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNI
 | 
			
		||||
                                                                             jclass clazz,
 | 
			
		||||
                                                                             jstring j_directory);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT void JNICALL
 | 
			
		||||
Java_org_yuzu_yuzu_1emu_NativeLibrary_Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver(
 | 
			
		||||
    JNIEnv* env, jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
 | 
			
		||||
    jstring custom_driver_name, jstring file_redirect_dir);
 | 
			
		||||
 | 
			
		||||
JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
 | 
			
		||||
                                                                            jclass clazz);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user