From 75a81e95990eaa334291acc2d8d742dd6648b3b7 Mon Sep 17 00:00:00 2001 From: ThirteenAG Date: Thu, 9 May 2024 23:09:33 +0800 Subject: [PATCH] callback exports --- .github/workflows/sync-fork.yml | 34 ++++ .../workflows/windows_build_matrix_fork.yml | 84 ++++++++++ .github/workflows/windows_build_qt_fork.yml | 149 ++++++++++++++++++ pcsx2-qt/Settings/AdvancedSettingsWidget.cpp | 3 +- pcsx2/ImGui/ImGuiOverlays.cpp | 78 +++++++++ pcsx2/Pcsx2Config.cpp | 3 +- pcsx2/VMManager.cpp | 126 ++++++++++++++- 7 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/sync-fork.yml create mode 100644 .github/workflows/windows_build_matrix_fork.yml create mode 100644 .github/workflows/windows_build_qt_fork.yml diff --git a/.github/workflows/sync-fork.yml b/.github/workflows/sync-fork.yml new file mode 100644 index 0000000000000..e419f0fe5488c --- /dev/null +++ b/.github/workflows/sync-fork.yml @@ -0,0 +1,34 @@ +name: Merge from upstream +on: + schedule: + # scheduled for 00:00 every day + - cron: '0 0 * * *' + + workflow_dispatch: + +jobs: + merge-from-upstream-repo: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + token: ${{ secrets.SYNC_TOKEN }} + + - name: Merge from upstream repo + uses: aormsby/Fork-Sync-With-Upstream-action@main + with: + target_sync_branch: master + upstream_sync_branch: master + upstream_sync_repo: PCSX2/pcsx2 + + - name: New commits found + if: steps.sync.outputs.has_new_commits == 'true' + run: echo "New commits were found to sync." + + - name: No new commits + if: steps.sync.outputs.has_new_commits == 'false' + run: echo "There were no new commits." + + - name: Show value of 'has_new_commits' + run: echo ${{ steps.sync.outputs.has_new_commits }} diff --git a/.github/workflows/windows_build_matrix_fork.yml b/.github/workflows/windows_build_matrix_fork.yml new file mode 100644 index 0000000000000..ce33a11f8781b --- /dev/null +++ b/.github/workflows/windows_build_matrix_fork.yml @@ -0,0 +1,84 @@ +name: Fork Windows Builds + +on: + push: + branches: + - '*' + pull_request: + branches: + - master + workflow_dispatch: + +jobs: + # MSBUILD + lint_vs_proj_files: + name: Lint VS Project Files + runs-on: windows-2022 + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + - name: Verify VS Project Files + run: .github\workflows\scripts\windows\validate-vs-filters.ps1 + + build_qt_sse4: + needs: lint_vs_proj_files + name: "SSE4" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "MSVC-SSE4" + artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-msvc" + configuration: Release + simd: "SSE4" + secrets: inherit + + build_qt_avx2: + needs: lint_vs_proj_files + name: "AVX2" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "MSVC-AVX2" + artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-msvc" + configuration: Release AVX2 + secrets: inherit + + build_qt_cmake: + name: "CMake" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "CMake-MSVC" + artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-msvc" + configuration: CMake + buildSystem: cmake + secrets: inherit + + build_qt_clang_sse4: + needs: lint_vs_proj_files + name: "Clang-SSE4" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "Clang-SSE4" + artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-clang" + configuration: Release Clang + simd: "SSE4" + secrets: inherit + + build_qt_clang_avx2: + needs: lint_vs_proj_files + name: "Clang-AVX2" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "Clang-AVX2" + artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-clang" + configuration: Release Clang AVX2 + secrets: inherit + + build_qt_cmake_clang: + name: "Clang-CMake" + uses: ./.github/workflows/windows_build_qt_fork.yml + with: + jobName: "CMake-Clang" + artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-clang" + configuration: CMake + buildSystem: cmake + cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang + secrets: inherit diff --git a/.github/workflows/windows_build_qt_fork.yml b/.github/workflows/windows_build_qt_fork.yml new file mode 100644 index 0000000000000..4e2f5e7a01cff --- /dev/null +++ b/.github/workflows/windows_build_qt_fork.yml @@ -0,0 +1,149 @@ +name: Fork Windows Build Steps - Qt + +on: + workflow_call: + inputs: + jobName: + required: true + type: string + artifactPrefixName: + required: true + type: string + os: + required: false + type: string + default: windows-2022 + platform: + required: false + type: string + default: x64 + configuration: + required: true + type: string + simd: + required: false + type: string + default: AVX2 + buildSystem: + required: false + type: string + default: msbuild + cmakeFlags: + required: false + type: string + default: "" + patchesUrl: + required: false + type: string + default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download + fetchTags: + required: false + type: boolean + default: false + +jobs: + build_windows_qt: + name: ${{ inputs.jobName }} + runs-on: ${{ inputs.os }} + # Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them. + timeout-minutes: 90 + env: + POWERSHELL_TELEMETRY_OPTOUT: 1 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: recursive + + # actions/checkout elides tags, fetch them primarily for releases + - name: Fetch Tags + if: ${{ inputs.fetchTags }} + run: git fetch --tags --no-recurse-submodules + + - name: Prepare Artifact Metadata + id: artifact-metadata + shell: bash + env: + PREFIX: ${{ inputs.artifactPrefixName }} + EVENT_NAME: ${{ github.event_name }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_NUM: ${{ github.event.pull_request.number }} + PR_SHA: ${{ github.event.pull_request.head.sha }} + run: ./.github/workflows/scripts/common/name-artifacts.sh + + - name: Setup msbuild + if: inputs.configuration != 'CMake' + uses: microsoft/setup-msbuild@v1 + + - name: Download patches + shell: cmd + run: | + cd bin/resources + aria2c -Z "${{ inputs.patchesUrl }}/patches.zip" + + - name: Cache Dependencies + id: cache-deps + uses: actions/cache@v3 + with: + path: deps + key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat') }} + + - name: Build Dependencies + if: steps.cache-deps.outputs.cache-hit != 'true' + env: + DEBUG: 0 + run: .github/workflows/scripts/windows/build-dependencies.bat + + - name: Generate CMake + if: inputs.configuration == 'CMake' + id: cmake + shell: cmd + run: | + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + cmake . -B build ${{ inputs.cmakeFlags }} "-DCMAKE_PREFIX_PATH=%cd%\deps" -DQT_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DDISABLE_ADVANCE_SIMD=ON -G Ninja + + - name: Build PCSX2 + shell: cmd + run: | + if "${{ inputs.configuration }}"=="CMake" ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + cmake --build build --config Release || exit /b + cmake --install build --config Release || exit /b + ) else ( + msbuild "PCSX2_qt.sln" /m /v:m /p:Configuration="${{ inputs.configuration }}" /p:Platform="${{ inputs.platform }}" + ) + + - name: Download Plugin Injector artifact + uses: robinraju/release-downloader@v1.6 + with: + repository: "ThirteenAG/PCSX2PluginInjector" + tag: "latest" + fileName: "PCSX2PluginInjector.zip" + - name: Unpack Plugin Injector + run: | + 7z x PCSX2PluginInjector.zip -obin/ -y + del PCSX2PluginInjector.zip + - name: Pack binaries + uses: TheDoctor0/zip-release@0.7.6 + with: + path: './bin/**' + type: 'zip' + filename: PCSX2Fork-Windows-${{ inputs.platform }}-${{ inputs.jobName }}.zip + exclusions: '*.bsc *.exp *.ilk *.iobj *.ipdb *.pdb *.lib' + - name: Get release info + id: release_info + uses: cardinalby/git-get-release-action@1.2.4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag: latest + - name: Upload Release + uses: ncipollo/release-action@v1.13.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + allowUpdates: true + name: ${{ steps.release_info.outputs.name }} + body: ${{ steps.release_info.outputs.body }} + tag: ${{ steps.release_info.outputs.tag_name }} + artifacts: "*.zip" diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp index 3279b70007552..a9726ace889aa 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp @@ -87,8 +87,9 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* "end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid " "access occurred.")); - dialog->registerWidgetHelp(m_ui.extraMemory, tr("Enable 128MB RAM (Dev Console)"), tr("Unchecked"), + dialog->registerWidgetHelp(m_ui.extraMemory, tr("Enable 128MB RAM (Dev Console)"), tr("Checked"), tr("Exposes an additional 96MB of memory to the virtual machine.")); + m_ui.extraMemory->setEnabled(false); dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("VU0 Rounding Mode"), tr("Chop/Zero (Default)"), tr("Changes how PCSX2 handles rounding while emulating the Emotion Engine's Vector Unit 0 (EE VU0). " "The default value handles the vast majority of games; modifying this setting when a game is not having a visible problem will cause stability issues and/or crashes.")); diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp index 5a81630f44873..db60bac82c2ab 100644 --- a/pcsx2/ImGui/ImGuiOverlays.cpp +++ b/pcsx2/ImGui/ImGuiOverlays.cpp @@ -45,6 +45,8 @@ #include #include +extern "C" bool GetIsThrottlerTempDisabled(); + namespace ImGuiManager { static void FormatProcessorStat(SmallStringBase& text, double usage, double time); @@ -251,6 +253,9 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f else // Unlimited DRAW_LINE(standard_font, ICON_FA_FORWARD, IM_COL32(255, 255, 255, 255)); } + + if (GetIsThrottlerTempDisabled()) + DRAW_LINE(standard_font, ICON_FA_FORWARD, IM_COL32(255, 0, 0, 255)); } if (GSConfig.OsdShowFrameTimes) @@ -1071,6 +1076,10 @@ void SaveStateSelectorUI::ShowSlotOSDMessage() Host::OSD_QUICK_DURATION); } +#ifdef _WIN32 +void DrawPluginsOverlay(); +#endif + void ImGuiManager::RenderOverlays() { const float scale = ImGuiManager::GetGlobalScale(); @@ -1082,6 +1091,75 @@ void ImGuiManager::RenderOverlays() DrawPerformanceOverlay(position_y, scale, margin, spacing); DrawSettingsOverlay(scale, margin, spacing); DrawInputsOverlay(scale, margin, spacing); + +#ifdef _WIN32 + DrawPluginsOverlay(); +#endif + if (SaveStateSelectorUI::s_open) SaveStateSelectorUI::Draw(); } + +#ifdef _WIN32 +#define NOMINMAX +#include + +void DrawPluginsOverlay() +{ +#ifdef _WIN32 + auto GetPCSX2PluginInjector = []() -> HMODULE { + constexpr auto dll = L"PCSX2PluginInjector.asi"; + auto hm = GetModuleHandleW(dll); + return (hm ? hm : LoadLibraryW(dll)); + }; + auto GetOSDVectorSize = (size_t(*)())GetProcAddress(GetPCSX2PluginInjector(), "GetOSDVectorSize"); + auto GetOSDVectorData = (const char* (*)(size_t index))GetProcAddress(GetPCSX2PluginInjector(), "GetOSDVectorData"); + if (GetOSDVectorSize != NULL && GetOSDVectorData != NULL) + { + if (GetOSDVectorSize()) + { + const float scale = ImGuiManager::GetGlobalScale(); + const float shadow_offset = std::ceil(1.0f * scale); + const float margin = std::ceil(10.0f * scale); + const float spacing = std::ceil(5.0f * scale); + float position_y = margin; + + ImDrawList* dl = ImGui::GetBackgroundDrawList(); + std::string text; + ImVec2 text_size; + text.reserve(255); + +#define DRAW_LINE(font, text, color) \ + do \ + { \ + text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits::max(), -1.0f, (text), nullptr, nullptr); \ + dl->AddText(font, font->FontSize, \ + ImVec2(margin + shadow_offset, position_y + shadow_offset), \ + IM_COL32(0, 0, 0, 100), (text)); \ + dl->AddText(font, font->FontSize, ImVec2(margin, position_y), color, (text)); \ + position_y += text_size.y + spacing; \ + } while (0) + + const bool paused = (VMManager::GetState() == VMState::Paused); + + if (!paused) + { + ImFont* const fixed_font = ImGuiManager::GetFixedFont(); + for (size_t i = 0; i < GetOSDVectorSize(); i++) + { + std::string_view s(GetOSDVectorData(i), 255); + if (!s.empty() && s[0] != 0) + { + text.clear(); + fmt::format_to(std::back_inserter(text), "{}", s); + DRAW_LINE(fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255)); + } + } + } +#undef DRAW_LINE + } + } +#endif +} +#undef NOMINMAX +#endif \ No newline at end of file diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index c308903a6a936..3842b5bf01e6a 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -513,7 +513,7 @@ Pcsx2Config::CpuOptions::CpuOptions() VU0FPCR = DEFAULT_VU_FP_CONTROL_REGISTER; VU1FPCR = DEFAULT_VU_FP_CONTROL_REGISTER; AffinityControlMode = 0; - ExtraMemory = false; + ExtraMemory = true; // Forced true for now. } void Pcsx2Config::CpuOptions::ApplySanityCheck() @@ -546,6 +546,7 @@ void Pcsx2Config::CpuOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapEntry(AffinityControlMode); SettingsWrapBitBool(ExtraMemory); + ExtraMemory = true; // Forced true for now. Recompiler.LoadSave(wrap); } diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 5ef9e7e24d685..9c40d754e0308 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -200,6 +200,112 @@ static time_t s_discord_presence_time_epoch; // Making GSDumpReplayer.h dependent on R5900.h is a no-no, since the GS uses it. extern R5900cpu GSDumpReplayerCpu; +class VMEvent +{ +public: + template + class Event : public std::function + { + public: + using std::function::function; + + private: + std::vector> handlers; + + public: + void operator+=(std::function&& handler) + { + handlers.push_back(handler); + } + + void executeAll(Args... args) const + { + if (!handlers.empty()) + { + for (auto& handler : handlers) + { + handler(args...); + } + } + } + }; + +public: + static auto& onGameElfInit() + { + static Event eventEntryPointCompilingOnCPUThread; + return eventEntryPointCompilingOnCPUThread; + } + static auto& onGameShutdown() + { + static Event<> eventShutdown; + return eventShutdown; + } +}; + +extern "C" +{ +#ifdef _WIN32 +#define DLLEXPORT _declspec(dllexport) +#else +#define DLLEXPORT __attribute__((visibility("default"), used)) +#endif + + static volatile bool s_is_throttler_temp_disabled = false; + + using InitCB = void (*)( + const char* s_disc_serial, + const char* s_disc_elf, + const char* s_disc_version, + const char* s_title, + const char* s_elf_path, + const uint32_t s_disc_crc, + const uint32_t s_current_crc, + const uint32_t s_elf_entry_point, + uint8_t* EEMainMemoryStart, + size_t EEMainMemorySize, + const void* WindowHandle, + const uint32_t WindowSizeX, + const uint32_t WindowSizeY, + const bool IsFullscreen, + const AspectRatioType AspectRatioSetting); + using ShutdownCB = void (*)(); + + DLLEXPORT bool GetIsThrottlerTempDisabled(); + DLLEXPORT void SetIsThrottlerTempDisabled(bool disable); + DLLEXPORT VMState GetVMState(); + DLLEXPORT void AddOnGameElfInitCallback(InitCB callback); + DLLEXPORT void AddOnGameShutdownCallback(ShutdownCB callback); + + bool GetIsThrottlerTempDisabled() + { + return s_is_throttler_temp_disabled; + } + + void SetIsThrottlerTempDisabled(bool disable) + { + s_is_throttler_temp_disabled = disable; + } + + VMState GetVMState() + { + return VMManager::GetState(); + } + + void AddOnGameElfInitCallback(InitCB callback) + { + VMEvent::onGameElfInit() += callback; + } + + void AddOnGameShutdownCallback(ShutdownCB callback) + { + VMEvent::onGameShutdown() += callback; + } +#undef DLLEXPORT +} + bool VMManager::PerformEarlyHardwareChecks(const char** error) { #define COMMON_DOWNLOAD_MESSAGE "PCSX2 builds can be downloaded from https://pcsx2.net/downloads/" @@ -1505,6 +1611,8 @@ void VMManager::Shutdown(bool save_resume_state) // but just in case, so any of the stuff we call here knows we don't have a valid VM. s_state.store(VMState::Stopping, std::memory_order_release); + VMEvent::onGameShutdown().executeAll(); + SetTimerResolutionIncreased(false); // sync everything @@ -2072,7 +2180,7 @@ void VMManager::ResetFrameLimiter() void VMManager::Internal::Throttle() { - if (s_target_speed == 0.0f || s_use_vsync_for_timing) + if (s_target_speed == 0.0f || s_use_vsync_for_timing || GetIsThrottlerTempDisabled()) return; const u64 uExpectedEnd = @@ -2629,6 +2737,22 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread() HandleELFChange(true); + auto GetPCSX2PluginInjector = []() -> HMODULE { + constexpr auto dll = L"PCSX2PluginInjector.asi"; + auto hm = GetModuleHandleW(dll); + return (hm ? hm : LoadLibraryW(dll)); + }; + + std::ignore = GetPCSX2PluginInjector(); + + VMEvent::onGameElfInit().executeAll( + s_disc_serial.data(), s_disc_elf.data(), s_disc_version.data(), s_title.data(), + s_elf_path.data(), s_disc_crc, s_current_crc, s_elf_entry_point, + &eeMem->Main[0], Ps2MemSize::ExposedRam, &g_gs_device->GetWindowInfo().window_handle, + g_gs_device->GetWindowInfo().surface_width, g_gs_device->GetWindowInfo().surface_height, + Host::IsFullscreen(), EmuConfig.GS.AspectRatio + ); + Patch::ApplyLoadedPatches(Patch::PPT_ONCE_ON_LOAD); // If the config changes at this point, it's a reset, so the game doesn't currently know about the memcard // so there's no need to leave the eject running.