From d6572b2c7e4e73070aa67728a85d19d676af5065 Mon Sep 17 00:00:00 2001 From: dantmnf Date: Thu, 30 May 2024 01:56:21 +0800 Subject: [PATCH] feat: GPU acceleration (DX12/DirectML) Co-authored-by: SherkeyXD <253294679@qq.com> --- .github/workflows/ci.yml | 2 +- CMakeLists.txt | 50 ++- MaaDeps | 2 +- cmake/FindFastDeploy.cmake | 22 -- cmake/FindONNXRuntime.cmake | 20 -- cmake/fastdeploy.cmake | 50 --- cmake/macos.cmake | 8 +- maadeps-download.py | 2 +- src/MaaCore/Assistant.cpp | 3 + src/MaaCore/Config/OnnxSessions.cpp | 68 ++++ src/MaaCore/Config/OnnxSessions.h | 5 + src/MaaCore/MaaCore.vcxproj | 12 +- src/MaaMacGui | 2 +- src/MaaWpfGui/Constants/ConfigurationKeys.cs | 4 + src/MaaWpfGui/Helper/GpuOption.cs | 303 ++++++++++++++++++ src/MaaWpfGui/MaaWpfGui.csproj | 1 + src/MaaWpfGui/Main/AsstProxy.cs | 28 ++ src/MaaWpfGui/Res/Localizations/en-us.xaml | 4 + src/MaaWpfGui/Res/Localizations/zh-cn.xaml | 5 + src/MaaWpfGui/Services/MaaService.cs | 3 + .../ViewModels/UI/SettingsViewModel.cs | 64 ++-- src/MaaWpfGui/Views/UI/SettingsView.xaml | 19 +- .../ConnectSettingsUserControl.xaml | 6 - .../UserControl/PerformanceUserControl.xaml | 56 ++++ .../PerformanceUserControl.xaml.cs | 29 ++ tools/build_macos_universal.zsh | 2 +- 26 files changed, 594 insertions(+), 176 deletions(-) delete mode 100644 cmake/FindFastDeploy.cmake delete mode 100644 cmake/FindONNXRuntime.cmake delete mode 100644 cmake/fastdeploy.cmake create mode 100644 src/MaaWpfGui/Helper/GpuOption.cs create mode 100644 src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml create mode 100644 src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02e92e1c94..cbeafb6198 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -367,7 +367,7 @@ jobs: - name: Build XCFramework run: | xcodebuild -create-xcframework -library libMaaCore.dylib -headers ../include -output MaaCore.xcframework - xcodebuild -create-xcframework -library libMaaDerpLearning.dylib -output MaaDerpLearning.xcframework + xcodebuild -create-xcframework -library libfastdeploy_ppocr.dylib -output fastdeploy_ppocr.xcframework xcodebuild -create-xcframework -library libonnxruntime.*.dylib -output ONNXRuntime.xcframework xcodebuild -create-xcframework -library libopencv*.dylib -output OpenCV.xcframework working-directory: build diff --git a/CMakeLists.txt b/CMakeLists.txt index 240a7b212b..18dbbb59b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,36 +84,32 @@ find_package(cpr CONFIG REQUIRED) list(APPEND maa_libs ${OpenCV_LIBS} ZLIB::ZLIB cpr::cpr header_only_libraries) if(USE_MAADEPS) - find_package(ONNXRuntime REQUIRED) find_package(asio REQUIRED) - list(APPEND maa_libs ONNXRuntime::ONNXRuntime asio::asio) - - find_package(MaaDerpLearning REQUIRED) - list(APPEND maa_libs MaaDerpLearning) -else() - find_package(onnxruntime REQUIRED) # provided by onnxruntime>=1.16 - list(APPEND maa_libs onnxruntime::onnxruntime) - if(DEFINED fastdeploy_SOURCE_DIR) - # TODO: FetchContent github.com/MaaAssistantArknights/FastDeploy - if(NOT DEFINED fastdeploy_BINARY_DIR) - set(fastdeploy_BINARY_DIR ${CMAKE_BINARY_DIR}/fastdeploy) - endif() - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - add_subdirectory(${fastdeploy_SOURCE_DIR} ${fastdeploy_BINARY_DIR} EXCLUDE_FROM_ALL SYSTEM) - if(NOT DEFINED fastdeploy_INCLUDE_DIRS) - set(fastdeploy_INCLUDE_DIRS ${fastdeploy_SOURCE_DIR}) - endif() - get_target_property(fastdeploy_type fastdeploy_ppocr TYPE) - if(fastdeploy_type STREQUAL "SHARED_LIBRARY") - install(TARGETS fastdeploy_ppocr) - endif() - else() - find_package(fastdeploy_ppocr REQUIRED) - endif() - list(APPEND maa_libs fastdeploy_ppocr) - target_include_directories(MaaCore SYSTEM PRIVATE ${fastdeploy_INCLUDE_DIRS}) + list(APPEND maa_libs asio::asio) endif() +find_package(onnxruntime CONFIG REQUIRED) # provided by onnxruntime>=1.16 +list(APPEND maa_libs onnxruntime::onnxruntime) +if(DEFINED fastdeploy_SOURCE_DIR) + # TODO: FetchContent github.com/MaaAssistantArknights/FastDeploy + if(NOT DEFINED fastdeploy_BINARY_DIR) + set(fastdeploy_BINARY_DIR ${CMAKE_BINARY_DIR}/fastdeploy) + endif() + set(CMAKE_POSITION_INDEPENDENT_CODE ON) + add_subdirectory(${fastdeploy_SOURCE_DIR} ${fastdeploy_BINARY_DIR} EXCLUDE_FROM_ALL SYSTEM) + if(NOT DEFINED fastdeploy_INCLUDE_DIRS) + set(fastdeploy_INCLUDE_DIRS ${fastdeploy_SOURCE_DIR}) + endif() + target_include_directories(MaaCore SYSTEM PRIVATE ${fastdeploy_INCLUDE_DIRS}) + get_target_property(fastdeploy_type fastdeploy_ppocr TYPE) + if(fastdeploy_type STREQUAL "SHARED_LIBRARY") + install(TARGETS fastdeploy_ppocr) + endif() +else() + find_package(fastdeploy_ppocr REQUIRED) +endif() +list(APPEND maa_libs fastdeploy_ppocr) + target_link_libraries(MaaCore ${maa_libs}) if(WITH_EMULATOR_EXTRAS AND NOT EXISTS ${PROJECT_SOURCE_DIR}/3rdparty/EmulatorExtras/Mumu) diff --git a/MaaDeps b/MaaDeps index 1297324ea7..10d51f5832 160000 --- a/MaaDeps +++ b/MaaDeps @@ -1 +1 @@ -Subproject commit 1297324ea7be63d5488deeae29bd2ebda1e9bb7b +Subproject commit 10d51f5832f3a085331f43221082b03af58385f9 diff --git a/cmake/FindFastDeploy.cmake b/cmake/FindFastDeploy.cmake deleted file mode 100644 index 89dbc012ee..0000000000 --- a/cmake/FindFastDeploy.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# TODO: replace with cmake-generated interface file - -find_path(FastDeploy_INCLUDE_DIR NAMES fastdeploy/fastdeploy_model.h) - -find_library(FastDeploy_LIBRARY NAMES fastdeploy) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - FastDeploy - REQUIRED_VARS FastDeploy_LIBRARY FastDeploy_INCLUDE_DIR -) - -if(FastDeploy_FOUND) - set(FastDeploy_INCLUDE_DIRS ${FastDeploy_INCLUDE_DIR}) - if(NOT TARGET FastDeploy::FastDeploy) - add_library(FastDeploy::FastDeploy UNKNOWN IMPORTED) - set_target_properties(FastDeploy::FastDeploy PROPERTIES - IMPORTED_LOCATION "${FastDeploy_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${FastDeploy_INCLUDE_DIR}" - ) - endif() -endif() diff --git a/cmake/FindONNXRuntime.cmake b/cmake/FindONNXRuntime.cmake deleted file mode 100644 index c40452bddb..0000000000 --- a/cmake/FindONNXRuntime.cmake +++ /dev/null @@ -1,20 +0,0 @@ -find_path(ONNXRuntime_INCLUDE_DIR NAMES onnxruntime/core/session/onnxruntime_c_api.h) - -find_library(ONNXRuntime_LIBRARY NAMES onnxruntime) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - ONNXRuntime - REQUIRED_VARS ONNXRuntime_LIBRARY ONNXRuntime_INCLUDE_DIR -) - -if(ONNXRuntime_FOUND) - set(ONNXRuntime_INCLUDE_DIRS ${ONNXRuntime_INCLUDE_DIR}) - if(NOT TARGET ONNXRuntime::ONNXRuntime) - add_library(ONNXRuntime::ONNXRuntime UNKNOWN IMPORTED) - set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES - IMPORTED_LOCATION "${ONNXRuntime_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${ONNXRuntime_INCLUDE_DIR}" - ) - endif() -endif() \ No newline at end of file diff --git a/cmake/fastdeploy.cmake b/cmake/fastdeploy.cmake deleted file mode 100644 index 1a4f6138c5..0000000000 --- a/cmake/fastdeploy.cmake +++ /dev/null @@ -1,50 +0,0 @@ - - -set(FASTDEPLOY_URL_PREFIX "https://github.com/MaaAssistantArknights/build-fastdeploy/releases/download") - -set(FASTDEPLOY_TAG "gac255b8a") - -set(COMPRESSED_SUFFIX ".tar.gz") - -if(WIN32) - set(FASTDEPLOY_FILENAME "FastDeploy-Windows") - set(FASTDEPLOY_CHECKSUM "0a0700d4e8923bcd4c387a658e5e9a689ed9e0d114c260b11d082a2176c233d4") -elseif(APPLE) - if (CURRENT_OSX_ARCH STREQUAL "arm64") - set(FASTDEPLOY_FILENAME "FastDeploy-macOS-arm64") - set(FASTDEPLOY_CHECKSUM "28a771814d197ba8056f1fcb7cc0671facec90a8733a0dac2cf0b68a8cc36d24") - else() - set(FASTDEPLOY_FILENAME "FastDeploy-macOS-x86_64") - set(FASTDEPLOY_CHECKSUM "76e97c7e944a18eb160646fa32ac0a7e24c87751b2b127dc33454f993f6d4b97") - endif() -else() - set(FASTDEPLOY_FILENAME "FastDeploy-Linux") - set(FASTDEPLOY_CHECKSUM "4d106e5499e9b5b29426667617215ac7e4e70d2353af10caccdfdf6c1f1534a7") -endif(WIN32) - -set(FASTDEPLOY_URL ${FASTDEPLOY_URL_PREFIX}/${FASTDEPLOY_TAG}/${FASTDEPLOY_FILENAME}${COMPRESSED_SUFFIX}) - -if (FASTDEPLOY_DIRECTORY) - set(FastDeploy_DIR ${FASTDEPLOY_DIRECTORY}) - find_package(FastDeploy REQUIRED PATHS ${FastDeploy_DIR}) - include_directories(${FastDeploy_INCLUDE_DIRS}) - list(APPEND DEPEND_LIBS ${FastDeploy_LIBS}) -else () - download_and_decompress(${FASTDEPLOY_URL} - ${CMAKE_CURRENT_BINARY_DIR}/${FASTDEPLOY_FILENAME}${COMPRESSED_SUFFIX} - ${FASTDEPLOY_CHECKSUM} - ${THIRD_PARTY_PATH}/install/) - set(FASTDEPLOY_FILENAME fastdeploy) - set(FastDeploy_DIR ${THIRD_PARTY_PATH}/install/${FASTDEPLOY_FILENAME}) - - find_package(FastDeploy REQUIRED PATHS ${FastDeploy_DIR} NO_DEFAULT_PATH) - include_directories(${FastDeploy_INCLUDE_DIRS}) - list(APPEND DEPEND_LIBS ${FastDeploy_LIBS}) -endif (FASTDEPLOY_DIRECTORY) - -if (INSTALL_THIRD_LIBS) - install(DIRECTORY ${FastDeploy_DIR}/lib/ DESTINATION . USE_SOURCE_PERMISSIONS) - install(DIRECTORY ${ORT_LIB_PATH}/ DESTINATION . USE_SOURCE_PERMISSIONS) - install(DIRECTORY ${FastDeploy_DIR}/third_libs/install/paddle2onnx/lib/ - DESTINATION . USE_SOURCE_PERMISSIONS) -endif (INSTALL_THIRD_LIBS) diff --git a/cmake/macos.cmake b/cmake/macos.cmake index 0a52c2daf0..b3986a87bb 100644 --- a/cmake/macos.cmake +++ b/cmake/macos.cmake @@ -15,13 +15,13 @@ if (BUILD_XCFRAMEWORK) COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libonnxruntime.1.14.1.dylib" -output ONNXRuntime.xcframework ) - add_custom_command(OUTPUT MaaDerpLearning.xcframework - COMMAND rm -rf MaaDerpLearning.xcframework - COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libMaaDerpLearning.dylib" -output MaaDerpLearning.xcframework + add_custom_command(OUTPUT fastdeploy_ppocr.xcframework + COMMAND rm -rf fastdeploy_ppocr.xcframework + COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libfastdeploy_ppocr.dylib" -output fastdeploy_ppocr.xcframework ) add_custom_target(MaaXCFramework ALL - DEPENDS MaaCore MaaCore.xcframework OpenCV.xcframework ONNXRuntime.xcframework MaaDerpLearning.xcframework + DEPENDS MaaCore MaaCore.xcframework OpenCV.xcframework ONNXRuntime.xcframework fastdeploy_ppocr.xcframework ) endif (BUILD_XCFRAMEWORK) diff --git a/maadeps-download.py b/maadeps-download.py index bb41779cd4..a8f10bfaaf 100644 --- a/maadeps-download.py +++ b/maadeps-download.py @@ -8,7 +8,7 @@ import time from pathlib import Path import shutil -TARGET_TAG = "2023-04-24-3" +TARGET_TAG = "2024-05-30" basedir = Path(__file__).parent def detect_host_triplet(): diff --git a/src/MaaCore/Assistant.cpp b/src/MaaCore/Assistant.cpp index 87ed11a1a1..5194a447f0 100644 --- a/src/MaaCore/Assistant.cpp +++ b/src/MaaCore/Assistant.cpp @@ -6,6 +6,7 @@ #include "Config/GeneralConfig.h" #include "Config/Miscellaneous/OcrPack.h" +#include "Config/OnnxSessions.h" #include "Config/ResourceLoader.h" #include "Controller/Controller.h" #include "Status.h" @@ -40,12 +41,14 @@ bool ::AsstExtAPI::set_static_option(StaticOptionKey key, const std::string& val case StaticOptionKey::CpuOCR: { WordOcr::get_instance().use_cpu(); CharOcr::get_instance().use_cpu(); + OnnxSessions::get_instance().use_cpu(); return true; } break; case StaticOptionKey::GpuOCR: { int device_id = std::stoi(value); WordOcr::get_instance().use_gpu(device_id); CharOcr::get_instance().use_gpu(device_id); + OnnxSessions::get_instance().use_gpu(device_id); return true; } break; default: diff --git a/src/MaaCore/Config/OnnxSessions.cpp b/src/MaaCore/Config/OnnxSessions.cpp index 249fbc6251..33e8ae4747 100644 --- a/src/MaaCore/Config/OnnxSessions.cpp +++ b/src/MaaCore/Config/OnnxSessions.cpp @@ -6,6 +6,16 @@ #include "Utils/Logger.hpp" +#if __has_include() +#define WITH_DML +#include +#endif + +#if __has_include() +#define WITH_COREML +#include +#endif + bool asst::OnnxSessions::load(const std::filesystem::path& path) { LogTraceFunction; @@ -30,3 +40,61 @@ Ort::Session& asst::OnnxSessions::get(const std::string& name) } return m_sessions.at(name); } + +bool asst::OnnxSessions::use_cpu() +{ + if (m_sessions.size() != 0) return false; + m_options = Ort::SessionOptions(); + gpu_enabled = false; + return true; +} + +bool asst::OnnxSessions::use_gpu(int device_id) +{ + if (gpu_enabled) return true; + if (m_sessions.size() != 0) return false; + auto all_providers = Ort::GetAvailableProviders(); + bool support_cuda = false; + bool support_dml = false; + bool support_coreml = false; + for (const auto& provider : all_providers) { + if (provider == "CUDAExecutionProvider") { + support_cuda = true; + } + if (provider == "DmlExecutionProvider") { + support_dml = true; + } + if (provider == "CoreMLExecutionProvider") { + support_coreml = true; + } + } + + bool any_gpu = support_cuda || support_dml || support_coreml; + + if (support_cuda) { + OrtCUDAProviderOptions cuda_options; + cuda_options.device_id = device_id; + m_options.AppendExecutionProvider_CUDA(cuda_options); + } +#ifdef WITH_DML + else if (support_dml) { + if (!Ort::Status(OrtSessionOptionsAppendExecutionProvider_DML(m_options, device_id)).IsOK()) { + return false; + } + } +#endif +#ifdef WITH_COREML + else if (support_coreml) { + if (!Ort::Status(OrtSessionOptionsAppendExecutionProvider_CoreML((OrtSessionOptions*)m_options, 0)).IsOK()) { + return false; + } + } +#endif + if (!any_gpu) { + Log.error(__FUNCTION__, "No GPU execution provider available"); + return false; + } + + gpu_enabled = true; + return true; +} diff --git a/src/MaaCore/Config/OnnxSessions.h b/src/MaaCore/Config/OnnxSessions.h index c03f1e631f..9fea15c76b 100644 --- a/src/MaaCore/Config/OnnxSessions.h +++ b/src/MaaCore/Config/OnnxSessions.h @@ -6,6 +6,8 @@ #if __has_include() #include +#elif __has_include() +#include #else #include #endif @@ -19,11 +21,14 @@ namespace asst virtual bool load(const std::filesystem::path& path) override; Ort::Session& get(const std::string& name); + bool use_cpu(); + bool use_gpu(int device_id); private: Ort::Env m_env; Ort::SessionOptions m_options; std::unordered_map m_sessions; std::unordered_map m_model_paths; + bool gpu_enabled; }; } diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj index f4d7dd1fa4..42c4ae01d5 100644 --- a/src/MaaCore/MaaCore.vcxproj +++ b/src/MaaCore/MaaCore.vcxproj @@ -521,7 +521,7 @@ true true true - MaaDerpLearning.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator true /ignore:4286 %(AdditionalOptions) @@ -568,7 +568,7 @@ true true true - MaaDerpLearning.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator true /ignore:4286 %(AdditionalOptions) @@ -619,7 +619,7 @@ true true true - MaaDerpLearning.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator true /ignore:4286 %(AdditionalOptions) @@ -673,7 +673,7 @@ true - MaaDerpLearning.lib;opencv_world4d.lib;zlibd.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl-d.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4d.lib;zlibd.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl-d.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator @@ -724,7 +724,7 @@ true true true - MaaDerpLearning.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator true /ignore:4286 %(AdditionalOptions) @@ -777,7 +777,7 @@ true - MaaDerpLearning.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) + fastdeploy_ppocr.lib;opencv_world4.lib;zlib.lib;ws2_32.lib;onnxruntime.lib;cpr.lib;libcurl.lib;crypt32.lib;%(AdditionalDependencies) RequireAdministrator diff --git a/src/MaaMacGui b/src/MaaMacGui index 3c1787a511..b3553eee75 160000 --- a/src/MaaMacGui +++ b/src/MaaMacGui @@ -1 +1 @@ -Subproject commit 3c1787a5118723a9da653a7bd48732e2f8edefab +Subproject commit b3553eee75fa199d15baaf5a204c9b6f70a8a60f diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index ece91e3146..9b95d39299 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -231,6 +231,10 @@ namespace MaaWpfGui.Constants public const string ExternalNotificationBarkSendKey = "ExternalNotification.Bark.SendKey"; public const string ExternalNotificationBarkServer = "ExternalNotification.Bark.Server"; + public const string PerformanceUseGpu = "Performance.UseGpu"; + public const string PerformancePreferredGpuDescription = "Performance.PreferredGpuDescription"; + public const string PerformancePreferredGpuInstancePath = "Performance.PreferredGpuInstancePath"; + // The following should not be modified manually public const string VersionName = "VersionUpdate.name"; diff --git a/src/MaaWpfGui/Helper/GpuOption.cs b/src/MaaWpfGui/Helper/GpuOption.cs new file mode 100644 index 0000000000..13a7e606db --- /dev/null +++ b/src/MaaWpfGui/Helper/GpuOption.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using DirectN; +using MaaWpfGui.Constants; +using Microsoft.Win32; + +namespace MaaWpfGui.Helper +{ + public abstract class GpuOption + { + public static GpuOption Disable => DisableOption.Instance; + + public static GpuOption SystemDefault => SystemDefaultOption.Instance; + + private static readonly List _unavailableOptions = [Disable]; + + private static IDXGIFactory4? GetDxgiFactory() + { + var hr = DXGIFunctions.CreateDXGIFactory2(0, typeof(IDXGIFactory4).GUID, out var comobj); + if (!hr.IsSuccess) + { + return null; + } + + return (IDXGIFactory4)comobj; + } + + public static List GetGpuOptions() + { + var factory = GetDxgiFactory(); + + if (factory == null) + { + return _unavailableOptions; + } + + uint i = 0; + + var options = new List() + { + Disable, + SystemDefault, + }; + + while (true) + { + IDXGIAdapter1 adapter; + var hr = factory.EnumAdapters1(i, out adapter); + if (hr == HRESULTS.DXGI_ERROR_NOT_FOUND) + { + break; + } + + var index = i; + i++; + + var desc = adapter.GetDesc1(); + + if ((desc.Flags & (uint)DXGI_ADAPTER_FLAG.DXGI_ADAPTER_FLAG_SOFTWARE) != 0) + { + // skip software device + continue; + } + + if (!CheckD3D12Support(adapter)) + { + // skip adapters without D3D12 support + continue; + } + + var instance_path = GetAdapterInstancePath((ulong)desc.AdapterLuid.Value); + + if (instance_path != null && IsIndirectDisplayAdapter(instance_path)) + { + // skip virtual adapters (streaming/RDP) + continue; + } + + options.Add(new SpecificGpuOption(index, desc, instance_path ?? string.Empty)); + } + + if (i == 0) + { + return _unavailableOptions; + } + + // show index if multiple adapters with same name installed + var counter = new Dictionary(); + foreach (var option in options.OfType()) + { + counter[option.Description] = counter.GetValueOrDefault(option.Description, 0) + 1; + } + + foreach (var option in options.OfType()) + { + if (counter.GetValueOrDefault(option.Description, 0) > 1) + { + option.ShowIndex = true; + } + } + + return options; + } + + private static bool CheckD3D12Support(IDXGIAdapter1 adapter) + { + // using the same feature level as onnxruntime does + var hr = D3D12Functions.D3D12CheckDeviceCreate(adapter, D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_11_0); + + return hr == HRESULTS.S_FALSE; + } + + private static string? GetAdapterInstancePath(ulong luid) + { + try + { + var adpname = Vanara.PInvoke.User32.DisplayConfigGetDeviceInfo(luid, 0, Vanara.PInvoke.Gdi32.DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME); + + var interface_path = adpname.adapterDevicePath; + + var interface_guid_pos = interface_path.LastIndexOf('#'); + if (interface_guid_pos == -1) + { + return null; + } + + return interface_path[4..interface_guid_pos].Replace('#', '\\'); + } + catch + { + return null; + } + } + + private static bool IsIndirectDisplayAdapter(string instance_path) + { + try + { + using var regkey = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum\\" + instance_path, false); + + if (regkey == null) + { + return false; + } + + var upperfilters = regkey.GetValue("UpperFilters"); + + if (upperfilters == null) + { + return false; + } + + if (upperfilters is string[] sa) + { + return sa.Any(s => s.Equals("IndirectKmd", StringComparison.InvariantCultureIgnoreCase)); + } + } + catch + { + // ignore + } + + return false; + } + + public static GpuOption GetCurrent() + { + bool.TryParse(ConfigurationHelper.GetValue(ConfigurationKeys.PerformanceUseGpu, "false"), out var useGpu); + var preferredGpuInstancePath = ConfigurationHelper.GetValue(ConfigurationKeys.PerformancePreferredGpuInstancePath, string.Empty); + var preferredGpuDescription = ConfigurationHelper.GetValue(ConfigurationKeys.PerformancePreferredGpuDescription, string.Empty); + + GpuOption result; + if (useGpu) + { + var options = GetGpuOptions(); + if (ReferenceEquals(options, _unavailableOptions)) + { + result = Disable; + } + + result = SystemDefault; + if (preferredGpuInstancePath != string.Empty) + { + result = options.OfType().FirstOrDefault(x => string.Equals(((SpecificGpuOption)x).InstancePath, preferredGpuInstancePath, StringComparison.Ordinal), SystemDefault); + } + + if (result == SystemDefault && preferredGpuDescription != string.Empty) + { + // instance path lookup failed, fallback to description (name) lookup + result = options.OfType().FirstOrDefault(x => string.Equals(((SpecificGpuOption)x).Description, preferredGpuDescription, StringComparison.OrdinalIgnoreCase), SystemDefault); + } + } + else + { + result = Disable; + } + + return result; + } + + public static void SetCurrent(GpuOption option) + { + switch (option) + { + case DisableOption _: + ConfigurationHelper.SetValue(ConfigurationKeys.PerformanceUseGpu, "false"); + break; + case SystemDefaultOption _: + ConfigurationHelper.SetValue(ConfigurationKeys.PerformanceUseGpu, "true"); + ConfigurationHelper.SetValue(ConfigurationKeys.PerformancePreferredGpuDescription, string.Empty); + ConfigurationHelper.SetValue(ConfigurationKeys.PerformancePreferredGpuInstancePath, string.Empty); + break; + case SpecificGpuOption x: + ConfigurationHelper.SetValue(ConfigurationKeys.PerformanceUseGpu, "true"); + ConfigurationHelper.SetValue(ConfigurationKeys.PerformancePreferredGpuDescription, x.Description); + ConfigurationHelper.SetValue(ConfigurationKeys.PerformancePreferredGpuInstancePath, x.InstancePath); + break; + default: + break; + } + } + + public class DisableOption : GpuOption + { + public static DisableOption Instance { get; } = new DisableOption(); + + private DisableOption() { } + + public override bool Equals(object? obj) + { + return obj is DisableOption; + } + + public override int GetHashCode() => typeof(DisableOption).GetHashCode(); + + public override string ToString() => LocalizationHelper.GetString("GpuOptionDisable"); + } + + public abstract class EnableOption : GpuOption + { + public abstract uint Index { get; } + } + + public class SystemDefaultOption : EnableOption + { + public static SystemDefaultOption Instance { get; } = new SystemDefaultOption(); + + private SystemDefaultOption() { } + + public override uint Index => 0; + + public override bool Equals(object? obj) + { + return obj is SystemDefaultOption; + } + + public override int GetHashCode() => typeof(SystemDefaultOption).GetHashCode(); + + public override string ToString() => LocalizationHelper.GetString("GpuOptionSystemDefault"); + } + + public class SpecificGpuOption : EnableOption + { + private DXGI_ADAPTER_DESC1 _description; + private uint _index; + private string _instance_path; + + public bool ShowIndex { get; set; } + + public SpecificGpuOption(uint index, DXGI_ADAPTER_DESC1 description, string instance_path) + { + _index = index; + _description = description; + _instance_path = instance_path; + } + + public override uint Index => _index; + + public string Description => _description.Description; + + public string InstancePath => _instance_path; + + public override bool Equals(object? obj) + { + if (obj is SpecificGpuOption x) + { + return x._description.AdapterLuid.Value == _description.AdapterLuid.Value; + } + + return false; + } + + public override int GetHashCode() => (typeof(SpecificGpuOption), _description, _index, _instance_path).GetHashCode(); + + public override string ToString() => ShowIndex ? _description + $" (GPU {_index})" : _description.Description; + } + } +} diff --git a/src/MaaWpfGui/MaaWpfGui.csproj b/src/MaaWpfGui/MaaWpfGui.csproj index 60465735ef..633ee49365 100644 --- a/src/MaaWpfGui/MaaWpfGui.csproj +++ b/src/MaaWpfGui/MaaWpfGui.csproj @@ -89,6 +89,7 @@ + diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 1297bdff41..573140c19f 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -259,6 +259,11 @@ namespace MaaWpfGui.Main /// public void Init() { + if (GpuOption.GetCurrent() is GpuOption.EnableOption x) + { + AsstSetStaticOption(AsstStaticOptionKey.GpuOCR, x.Index.ToString()); + } + bool loaded = LoadResource(); _handle = MaaService.AsstCreateEx(_callback, AsstHandle.Zero); @@ -1597,6 +1602,11 @@ namespace MaaWpfGui.Main return AsstSetInstanceOption(_handle, (AsstInstanceOptionKey)key, value); } + public bool AsstSetStaticOption(AsstStaticOptionKey key, string value) + { + return MaaService.AsstSetStaticOption(key, value); + } + private static readonly bool _forcedReloadResource = File.Exists("DEBUG") || File.Exists("DEBUG.txt"); /// @@ -2632,6 +2642,24 @@ namespace MaaWpfGui.Main SubTaskStopped, } + public enum AsstStaticOptionKey + { + /// + /// 无效 + /// + Invalid, + + /// + /// 用CPU进行OCR + /// + CpuOCR, + + /// + /// 用GPU进行OCR + /// + GpuOCR, + } + public enum InstanceOptionKey { /* Deprecated */ // MinitouchEnabled = 1, diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index a838e5c388..08f050eecc 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -6,6 +6,7 @@ Settings General Advanced + Performance Client Base I.S. @@ -47,6 +48,9 @@ User ID Bot Token Chat ID + Use GPU for inference acceleration + Don’t use + System default GPU Task Settings Settings Guide diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 56fdcf423d..4da42f10f9 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -6,6 +6,7 @@ 设置 常规设置 高级设置 + 性能设置 游戏设置 基建设置 肉鸽设置 @@ -47,6 +48,10 @@ 用户 ID 机器人 Token 聊天 ID + 使用 GPU 加速推理 + 不使用 + 系统默认 GPU + 任务设置 设置指引 diff --git a/src/MaaWpfGui/Services/MaaService.cs b/src/MaaWpfGui/Services/MaaService.cs index 4e8b008f76..0843f86e81 100644 --- a/src/MaaWpfGui/Services/MaaService.cs +++ b/src/MaaWpfGui/Services/MaaService.cs @@ -36,6 +36,9 @@ namespace MaaWpfGui.Services [DllImport("MaaCore.dll")] public static extern unsafe bool AsstSetInstanceOption(AsstHandle handle, AsstInstanceOptionKey key, byte* value); + [DllImport("MaaCore.dll")] + public static extern unsafe bool AsstSetStaticOption(AsstStaticOptionKey key, [MarshalAs(UnmanagedType.LPUTF8Str)] string value); + [DllImport("MaaCore.dll")] public static extern unsafe bool AsstLoadResource(byte* dirname); diff --git a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs index 8deeb2a1ac..72024eb6db 100644 --- a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs @@ -565,10 +565,27 @@ namespace MaaWpfGui.ViewModels.UI #endregion External Notifications + #region Performance + + public List GpuOptions => GpuOption.GetGpuOptions(); + + public GpuOption ActiveGpuOption + { + get => GpuOption.GetCurrent(); + set + { + GpuOption.SetCurrent(value); + AskRestartToApplySettings(); + } + } + + #endregion Performance + private List _listTitle = [ LocalizationHelper.GetString("SwitchConfiguration"), LocalizationHelper.GetString("ScheduleSettings"), + LocalizationHelper.GetString("PerformanceSettings"), LocalizationHelper.GetString("GameSettings"), LocalizationHelper.GetString("ConnectionSettings"), LocalizationHelper.GetString("StartupSettings"), @@ -1237,15 +1254,7 @@ namespace MaaWpfGui.ViewModels.UI Instances.TaskQueueViewModel.UpdateStageList(true); Instances.TaskQueueViewModel.UpdateDatePrompt(); Instances.AsstProxy.LoadResource(); - var result = MessageBoxHelper.Show( - LocalizationHelper.GetString("PromptRestartForSettingsChange"), - LocalizationHelper.GetString("Tip"), - MessageBoxButton.OKCancel, - MessageBoxImage.Question); - if (result == MessageBoxResult.OK) - { - Bootstrapper.ShutdownAndRestartWithoutArgs(); - } + AskRestartToApplySettings(); } } @@ -2555,7 +2564,6 @@ namespace MaaWpfGui.ViewModels.UI /// /// Gets or sets a value indicating whether to collect special access rewards. /// - public bool ReceiveSpecialAccess { get => _receiveReceiveSpecialAccess; @@ -3798,15 +3806,7 @@ namespace MaaWpfGui.ViewModels.UI SetAndNotify(ref _touchMode, value); UpdateInstanceSettings(); ConfigurationHelper.SetValue(ConfigurationKeys.TouchMode, value); - var result = MessageBoxHelper.Show( - LocalizationHelper.GetString("PromptRestartForSettingsChange"), - LocalizationHelper.GetString("Tip"), - MessageBoxButton.OKCancel, - MessageBoxImage.Question); - if (result == MessageBoxResult.OK) - { - Bootstrapper.ShutdownAndRestartWithoutArgs(); - } + AskRestartToApplySettings(); } } @@ -4173,15 +4173,7 @@ namespace MaaWpfGui.ViewModels.UI SwitchDarkMode(); /* - var result = MessageBoxHelper.Show( - LocalizationHelper.GetString("PromptRestartForSettingsChange"), - LocalizationHelper.GetString("Tip"), - MessageBoxButton.OKCancel, - MessageBoxImage.Question); - if (result == MessageBoxResult.OK) - { - Bootstrapper.ShutdownAndRestartWithOutArgs(); - } + AskToRestartToApplySettings(); */ } } @@ -4652,6 +4644,22 @@ namespace MaaWpfGui.ViewModels.UI #endregion SettingsGuide + /// + /// 要求用户重启以应用设置 + /// + private void AskRestartToApplySettings() + { + var result = MessageBoxHelper.Show( + LocalizationHelper.GetString("PromptRestartForSettingsChange"), + LocalizationHelper.GetString("Tip"), + MessageBoxButton.OKCancel, + MessageBoxImage.Question); + if (result == MessageBoxResult.OK) + { + Bootstrapper.ShutdownAndRestartWithoutArgs(); + } + } + /// /// Make comboBox searchable /// diff --git a/src/MaaWpfGui/Views/UI/SettingsView.xaml b/src/MaaWpfGui/Views/UI/SettingsView.xaml index 445cbf3c84..0c2d2ad4b2 100644 --- a/src/MaaWpfGui/Views/UI/SettingsView.xaml +++ b/src/MaaWpfGui/Views/UI/SettingsView.xaml @@ -52,36 +52,39 @@ + + + - + - + - + - + - + - + - + - + diff --git a/src/MaaWpfGui/Views/UserControl/ConnectSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/ConnectSettingsUserControl.xaml index 49fb1e9f3e..68a90207e4 100644 --- a/src/MaaWpfGui/Views/UserControl/ConnectSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/ConnectSettingsUserControl.xaml @@ -306,11 +306,5 @@ IsChecked="{Binding BlockSleepWithScreenOn}" Visibility="{c:Binding BlockSleep}" /> - diff --git a/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml b/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml new file mode 100644 index 0000000000..9dd2feaf64 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + diff --git a/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml.cs b/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml.cs new file mode 100644 index 0000000000..42f45d64e4 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/PerformanceUserControl.xaml.cs @@ -0,0 +1,29 @@ +// +// MaaWpfGui - A part of the MaaCoreArknights project +// Copyright (C) 2021 MistEO and Contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License v3.0 only as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY +// + +namespace MaaWpfGui.Views.UserControl +{ + /// + /// GameClientUserControl.xaml 的交互逻辑 + /// + public partial class PerformanceUserControl : System.Windows.Controls.UserControl + { + /// + /// Initializes a new instance of the class. + /// + public PerformanceUserControl() + { + InitializeComponent(); + } + } +} diff --git a/tools/build_macos_universal.zsh b/tools/build_macos_universal.zsh index 3b8d77ce0f..f430a92e4e 100755 --- a/tools/build_macos_universal.zsh +++ b/tools/build_macos_universal.zsh @@ -23,7 +23,7 @@ done pushd build xcodebuild -create-xcframework -library libMaaCore.dylib -headers ../include -output MaaCore.xcframework -xcodebuild -create-xcframework -library libMaaDerpLearning.dylib -output MaaDerpLearning.xcframework +xcodebuild -create-xcframework -library libfastdeploy_ppocr.dylib -output fastdeploy_ppocr.xcframework xcodebuild -create-xcframework -library libonnxruntime.*.dylib -output ONNXRuntime.xcframework xcodebuild -create-xcframework -library libopencv*.dylib -output OpenCV.xcframework rm -rf *.dylib