android: Custom driver code
This commit is contained in:
parent
85dd604a7e
commit
6c391971c6
15 changed files with 118 additions and 26 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -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
|
||||
|
|
5
externals/CMakeLists.txt
vendored
5
externals/CMakeLists.txt
vendored
|
@ -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
1
externals/libadrenotools
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1
|
|
@ -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)
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -15,9 +15,9 @@ 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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_) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()};
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue