android: Custom driver code

This commit is contained in:
GPUCode 2023-08-13 17:44:16 +03:00
parent 85dd604a7e
commit 6c391971c6
15 changed files with 118 additions and 26 deletions

3
.gitmodules vendored
View file

@ -82,3 +82,6 @@
[submodule "library-headers"] [submodule "library-headers"]
path = externals/library-headers/library-headers path = externals/library-headers/library-headers
url = https://github.com/citra-emu/ext-library-headers.git url = https://github.com/citra-emu/ext-library-headers.git
[submodule "libadrenotools"]
path = externals/libadrenotools
url = https://github.com/bylaws/libadrenotools

View file

@ -242,3 +242,8 @@ target_include_directories(vma SYSTEM INTERFACE ./vma/include)
# vulkan-headers # vulkan-headers
add_library(vulkan-headers INTERFACE) add_library(vulkan-headers INTERFACE)
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include) target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
# adrenotools
if (ANDROID)
add_subdirectory(libadrenotools)
endif()

1
externals/libadrenotools vendored Submodule

@ -0,0 +1 @@
Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1

View file

@ -34,7 +34,7 @@ add_library(citra-android SHARED
ndk_motion.h 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) target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics log mediandk yuv)
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android) set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)

View file

@ -9,10 +9,24 @@
#include "jni/emu_window/emu_window_vk.h" #include "jni/emu_window/emu_window_vk.h"
#include "video_core/video_core.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<Common::DynamicLibrary> driver_library_)
: driver_library{driver_library_} {}
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface) ~GraphicsContext_Android() = default;
: EmuWindow_Android{surface} {
std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() override {
return driver_library;
}
private:
std::shared_ptr<Common::DynamicLibrary> driver_library;
};
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(
ANativeWindow* surface, std::shared_ptr<Common::DynamicLibrary> driver_library_)
: EmuWindow_Android{surface}, driver_library{driver_library_} {
CreateWindowSurface(); CreateWindowSurface();
if (core_context = CreateSharedContext(); !core_context) { if (core_context = CreateSharedContext(); !core_context) {
@ -35,7 +49,7 @@ bool EmuWindow_Android_Vulkan::CreateWindowSurface() {
} }
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const { std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const {
return std::make_unique<SharedContext_Android>(); return std::make_unique<GraphicsContext_Android>(driver_library);
} }
void EmuWindow_Android_Vulkan::StopPresenting() { void EmuWindow_Android_Vulkan::StopPresenting() {

View file

@ -10,7 +10,8 @@ struct ANativeWindow;
class EmuWindow_Android_Vulkan : public EmuWindow_Android { class EmuWindow_Android_Vulkan : public EmuWindow_Android {
public: public:
EmuWindow_Android_Vulkan(ANativeWindow* surface); EmuWindow_Android_Vulkan(ANativeWindow* surface,
std::shared_ptr<Common::DynamicLibrary> driver_library);
~EmuWindow_Android_Vulkan() override = default; ~EmuWindow_Android_Vulkan() override = default;
void TryPresenting() override; void TryPresenting() override;
@ -20,4 +21,7 @@ public:
private: private:
bool CreateWindowSurface() override; bool CreateWindowSurface() override;
private:
std::shared_ptr<Common::DynamicLibrary> driver_library;
}; };

View file

@ -4,13 +4,16 @@
#include <algorithm> #include <algorithm>
#include <thread> #include <thread>
#include <dlfcn.h>
#include <android/api-level.h> #include <android/api-level.h>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "audio_core/dsp_interface.h" #include "audio_core/dsp_interface.h"
#include "common/aarch64/cpu_detect.h" #include "common/aarch64/cpu_detect.h"
#include "common/arch.h"
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/dynamic_library/dynamic_library.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -43,10 +46,15 @@
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
#if CITRA_ARCH(arm64)
#include <adrenotools/driver.h>
#endif
namespace { namespace {
ANativeWindow* s_surf; ANativeWindow* s_surf;
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
std::unique_ptr<EmuWindow_Android> window; std::unique_ptr<EmuWindow_Android> window;
std::atomic<bool> stop_run{true}; std::atomic<bool> stop_run{true};
@ -127,11 +135,11 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf); window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf);
break; break;
case Settings::GraphicsAPI::Vulkan: case Settings::GraphicsAPI::Vulkan:
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf); window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
break; break;
default: default:
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using Vulkan", graphics_api); LOG_CRITICAL(Frontend, "Unknown graphics API {}, using Vulkan", graphics_api);
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf); window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
} }
Core::System& system{Core::System::GetInstance()}; Core::System& system{Core::System::GetInstance()};
@ -232,6 +240,37 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
return Core::System::ResultStatus::Success; 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<Common::DynamicLibrary>(handle);
#endif
}
extern "C" { extern "C" {
void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, 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(); 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, void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
[[maybe_unused]] jclass clazz, [[maybe_unused]] jclass clazz,
jint layout_option, jint layout_option,

View file

@ -15,9 +15,9 @@ std::vector<QString> GetVulkanPhysicalDevices() {
const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName); const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName);
result.push_back(name); result.push_back(name);
} }
} catch (...) { } catch (const std::runtime_error& err) {
LOG_ERROR(Frontend, "Error occured while querying for physical devices."); LOG_ERROR(Frontend, "Error occured while querying for physical devices: {}", err.what());
} }
return result; return result;
} }

