From 6c391971c638fd8af689c0de37ddc1c11f8617f3 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sun, 13 Aug 2023 17:44:16 +0300 Subject: [PATCH] android: Custom driver code --- .gitmodules | 3 ++ externals/CMakeLists.txt | 5 ++ externals/libadrenotools | 1 + src/android/app/src/main/jni/CMakeLists.txt | 2 +- .../src/main/jni/emu_window/emu_window_vk.cpp | 22 ++++++-- .../src/main/jni/emu_window/emu_window_vk.h | 6 ++- src/android/app/src/main/jni/native.cpp | 52 ++++++++++++++++++- src/citra_qt/util/vk_device_info.cpp | 6 +-- .../dynamic_library/dynamic_library.cpp | 2 + src/common/dynamic_library/dynamic_library.h | 1 + src/core/frontend/emu_window.h | 9 ++++ .../renderer_vulkan/vk_instance.cpp | 10 ++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 6 +-- .../renderer_vulkan/vk_platform.cpp | 15 ++++-- src/video_core/renderer_vulkan/vk_platform.h | 4 +- 15 files changed, 118 insertions(+), 26 deletions(-) create mode 160000 externals/libadrenotools diff --git a/.gitmodules b/.gitmodules index cd4790369..0311d459d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -82,3 +82,6 @@ [submodule "library-headers"] path = externals/library-headers/library-headers url = https://github.com/citra-emu/ext-library-headers.git +[submodule "libadrenotools"] + path = externals/libadrenotools + url = https://github.com/bylaws/libadrenotools diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 44882d6cf..285d6fa6f 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -242,3 +242,8 @@ target_include_directories(vma SYSTEM INTERFACE ./vma/include) # vulkan-headers add_library(vulkan-headers INTERFACE) target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include) + +# adrenotools +if (ANDROID) + add_subdirectory(libadrenotools) +endif() diff --git a/externals/libadrenotools b/externals/libadrenotools new file mode 160000 index 000000000..deec5f75e --- /dev/null +++ b/externals/libadrenotools @@ -0,0 +1 @@ +Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1 diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 7d1e917b2..7cc6304c1 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -34,7 +34,7 @@ add_library(citra-android SHARED ndk_motion.h ) -target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network) +target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network adrenotools) target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics log mediandk yuv) set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android) diff --git a/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp b/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp index 52c95dcae..c8dadd8ec 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp @@ -9,10 +9,24 @@ #include "jni/emu_window/emu_window_vk.h" #include "video_core/video_core.h" -class SharedContext_Android : public Frontend::GraphicsContext {}; +class GraphicsContext_Android final : public Frontend::GraphicsContext { +public: + explicit GraphicsContext_Android(std::shared_ptr driver_library_) + : driver_library{driver_library_} {} -EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface) - : EmuWindow_Android{surface} { + ~GraphicsContext_Android() = default; + + std::shared_ptr GetDriverLibrary() override { + return driver_library; + } + +private: + std::shared_ptr driver_library; +}; + +EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan( + ANativeWindow* surface, std::shared_ptr driver_library_) + : EmuWindow_Android{surface}, driver_library{driver_library_} { CreateWindowSurface(); if (core_context = CreateSharedContext(); !core_context) { @@ -35,7 +49,7 @@ bool EmuWindow_Android_Vulkan::CreateWindowSurface() { } std::unique_ptr EmuWindow_Android_Vulkan::CreateSharedContext() const { - return std::make_unique(); + return std::make_unique(driver_library); } void EmuWindow_Android_Vulkan::StopPresenting() { diff --git a/src/android/app/src/main/jni/emu_window/emu_window_vk.h b/src/android/app/src/main/jni/emu_window/emu_window_vk.h index 69f0f7c96..9459a735a 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_vk.h +++ b/src/android/app/src/main/jni/emu_window/emu_window_vk.h @@ -10,7 +10,8 @@ struct ANativeWindow; class EmuWindow_Android_Vulkan : public EmuWindow_Android { public: - EmuWindow_Android_Vulkan(ANativeWindow* surface); + EmuWindow_Android_Vulkan(ANativeWindow* surface, + std::shared_ptr driver_library); ~EmuWindow_Android_Vulkan() override = default; void TryPresenting() override; @@ -20,4 +21,7 @@ public: private: bool CreateWindowSurface() override; + +private: + std::shared_ptr driver_library; }; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index cddc45923..220151d11 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -4,13 +4,16 @@ #include #include +#include #include #include #include "audio_core/dsp_interface.h" #include "common/aarch64/cpu_detect.h" +#include "common/arch.h" #include "common/common_paths.h" +#include "common/dynamic_library/dynamic_library.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -43,10 +46,15 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" +#if CITRA_ARCH(arm64) +#include +#endif + namespace { ANativeWindow* s_surf; +std::shared_ptr vulkan_library{}; std::unique_ptr window; std::atomic stop_run{true}; @@ -127,11 +135,11 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { window = std::make_unique(s_surf); break; case Settings::GraphicsAPI::Vulkan: - window = std::make_unique(s_surf); + window = std::make_unique(s_surf, vulkan_library); break; default: LOG_CRITICAL(Frontend, "Unknown graphics API {}, using Vulkan", graphics_api); - window = std::make_unique(s_surf); + window = std::make_unique(s_surf, vulkan_library); } Core::System& system{Core::System::GetInstance()}; @@ -232,6 +240,37 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { return Core::System::ResultStatus::Success; } +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) { +#if CITRA_ARCH(arm64) + void* handle{}; + const char* file_redirect_dir_{}; + int featureFlags{}; + + // Enable driver file redirection when renderer debugging is enabled. + if (Settings::values.renderer_debug && file_redirect_dir.size()) { + featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT; + file_redirect_dir_ = file_redirect_dir.c_str(); + } + + // Try to load a custom driver. + if (custom_driver_name.size()) { + handle = adrenotools_open_libvulkan( + RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(), + custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr); + } + + // Try to load the system driver. + if (!handle) { + handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), + nullptr, nullptr, file_redirect_dir_, nullptr); + } + + vulkan_library = std::make_shared(handle); +#endif +} + extern "C" { void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, @@ -265,6 +304,15 @@ void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused window->TryPresenting(); } +void JNICALL 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) { + InitializeGpuDriver(GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), + GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); +} + void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env, [[maybe_unused]] jclass clazz, jint layout_option, diff --git a/src/citra_qt/util/vk_device_info.cpp b/src/citra_qt/util/vk_device_info.cpp index 276eb93c7..dee6acb3c 100644 --- a/src/citra_qt/util/vk_device_info.cpp +++ b/src/citra_qt/util/vk_device_info.cpp @@ -15,9 +15,9 @@ std::vector GetVulkanPhysicalDevices() { const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName); result.push_back(name); } - } catch (...) { - LOG_ERROR(Frontend, "Error occured while querying for physical devices."); + } catch (const std::runtime_error& err) { + LOG_ERROR(Frontend, "Error occured while querying for physical devices: {}", err.what()); } return result; -} \ No newline at end of file +} diff --git a/src/common/dynamic_library/dynamic_library.cpp b/src/common/dynamic_library/dynamic_library.cpp index 013c0c91a..016e27f4c 100644 --- a/src/common/dynamic_library/dynamic_library.cpp +++ b/src/common/dynamic_library/dynamic_library.cpp @@ -14,6 +14,8 @@ namespace Common { DynamicLibrary::DynamicLibrary() = default; +DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {} + DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) { auto full_name = GetLibraryName(name, major, minor); void(Load(full_name)); diff --git a/src/common/dynamic_library/dynamic_library.h b/src/common/dynamic_library/dynamic_library.h index 2fbb7a1b8..9a0c2083f 100644 --- a/src/common/dynamic_library/dynamic_library.h +++ b/src/common/dynamic_library/dynamic_library.h @@ -11,6 +11,7 @@ namespace Common { class DynamicLibrary { public: explicit DynamicLibrary(); + explicit DynamicLibrary(void* handle); explicit DynamicLibrary(std::string_view name, int major = -1, int minor = -1); ~DynamicLibrary(); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 61b09583b..766449110 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -12,6 +12,10 @@ #include "core/3ds.h" #include "core/frontend/framebuffer_layout.h" +namespace Common { +class DynamicLibrary; +} + namespace Frontend { /// Information for the Graphics Backends signifying what type of screen pointer is in @@ -82,6 +86,11 @@ public: /// Releases (dunno if this is the "right" word) the context from the caller thread virtual void DoneCurrent(){}; + /// Gets the GPU driver library (used by Android only) + virtual std::shared_ptr GetDriverLibrary() { + return {}; + } + class Scoped { public: explicit Scoped(GraphicsContext& context_) : context(context_) { diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 02a236c5a..1aaa77aef 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -130,10 +130,10 @@ Instance::Instance(bool enable_validation, bool dump_command_buffers) physical_devices{instance->enumeratePhysicalDevices()} {} Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) - : library{OpenLibrary()}, instance{CreateInstance( - *library, window.GetWindowInfo().type, - Settings::values.renderer_debug.GetValue(), - Settings::values.dump_command_buffers.GetValue())}, + : library{OpenLibrary(&window)}, instance{CreateInstance( + *library, window.GetWindowInfo().type, + Settings::values.renderer_debug.GetValue(), + Settings::values.dump_command_buffers.GetValue())}, debug_callback{CreateDebugCallback(*instance, debug_utils_supported)}, physical_devices{instance->enumeratePhysicalDevices()} { const std::size_t num_physical_devices = static_cast(physical_devices.size()); @@ -461,8 +461,6 @@ bool Instance::CreateDevice() { .features{ .geometryShader = features.geometryShader, .logicOp = features.logicOp, - .depthClamp = features.depthClamp, - .largePoints = features.largePoints, .samplerAnisotropy = features.samplerAnisotropy, .fragmentStoresAndAtomics = features.fragmentStoresAndAtomics, .shaderClipDistance = features.shaderClipDistance, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 54e693068..618e35c43 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -183,9 +183,9 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { auto [it, new_pipeline] = graphics_pipelines.try_emplace(pipeline_hash); if (new_pipeline) { - it.value() = std::make_unique( - instance, renderpass_cache, info, *pipeline_cache, *pipeline_layout, current_shaders, - &workers); + it.value() = + std::make_unique(instance, renderpass_cache, info, *pipeline_cache, + *pipeline_layout, current_shaders, &workers); } GraphicsPipeline* const pipeline{it->second.get()}; diff --git a/src/video_core/renderer_vulkan/vk_platform.cpp b/src/video_core/renderer_vulkan/vk_platform.cpp index a91914669..7b4c6e230 100644 --- a/src/video_core/renderer_vulkan/vk_platform.cpp +++ b/src/video_core/renderer_vulkan/vk_platform.cpp @@ -95,7 +95,14 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT } } // Anonymous namespace -std::shared_ptr OpenLibrary() { +std::shared_ptr OpenLibrary( + [[maybe_unused]] Frontend::GraphicsContext* context) { +#ifdef ANDROID + // Android may override the Vulkan driver from the frontend. + if (auto library = context->GetDriverLibrary(); library) { + return library; + } +#endif auto library = std::make_shared(); #ifdef __APPLE__ const std::string filename = Common::DynamicLibrary::GetLibraryName("vulkan"); @@ -273,16 +280,14 @@ vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library, const auto vkGetInstanceProcAddr = library.GetSymbol("vkGetInstanceProcAddr"); if (!vkGetInstanceProcAddr) { - LOG_CRITICAL(Render_Vulkan, "Failed GetSymbol vkGetInstanceProcAddr"); - return {}; + throw std::runtime_error("Failed GetSymbol vkGetInstanceProcAddr"); } VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); const auto extensions = GetInstanceExtensions(window_type, enable_validation); const u32 available_version = vk::enumerateInstanceVersion(); if (available_version < VK_API_VERSION_1_1) { - LOG_CRITICAL(Render_Vulkan, "Vulkan 1.0 is not supported, 1.1 is required!"); - return {}; + throw std::runtime_error("Vulkan 1.0 is not supported, 1.1 is required!"); } const vk::ApplicationInfo application_info = { diff --git a/src/video_core/renderer_vulkan/vk_platform.h b/src/video_core/renderer_vulkan/vk_platform.h index e80a0fb2d..48ebcc90d 100644 --- a/src/video_core/renderer_vulkan/vk_platform.h +++ b/src/video_core/renderer_vulkan/vk_platform.h @@ -13,6 +13,7 @@ namespace Frontend { class EmuWindow; +class GraphicsContext; enum class WindowSystemType : u8; } // namespace Frontend @@ -21,7 +22,8 @@ namespace Vulkan { using DebugCallback = std::variant; -std::shared_ptr OpenLibrary(); +std::shared_ptr OpenLibrary( + [[maybe_unused]] Frontend::GraphicsContext* context = nullptr); vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window);