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"]
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

View File

@ -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()

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
)
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)

View File

@ -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<Common::DynamicLibrary> driver_library_)
: driver_library{driver_library_} {}
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface)
: EmuWindow_Android{surface} {
~GraphicsContext_Android() = default;
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();
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 {
return std::make_unique<SharedContext_Android>();
return std::make_unique<GraphicsContext_Android>(driver_library);
}
void EmuWindow_Android_Vulkan::StopPresenting() {

View File

@ -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<Common::DynamicLibrary> driver_library);
~EmuWindow_Android_Vulkan() override = default;
void TryPresenting() override;
@ -20,4 +21,7 @@ public:
private:
bool CreateWindowSurface() override;
private:
std::shared_ptr<Common::DynamicLibrary> driver_library;
};

View File

@ -4,13 +4,16 @@
#include <algorithm>
#include <thread>
#include <dlfcn.h>
#include <android/api-level.h>
#include <android/native_window_jni.h>
#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 <adrenotools/driver.h>
#endif
namespace {
ANativeWindow* s_surf;
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
std::unique_ptr<EmuWindow_Android> window;
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);
break;
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;
default:
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()};
@ -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<Common::DynamicLibrary>(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,

View File

@ -15,8 +15,8 @@ std::vector<QString> 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;

View File

@ -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));

View File

@ -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();

View File

@ -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<Common::DynamicLibrary> GetDriverLibrary() {
return {};
}
class Scoped {
public:
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()} {}
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<u16>(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,

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);
if (new_pipeline) {
it.value() = std::make_unique<GraphicsPipeline>(
instance, renderpass_cache, info, *pipeline_cache, *pipeline_layout, current_shaders,
&workers);
it.value() =
std::make_unique<GraphicsPipeline>(instance, renderpass_cache, info, *pipeline_cache,
*pipeline_layout, current_shaders, &workers);
}
GraphicsPipeline* const pipeline{it->second.get()};

View File

@ -95,7 +95,14 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT
}
} // 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>();
#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<PFN_vkGetInstanceProcAddr>("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 = {

View File

@ -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<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);