View file

@ -14,6 +14,8 @@ namespace Common {
DynamicLibrary::DynamicLibrary() = default; DynamicLibrary::DynamicLibrary() = default;
DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {}
DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) { DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) {
auto full_name = GetLibraryName(name, major, minor); auto full_name = GetLibraryName(name, major, minor);
void(Load(full_name)); void(Load(full_name));

View file

@ -11,6 +11,7 @@ namespace Common {
class DynamicLibrary { class DynamicLibrary {
public: public:
explicit DynamicLibrary(); explicit DynamicLibrary();
explicit DynamicLibrary(void* handle);
explicit DynamicLibrary(std::string_view name, int major = -1, int minor = -1); explicit DynamicLibrary(std::string_view name, int major = -1, int minor = -1);
~DynamicLibrary(); ~DynamicLibrary();

View file

@ -12,6 +12,10 @@
#include "core/3ds.h" #include "core/3ds.h"
#include "core/frontend/framebuffer_layout.h" #include "core/frontend/framebuffer_layout.h"
namespace Common {
class DynamicLibrary;
}
namespace Frontend { namespace Frontend {
/// Information for the Graphics Backends signifying what type of screen pointer is in /// 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 /// Releases (dunno if this is the "right" word) the context from the caller thread
virtual void DoneCurrent(){}; virtual void DoneCurrent(){};
/// Gets the GPU driver library (used by Android only)
virtual std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() {
return {};
}
class Scoped { class Scoped {
public: public:
explicit Scoped(GraphicsContext& context_) : context(context_) { explicit Scoped(GraphicsContext& context_) : context(context_) {

View file

@ -130,10 +130,10 @@ Instance::Instance(bool enable_validation, bool dump_command_buffers)
physical_devices{instance->enumeratePhysicalDevices()} {} physical_devices{instance->enumeratePhysicalDevices()} {}
Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
: library{OpenLibrary()}, instance{CreateInstance( : library{OpenLibrary(&window)}, instance{CreateInstance(
*library, window.GetWindowInfo().type, *library, window.GetWindowInfo().type,
Settings::values.renderer_debug.GetValue(), Settings::values.renderer_debug.GetValue(),
Settings::values.dump_command_buffers.GetValue())}, Settings::values.dump_command_buffers.GetValue())},
debug_callback{CreateDebugCallback(*instance, debug_utils_supported)}, debug_callback{CreateDebugCallback(*instance, debug_utils_supported)},
physical_devices{instance->enumeratePhysicalDevices()} { physical_devices{instance->enumeratePhysicalDevices()} {
const std::size_t num_physical_devices = static_cast<u16>(physical_devices.size()); const std::size_t num_physical_devices = static_cast<u16>(physical_devices.size());
@ -461,8 +461,6 @@ bool Instance::CreateDevice() {
.features{ .features{
.geometryShader = features.geometryShader, .geometryShader = features.geometryShader,
.logicOp = features.logicOp, .logicOp = features.logicOp,
.depthClamp = features.depthClamp,
.largePoints = features.largePoints,
.samplerAnisotropy = features.samplerAnisotropy, .samplerAnisotropy = features.samplerAnisotropy,
.fragmentStoresAndAtomics = features.fragmentStoresAndAtomics, .fragmentStoresAndAtomics = features.fragmentStoresAndAtomics,
.shaderClipDistance = features.shaderClipDistance, .shaderClipDistance = features.shaderClipDistance,

View file

@ -183,9 +183,9 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) {
auto [it, new_pipeline] = graphics_pipelines.try_emplace(pipeline_hash); auto [it, new_pipeline] = graphics_pipelines.try_emplace(pipeline_hash);
if (new_pipeline) { if (new_pipeline) {
it.value() = std::make_unique<GraphicsPipeline>( it.value() =
instance, renderpass_cache, info, *pipeline_cache, *pipeline_layout, current_shaders, std::make_unique<GraphicsPipeline>(instance, renderpass_cache, info, *pipeline_cache,
&workers); *pipeline_layout, current_shaders, &workers);
} }
GraphicsPipeline* const pipeline{it->second.get()}; GraphicsPipeline* const pipeline{it->second.get()};

View file

@ -95,7 +95,14 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT
} }
} // Anonymous namespace } // Anonymous namespace
std::shared_ptr<Common::DynamicLibrary> OpenLibrary() { std::shared_ptr<Common::DynamicLibrary> 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<Common::DynamicLibrary>(); auto library = std::make_shared<Common::DynamicLibrary>();
#ifdef __APPLE__ #ifdef __APPLE__
const std::string filename = Common::DynamicLibrary::GetLibraryName("vulkan"); const std::string filename = Common::DynamicLibrary::GetLibraryName("vulkan");
@ -273,16 +280,14 @@ vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library,
const auto vkGetInstanceProcAddr = const auto vkGetInstanceProcAddr =
library.GetSymbol<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); library.GetSymbol<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) { if (!vkGetInstanceProcAddr) {
LOG_CRITICAL(Render_Vulkan, "Failed GetSymbol vkGetInstanceProcAddr"); throw std::runtime_error("Failed GetSymbol vkGetInstanceProcAddr");
return {};
} }
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
const auto extensions = GetInstanceExtensions(window_type, enable_validation); const auto extensions = GetInstanceExtensions(window_type, enable_validation);
const u32 available_version = vk::enumerateInstanceVersion(); const u32 available_version = vk::enumerateInstanceVersion();
if (available_version < VK_API_VERSION_1_1) { if (available_version < VK_API_VERSION_1_1) {
LOG_CRITICAL(Render_Vulkan, "Vulkan 1.0 is not supported, 1.1 is required!"); throw std::runtime_error("Vulkan 1.0 is not supported, 1.1 is required!");
return {};
} }
const vk::ApplicationInfo application_info = { const vk::ApplicationInfo application_info = {

View file

@ -13,6 +13,7 @@
namespace Frontend { namespace Frontend {
class EmuWindow; class EmuWindow;
class GraphicsContext;
enum class WindowSystemType : u8; enum class WindowSystemType : u8;
} // namespace Frontend } // namespace Frontend
@ -21,7 +22,8 @@ namespace Vulkan {
using DebugCallback = using DebugCallback =
std::variant<vk::UniqueDebugUtilsMessengerEXT, vk::UniqueDebugReportCallbackEXT>; std::variant<vk::UniqueDebugUtilsMessengerEXT, vk::UniqueDebugReportCallbackEXT>;
std::shared_ptr<Common::DynamicLibrary> OpenLibrary(); std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
[[maybe_unused]] Frontend::GraphicsContext* context = nullptr);
vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window); vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window);