mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-22 16:40:05 +00:00
android: Custom driver code
This commit is contained in:
parent
85dd604a7e
commit
6c391971c6
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||||
|
5
externals/CMakeLists.txt
vendored
5
externals/CMakeLists.txt
vendored
@ -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
1
externals/libadrenotools
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1
|
@ -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)
|
||||||
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -15,8 +15,8 @@ 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;
|
||||||
|
@ -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));
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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_) {
|
||||||
|
@ -130,7 +130,7 @@ 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())},
|
||||||
@ -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,
|
||||||
|
@ -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()};
|
||||||
|
@ -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 = {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user