android: native: Add support for custom Vulkan driver loading.
This commit is contained in:
parent
ae099d583c
commit
4c38220a64
|
@ -181,6 +181,8 @@ public final class NativeLibrary {
|
||||||
|
|
||||||
public static native void SetAppDirectory(String directory);
|
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();
|
public static native boolean ReloadKeys();
|
||||||
|
|
||||||
// Create the config.ini file.
|
// 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})
|
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 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)
|
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} yuzu-android)
|
||||||
|
|
|
@ -7,61 +7,62 @@
|
||||||
#include "jni/emu_window/emu_window.h"
|
#include "jni/emu_window/emu_window.h"
|
||||||
|
|
||||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
render_window = surface;
|
m_render_window = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
|
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
|
||||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, 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) {
|
void EmuWindow_Android::OnTouchMoved(int id, float x, float y) {
|
||||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, 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) {
|
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) {
|
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) {
|
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,
|
void EmuWindow_Android::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x,
|
||||||
float gyro_y, float gyro_z, float accel_x,
|
float gyro_y, float gyro_z, float accel_x,
|
||||||
float accel_y, float accel_z) {
|
float accel_y, float accel_z) {
|
||||||
input_subsystem->GetVirtualGamepad()->SetMotionState(player_index, delta_timestamp, gyro_x,
|
m_input_subsystem->GetVirtualGamepad()->SetMotionState(
|
||||||
gyro_y, gyro_z, accel_x, accel_y, accel_z);
|
player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_,
|
EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem,
|
||||||
ANativeWindow* surface_)
|
ANativeWindow* surface,
|
||||||
: input_subsystem{input_subsystem_} {
|
std::shared_ptr<Common::DynamicLibrary> driver_library)
|
||||||
|
: m_input_subsystem{input_subsystem}, m_driver_library{driver_library} {
|
||||||
LOG_INFO(Frontend, "initializing");
|
LOG_INFO(Frontend, "initializing");
|
||||||
|
|
||||||
if (!surface_) {
|
if (!surface) {
|
||||||
LOG_CRITICAL(Frontend, "surface is nullptr");
|
LOG_CRITICAL(Frontend, "surface is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window_width = ANativeWindow_getWidth(surface_);
|
m_window_width = ANativeWindow_getWidth(surface);
|
||||||
window_height = ANativeWindow_getHeight(surface_);
|
m_window_height = ANativeWindow_getHeight(surface);
|
||||||
|
|
||||||
// Ensures that we emulate with the correct aspect ratio.
|
// 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.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() {
|
EmuWindow_Android::~EmuWindow_Android() {
|
||||||
input_subsystem->Shutdown();
|
m_input_subsystem->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,34 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "core/frontend/graphics_context.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
|
||||||
struct ANativeWindow;
|
struct ANativeWindow;
|
||||||
|
|
||||||
class SharedContext_Android : public Core::Frontend::GraphicsContext {
|
class GraphicsContext_Android final : public Core::Frontend::GraphicsContext {
|
||||||
public:
|
public:
|
||||||
SharedContext_Android() = default;
|
explicit GraphicsContext_Android(std::shared_ptr<Common::DynamicLibrary> driver_library)
|
||||||
~SharedContext_Android() = default;
|
: m_driver_library{driver_library} {}
|
||||||
void MakeCurrent() override {}
|
|
||||||
void DoneCurrent() override {}
|
~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:
|
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();
|
~EmuWindow_Android();
|
||||||
|
|
||||||
void OnSurfaceChanged(ANativeWindow* surface);
|
void OnSurfaceChanged(ANativeWindow* surface);
|
||||||
|
@ -29,18 +42,20 @@ public:
|
||||||
void OnFrameDisplayed() override {}
|
void OnFrameDisplayed() override {}
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const 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 {
|
bool IsShown() const override {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InputCommon::InputSubsystem* input_subsystem{};
|
InputCommon::InputSubsystem* m_input_subsystem{};
|
||||||
|
|
||||||
ANativeWindow* render_window{};
|
ANativeWindow* m_render_window{};
|
||||||
ANativeWindow* host_window{};
|
ANativeWindow* m_host_window{};
|
||||||
|
|
||||||
float window_width{};
|
float m_window_width{};
|
||||||
float window_height{};
|
float m_window_height{};
|
||||||
|
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> m_driver_library;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,11 +5,15 @@
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <adrenotools/driver.h>
|
||||||
|
|
||||||
#include <android/api-level.h>
|
#include <android/api-level.h>
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
|
|
||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -70,6 +74,29 @@ public:
|
||||||
m_native_window = m_native_window_;
|
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 {
|
bool IsRunning() const {
|
||||||
std::scoped_lock lock(m_mutex);
|
std::scoped_lock lock(m_mutex);
|
||||||
return m_is_running;
|
return m_is_running;
|
||||||
|
@ -94,7 +121,8 @@ public:
|
||||||
Config{};
|
Config{};
|
||||||
|
|
||||||
// Create the render window.
|
// 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.
|
// Initialize system.
|
||||||
m_system.SetShuttingDown(false);
|
m_system.SetShuttingDown(false);
|
||||||
|
@ -242,6 +270,9 @@ private:
|
||||||
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
|
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
|
||||||
bool m_is_running{};
|
bool m_is_running{};
|
||||||
|
|
||||||
|
// GPU driver parameters
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
std::condition_variable_any m_cv;
|
std::condition_variable_any m_cv;
|
||||||
mutable std::mutex m_perf_stats_mutex;
|
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));
|
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,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
||||||
|
@ -363,7 +402,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unus
|
||||||
[[maybe_unused]] jint j_device,
|
[[maybe_unused]] jint j_device,
|
||||||
jint j_button, jint action) {
|
jint j_button, jint action) {
|
||||||
if (EmulationSession::GetInstance().IsRunning()) {
|
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);
|
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,
|
jint j_device, jint stick_id,
|
||||||
jfloat x, jfloat y) {
|
jfloat x, jfloat y) {
|
||||||
if (EmulationSession::GetInstance().IsRunning()) {
|
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);
|
return static_cast<jboolean>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent([[maybe_unused]] JNIEnv* env,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
|
||||||
[[maybe_unused]] jclass clazz, jint j_device,jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y,
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
|
||||||
jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z){
|
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()) {
|
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);
|
return static_cast<jboolean>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz, jint id, jfloat x,
|
[[maybe_unused]] jclass clazz, jint id,
|
||||||
jfloat y) {
|
jfloat x, jfloat y) {
|
||||||
if (EmulationSession::GetInstance().IsRunning()) {
|
if (EmulationSession::GetInstance().IsRunning()) {
|
||||||
EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
|
EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz, jint id, jfloat x,
|
[[maybe_unused]] jclass clazz, jint id,
|
||||||
jfloat y) {
|
jfloat x, jfloat y) {
|
||||||
if (EmulationSession::GetInstance().IsRunning()) {
|
if (EmulationSession::GetInstance().IsRunning()) {
|
||||||
EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
|
EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,11 @@ JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNI
|
||||||
jclass clazz,
|
jclass clazz,
|
||||||
jstring j_directory);
|
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,
|
JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
|
||||||
jclass clazz);
|
jclass clazz);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
|
|
||||||
namespace Core::Frontend {
|
namespace Core::Frontend {
|
||||||
|
|
||||||
|
@ -24,16 +25,8 @@ public:
|
||||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||||
virtual void DoneCurrent() {}
|
virtual void DoneCurrent() {}
|
||||||
|
|
||||||
/// Parameters used to configure custom drivers (used by Android only)
|
/// Gets the GPU driver library (used by Android only)
|
||||||
struct CustomDriverParameters {
|
virtual std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() {
|
||||||
std::string hook_lib_dir;
|
|
||||||
std::string custom_driver_dir;
|
|
||||||
std::string custom_driver_name;
|
|
||||||
std::string file_redirect_dir;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Gets custom driver parameters configured by the frontend (used by Android only)
|
|
||||||
virtual std::optional<CustomDriverParameters> GetCustomDriverParameters() {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
|
||||||
Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
|
Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
|
std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
|
||||||
: RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
|
: RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
|
||||||
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()),
|
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
|
||||||
instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
|
instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
|
||||||
Settings::values.renderer_debug.GetValue())),
|
Settings::values.renderer_debug.GetValue())),
|
||||||
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
|
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
|
||||||
surface(CreateSurface(instance, render_window.GetWindowInfo())),
|
surface(CreateSurface(instance, render_window.GetWindowInfo())),
|
||||||
|
|
|
@ -63,7 +63,7 @@ private:
|
||||||
Core::Memory::Memory& cpu_memory;
|
Core::Memory::Memory& cpu_memory;
|
||||||
Tegra::GPU& gpu;
|
Tegra::GPU& gpu;
|
||||||
|
|
||||||
Common::DynamicLibrary library;
|
std::shared_ptr<Common::DynamicLibrary> library;
|
||||||
vk::InstanceDispatch dld;
|
vk::InstanceDispatch dld;
|
||||||
|
|
||||||
vk::Instance instance;
|
vk::Instance instance;
|
||||||
|
|
|
@ -314,10 +314,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
|
const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
|
||||||
const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
|
const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
|
||||||
const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK;
|
const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK;
|
||||||
const bool is_adreno = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||||
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP;
|
||||||
|
|
||||||
if ((is_mvk || is_adreno) && !is_suitable) {
|
if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) {
|
||||||
LOG_WARNING(Render_Vulkan, "Unsuitable driver is MoltenVK, continuing anyway");
|
LOG_WARNING(Render_Vulkan, "Unsuitable driver is MoltenVK, continuing anyway");
|
||||||
} else if (!is_suitable) {
|
} else if (!is_suitable) {
|
||||||
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
|
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
|
||||||
|
@ -362,14 +362,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
CollectToolingInfo();
|
CollectToolingInfo();
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
if (is_adreno) {
|
if (is_qualcomm) {
|
||||||
must_emulate_scaled_formats = true;
|
must_emulate_scaled_formats = true;
|
||||||
|
|
||||||
LOG_WARNING(Render_Vulkan, "Adreno drivers have broken VK_EXT_extended_dynamic_state");
|
LOG_WARNING(Render_Vulkan, "Adreno drivers have broken VK_EXT_extended_dynamic_state");
|
||||||
extensions.extended_dynamic_state = false;
|
extensions.extended_dynamic_state = false;
|
||||||
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
|
|
||||||
LOG_WARNING(Render_Vulkan, "Adreno drivers have a slow VK_KHR_push_descriptor implementation");
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Adreno drivers have a slow VK_KHR_push_descriptor implementation");
|
||||||
extensions.push_descriptor = false;
|
extensions.push_descriptor = false;
|
||||||
loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
|
|
||||||
|
@ -392,6 +393,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
||||||
if (is_arm) {
|
if (is_arm) {
|
||||||
must_emulate_scaled_formats = true;
|
must_emulate_scaled_formats = true;
|
||||||
|
|
||||||
|
@ -513,7 +515,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
|
LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
|
||||||
cant_blit_msaa = true;
|
cant_blit_msaa = true;
|
||||||
}
|
}
|
||||||
if (is_intel_anv || is_adreno) {
|
if (is_intel_anv || is_qualcomm) {
|
||||||
LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format");
|
LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format");
|
||||||
must_emulate_bgr565 = true;
|
must_emulate_bgr565 = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,29 +10,35 @@
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
Common::DynamicLibrary OpenLibrary() {
|
std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
|
||||||
|
[[maybe_unused]] Core::Frontend::GraphicsContext* context) {
|
||||||
LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library");
|
LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library");
|
||||||
Common::DynamicLibrary library;
|
#ifdef ANDROID
|
||||||
|
// Android manages its Vulkan driver from the frontend.
|
||||||
|
return context->GetDriverLibrary();
|
||||||
|
#else
|
||||||
|
auto library = std::make_shared<Common::DynamicLibrary>();
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// Check if a path to a specific Vulkan library has been specified.
|
// Check if a path to a specific Vulkan library has been specified.
|
||||||
char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
|
char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
|
||||||
if (!libvulkan_env || !library.Open(libvulkan_env)) {
|
if (!libvulkan_env || !library->Open(libvulkan_env)) {
|
||||||
// Use the libvulkan.dylib from the application bundle.
|
// Use the libvulkan.dylib from the application bundle.
|
||||||
const auto filename =
|
const auto filename =
|
||||||
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
|
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
|
||||||
void(library.Open(Common::FS::PathToUTF8String(filename).c_str()));
|
void(library->Open(Common::FS::PathToUTF8String(filename).c_str()));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
|
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
|
||||||
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename);
|
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename);
|
||||||
if (!library.Open(filename.c_str())) {
|
if (!library->Open(filename.c_str())) {
|
||||||
// Android devices may not have libvulkan.so.1, only libvulkan.so.
|
// Android devices may not have libvulkan.so.1, only libvulkan.so.
|
||||||
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
|
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
|
||||||
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename);
|
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename);
|
||||||
void(library.Open(filename.c_str()));
|
void(library->Open(filename.c_str()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return library;
|
return library;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -3,10 +3,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "common/dynamic_library.h"
|
#include "common/dynamic_library.h"
|
||||||
|
#include "core/frontend/graphics_context.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
Common::DynamicLibrary OpenLibrary();
|
std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
|
||||||
|
[[maybe_unused]] Core::Frontend::GraphicsContext* context = nullptr);
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -515,8 +515,8 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
|
||||||
auto wsi = QtCommon::GetWindowSystemInfo(window);
|
auto wsi = QtCommon::GetWindowSystemInfo(window);
|
||||||
|
|
||||||
vk::InstanceDispatch dld;
|
vk::InstanceDispatch dld;
|
||||||
const Common::DynamicLibrary library = OpenLibrary();
|
const auto library = OpenLibrary();
|
||||||
const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type);
|
const vk::Instance instance = CreateInstance(*library, dld, VK_API_VERSION_1_1, wsi.type);
|
||||||
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
|
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
|
||||||
vk::SurfaceKHR surface = CreateSurface(instance, wsi);
|
vk::SurfaceKHR surface = CreateSurface(instance, wsi);
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ void CheckVulkan() {
|
||||||
// Just start the Vulkan loader, this will crash if something is wrong
|
// Just start the Vulkan loader, this will crash if something is wrong
|
||||||
try {
|
try {
|
||||||
Vulkan::vk::InstanceDispatch dld;
|
Vulkan::vk::InstanceDispatch dld;
|
||||||
const Common::DynamicLibrary library = Vulkan::OpenLibrary();
|
const auto library = Vulkan::OpenLibrary();
|
||||||
const Vulkan::vk::Instance instance =
|
const Vulkan::vk::Instance instance =
|
||||||
Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
|
Vulkan::CreateInstance(*library, dld, VK_API_VERSION_1_1);
|
||||||
|
|
||||||
} catch (const Vulkan::vk::Exception& exception) {
|
} catch (const Vulkan::vk::Exception& exception) {
|
||||||
fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
|
fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
|
||||||
|
|
Reference in New Issue