From 03484d214678cd5e442f196bbfc38b79c53509f9 Mon Sep 17 00:00:00 2001 From: Cemu-Language CI Date: Wed, 28 Aug 2024 09:05:50 +0000 Subject: [PATCH 1/9] Update translation files --- bin/resources/fr/cemu.mo | Bin 72178 -> 73978 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/resources/fr/cemu.mo b/bin/resources/fr/cemu.mo index 8328991f01eb915b5ea722452ccefde985d6416c..f3f3b49871a8078edf991f90f995d71f14e80f94 100644 GIT binary patch delta 25041 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

6St{+jX!tOk4R)*ctg7C=)jM%9y?j)W}9dO-(+O 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 delta 23379 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 From 9a53b19403d4fea5861bcdf115a673d801759245 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:06:49 -0700 Subject: [PATCH 2/9] CI+build: Improve macOS builds (#1310) --- .github/workflows/build.yml | 20 +++++------- BUILD.md | 50 ++++++++++++++++++------------ CMakeLists.txt | 1 + dependencies/ih264d/CMakeLists.txt | 12 +++++-- src/asm/CMakeLists.txt | 12 +++++-- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd28ceb..72bbcf5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -176,7 +176,7 @@ jobs: path: ./bin/Cemu.exe build-macos: - runs-on: macos-12 + runs-on: macos-14 steps: - name: "Checkout repo" uses: actions/checkout@v4 @@ -198,17 +198,14 @@ jobs: - name: "Install system dependencies" run: | brew update - brew install llvm@15 ninja nasm automake libtool - brew install cmake ninja + brew install ninja nasm automake libtool - - name: "Build and install molten-vk" + - name: "Install molten-vk" run: | - git clone https://github.com/KhronosGroup/MoltenVK.git - cd MoltenVK - git checkout bf097edc74ec3b6dfafdcd5a38d3ce14b11952d6 - ./fetchDependencies --macos - make macos - make install + curl -L -O https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.9/MoltenVK-macos.tar + tar xf MoltenVK-macos.tar + sudo mkdir -p /usr/local/lib + sudo cp MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib /usr/local/lib - name: "Setup cmake" uses: jwlawson/actions-setup-cmake@v2 @@ -239,9 +236,8 @@ jobs: cd build cmake .. ${{ env.BUILD_FLAGS }} \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \ + -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DMACOS_BUNDLE=ON \ - -DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \ - -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++ \ -G Ninja - name: "Build Cemu" diff --git a/BUILD.md b/BUILD.md index 1e92527..44d69c6 100644 --- a/BUILD.md +++ b/BUILD.md @@ -16,11 +16,11 @@ - [Compiling Errors](#compiling-errors) - [Building Errors](#building-errors) - [macOS](#macos) - - [On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used](#on-apple-silicon-macs-rosetta-2-and-the-x86_64-version-of-homebrew-must-be-used) - [Installing brew](#installing-brew) - - [Installing Dependencies](#installing-dependencies) - - [Build Cemu using CMake and Clang](#build-cemu-using-cmake-and-clang) - - [Updating Cemu and source code](#updating-cemu-and-source-code) + - [Installing Tool Dependencies](#installing-tool-dependencies) + - [Installing Library Dependencies](#installing-library-dependencies) + - [Build Cemu using CMake](#build-cemu-using-cmake) +- [Updating Cemu and source code](#updating-cemu-and-source-code) ## Windows @@ -141,31 +141,41 @@ If you are getting a different error than any of the errors listed above, you ma ## macOS -To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and -below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. The OpenGL graphics -API isn't support on macOS, Vulkan must be used. Additionally Vulkan must be used through the -Molten-VK compatibility layer - -### On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used - -You can skip this section if you have an Intel Mac. Every time you compile, you need to perform steps 2. - -1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once -2. `arch -x86_64 zsh` # run an x64 shell +To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and below +don't support the C++20 feature set required, so either install LLVM from Homebrew or make sure that +you have a recent enough version of Xcode. Xcode 15 is known to work. The OpenGL graphics API isn't +supported on macOS, so Vulkan must be used through the Molten-VK compatibility layer. ### Installing brew 1. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` -2. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` # set x86_64 brew env +2. Set up the Homebrew shell environment: + 1. **On an Intel Mac:** `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` + 2. **On an Apple Silicon Mac:** eval `"$(/opt/homebrew/bin/brew shellenv)"` -### Installing Dependencies +### Installing Tool Dependencies -`brew install boost git cmake llvm ninja nasm molten-vk automake libtool` +The native versions of these can be used regardless of what type of Mac you have. + +`brew install git cmake ninja nasm automake libtool` + +### Installing Library Dependencies + +**On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used to install these dependencies:** +1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once +2. `arch -x86_64 zsh` # run an x64 shell +3. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` +4. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` + +Then install the dependencies: + +`brew install boost molten-vk` + +### Build Cemu using CMake -### Build Cemu using CMake and Clang 1. `git clone --recursive https://github.com/cemu-project/Cemu` 2. `cd Cemu` -3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -G Ninja` +3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_OSX_ARCHITECTURES=x86_64 -G Ninja` 4. `cmake --build build` 5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`. diff --git a/CMakeLists.txt b/CMakeLists.txt index 80ac6cf..54e2012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ endif() if (APPLE) enable_language(OBJC OBJCXX) + set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0") endif() if (UNIX AND NOT APPLE) diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index d97d6dd..686a9d0 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -117,7 +117,13 @@ add_library (ih264d "decoder/ivd.h" ) -if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") +if (CMAKE_OSX_ARCHITECTURES) +set(IH264D_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) +else() +set(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +endif() + +if (IH264D_ARCHITECTURE STREQUAL "x86_64" OR IH264D_ARCHITECTURE STREQUAL "amd64" OR IH264D_ARCHITECTURE STREQUAL "AMD64") set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86") include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES}) target_sources(ih264d PRIVATE @@ -140,7 +146,7 @@ target_sources(ih264d PRIVATE "decoder/x86/ih264d_function_selector_sse42.c" "decoder/x86/ih264d_function_selector_ssse3.c" ) -elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") +elseif(IH264D_ARCHITECTURE STREQUAL "aarch64" OR IH264D_ARCHITECTURE STREQUAL "arm64") enable_language( C CXX ASM ) set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm") include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES}) @@ -178,7 +184,7 @@ target_sources(ih264d PRIVATE ) target_compile_options(ih264d PRIVATE -DARMV8) else() -message(FATAL_ERROR "ih264d unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}") +message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}") endif() if(MSVC) diff --git a/src/asm/CMakeLists.txt b/src/asm/CMakeLists.txt index 5d9f84c..19a7ddd 100644 --- a/src/asm/CMakeLists.txt +++ b/src/asm/CMakeLists.txt @@ -1,6 +1,12 @@ project(CemuAsm C) -if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") +if (CMAKE_OSX_ARCHITECTURES) + set(CEMU_ASM_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) +else() + set(CEMU_ASM_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +endif() + +if (CEMU_ASM_ARCHITECTURE MATCHES "(x86)|(X86)|(amd64)|(AMD64)") if (WIN32) @@ -40,8 +46,8 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") endif() -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") +elseif(CEMU_ASM_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") add_library(CemuAsm stub.cpp) else() - message(STATUS "CemuAsm - Unsupported arch: ${CMAKE_SYSTEM_PROCESSOR}") + message(STATUS "CemuAsm - Unsupported arch: ${CEMU_ASM_ARCHITECTURE}") endif() From b06990607d31fc204d82be2b062df4c7edd6e299 Mon Sep 17 00:00:00 2001 From: Joshua de Reeper Date: Mon, 2 Sep 2024 15:20:16 +0100 Subject: [PATCH 3/9] nsysnet: Avoid crash on NULL timeout in select (#1324) --- src/Cafe/OS/libs/nsysnet/nsysnet.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp index dd7c918..5a0ddc5 100644 --- a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp +++ b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp @@ -1210,6 +1210,14 @@ void nsysnetExport_select(PPCInterpreter_t* hCPU) timeval tv = { 0 }; + if (timeOut == NULL) + { + // return immediately + cemuLog_log(LogType::Socket, "select returned immediately because of null timeout"); + osLib_returnFromFunction(hCPU, 0); + return; + } + uint64 msTimeout = (_swapEndianU32(timeOut->tv_usec) / 1000) + (_swapEndianU32(timeOut->tv_sec) * 1000); uint32 startTime = GetTickCount(); while (true) From 0d8fd7c0dc2ea6ff750f4ef5b193ebc6388d31d0 Mon Sep 17 00:00:00 2001 From: MoonlightWave-12 <123384363+MoonlightWave-12@users.noreply.github.com> Date: Mon, 2 Sep 2024 21:22:38 +0200 Subject: [PATCH 4/9] appimage: Do not copy `libstdc++.so.6` to `usr/lib/` (#1319) --- dist/linux/appimage.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dist/linux/appimage.sh b/dist/linux/appimage.sh index e908152..b66326d 100755 --- a/dist/linux/appimage.sh +++ b/dist/linux/appimage.sh @@ -50,7 +50,6 @@ fi echo "Cemu Version Cemu-${GITVERSION}" rm AppDir/usr/lib/libwayland-client.so.0 -cp /lib/x86_64-linux-gnu/libstdc++.so.6 AppDir/usr/lib/ echo -e "export LC_ALL=C\nexport FONTCONFIG_PATH=/etc/fonts" >> AppDir/apprun-hooks/linuxdeploy-plugin-gtk.sh VERSION="${GITVERSION}" ./mkappimage.AppImage --appimage-extract-and-run "${GITHUB_WORKSPACE}"/AppDir From ba54d1540cf6103728abe606223b299d284a6df8 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:21:20 +0200 Subject: [PATCH 5/9] Fix "Receive untested updates" option not being synced to config --- src/gui/GeneralSettings2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index bd39447..eaada7c 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -932,6 +932,7 @@ void GeneralSettings2::StoreConfig() config.fullscreen_menubar = m_fullscreen_menubar->IsChecked(); config.check_update = m_auto_update->IsChecked(); config.save_screenshot = m_save_screenshot->IsChecked(); + config.receive_untested_updates = m_receive_untested_releases->IsChecked(); #if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE) config.feral_gamemode = m_feral_gamemode->IsChecked(); #endif From 1a4d9660e756f52a01589add71df619361543a2f Mon Sep 17 00:00:00 2001 From: Cemu-Language CI Date: Sun, 8 Sep 2024 15:40:13 +0000 Subject: [PATCH 6/9] Update translation files --- bin/resources/ko/cemu.mo | Bin 70573 -> 71668 bytes bin/resources/zh/cemu.mo | Bin 58070 -> 60704 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/resources/ko/cemu.mo b/bin/resources/ko/cemu.mo index b812df970a34b41a6d2407c9ec4771adadd6a5db..5ea5e1da1a39c3ac7d15b9b270c5a01a89a4ed07 100644 GIT binary patch delta 22630 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 delta 21570 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 diff --git a/bin/resources/zh/cemu.mo b/bin/resources/zh/cemu.mo index 69e06e572cbc240cd3fa396bb0fb323e9dfb62cd..3e6369713ad379e558631b4db68b02fde8dab833 100644 GIT binary patch delta 18541 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 delta 16136 zcmZA72Yij^|Nrqj5ebPcu_DB-8Jk)aM5!Ql)uv|cO>wN2C{;quTCuf8Pbq5FY$G-|g=lbOF@c-YB$Cc;j+Sh&E*L}{>?{~%3bQh1L^WDf1GT-C65$t*S zF;i~OyOhrJ{w}Lh&wI7D=ViwBm|^APee_a-k-QMNL%E^3_otUqLOb1?I%pkvs85qZT>^)o&(hyt$TNikfE? zYG*cL1|Pu=0&UHH)WoMz4R50E=ss#^o}%tJtggG07}Nx1P!m=~Eu@zDGHTqGSPZ+P z7C0T%Zw~r2(GmhZ<5biH+fWUUVIDkV`TMAaJVq_-Kh&ej7Vj1ug}Q+lRDB$30d-N2 zB+2ZF8h>m&`>!pWLV>nq0cvYgQFpQfwXlPzcBfGbzKwbmKcWVDjJl&|s0q{8XGb5O>o@u zC$Tm8tEfATYv?AbhttTvf*SWMYC)M_4z%-mF$CL!}*2wb; zVIro-fv86@97AvdYT_xVNAo^vM^mv19zwPI3)Sym%%k@|Lt}SGg)oeYILv_6%(|$p zYHW5w?Z6P!A@ZRndlG3nx?43)fsgtN1z6tg&J@ks@*!&S=otI@giymGdJPm8w+DIoPoZ61Xl=N#0H7( zjwWCmH9#%sJ6wbha3M}@>UJoGQM6OVQD-O)wNuSdkElCpNBfwAt$egOp&9$HFNdkt zU6{^0oITZEC-o^zu56fejB=(=1 z@;W7X9_P&4h z60jg9Vl4Le5#%74g&*Mx)JmJR^1PbZ5!G=aX2<2It=)z?OrN6qe}G3~lTBEc1JH2(r?k3zon^s0A#*e3*)QJNBUlx`x{7N2oi`+Rl|1MlGy5 zvKFr~M&dHmPWZ70?!tx`^D1rh{=ZJ3t=)`jcmQ+aQPc!iaS}enzBs78dqh`ITX_%j z;xCvBGrr~~j>SCWtDwedhPkmDYMwC|&itN_pft|Finzn__fdx~ssjfP>tZ<^j#V)g zOX5|mj3FIe{}-_u`TnSJSEHWw8S@hAQQttHDsB^KYagI?!t3NF%z+x9A?lF~Mcv5+ z)Yi^H9oDs|*Yp$Ap*)Ducm#{!P1Me$@9aL(^P?8tzBBt@gJ22;y3>8A1>HA)MV*a5 zQ4@uAarIGHh<53gMvGPS2*m|r^`6svsAEI8;KWf|qsKa;$HO_quM&BcXj|hH8t!Pyb zcLp|~p5bSxow$VB%Im0w{eW5Uf2f6oaQphM$bp(LKWeASpw3h^)Ydmf-O%gE8S;6f z3Dj{GYJvs$Hm2ezEY;J!x2v!f`OsecJ_z!>*HCw|w72`*SdBWACsD80P1H`@LoMJ} z)D8sqarMy{s`tMTff~MmT0jL1!`i4038)2j#t`gd4nVy%Ls2_29knC#QLpi8)OeRL z1KvjU{|R*l9$^IYd%63%Eh~arX(iMLN&>257Ys~{dPDMT6N zqL}dwmoJAJzZPoz1WbpG-eCV#kZ28?qbBNvTH#RCLMEfO_I=B*LG9Eo)FV29n(z*4 zM>6(z3(bzomq0zDIE=trmT%Ob{nwVZp`Z|U#4|Vnb%)IdxM$xQbqAeMTiV<5hma3V z@1*5R4s;8yh?=+|s$VnIJnb+ec19i2K0bm11OrhYk+V=8SED+7i0a@+ZT()1!E>ms ze}rn6Wsv&>jKWOhTbP|uLjvBBb#$rHXBKeUR zj~h^r=ttD|cldDkWmOpUiPjWLU?0>%-a{?WZ~4opoqLAbfe`LW<3(cN_kSep=VHCcFy2B-y1wY1Yco5a^ELOp9P|rH&NcR)(Rn!ekLiJySf%kta zfgZtj)U(`!TF_zCcffh8|JBO>G{g9OR=?b+XIucapi-!DUPLWC9(5zlF(-Dk`oW{v ze{IcZE0|;^qjq8rs$(ju<5tw?#bMOM$53y_Da&6*J>zdtJCSa*TR;}nGtZA}u@362 z-5t&Ik0l5m!|(DSI^&Dv>yLH6RK{aV^1D&(GQa68hicax?_)By#bM)I{g>F3{Et|I zabFzo{-M%sf*W@w##4X8NANB|EDI@vTd*2l#|juZ(f!tIh&q(xaSd)o9lExYXwL)_ zP={{EWOrxRuqOE@s7F$HiaUh$QI8}M3!?8e0(~2eMIE9Q)?gdvBEKKCl^0Qu>LzN- zAK(l4yOqaGbvsfV_3XQ%#_NM2I0n<<1dPJTSWoZ&LIORDYgh}PAY*z}-l7riLUpM1 zwtMC+Q3JO}osoX1Gcpc~V=@NL3aZ~>)D2w4W_Z`iD^F8B+x!ZFwx}z%!a=AGhXM^a zT&R!SJ60Y%-FIPf zen9zM)SXO8cF$}PzCeB#=D}O29eIY@kxVn(cm?o%@`aTTrajgrzjvnlp!yemT4|wK zZtLQ(2Kly_7w2GY+=PelK8D~&oY)NbF-GENm>$m{&(yn!T5#Uk&NvJupMbj2MASG* zv)O-jY-0r-Py=?g{0MU_YRh~Wj?+;6=3+ivh}sc9X2t861%JZK_zcxP<9lx6tQhzR zevkdvYgdT^eS&qh2K`YJ4ncO#8-u!oao7x}U=d!svzU$iA9LKqVRPNYxlxC*xLL`p zYc@qK^fe!W-ot*Vfo7mi?-JA zNA2)1(>I+!TlfKL2X>++I&7XcubOu;C-uKtK4hL7Fe_@Si=xg>MbrWkQ4{w-jXT`* zA>;VG8CI~&++co!I%NA%0~|N6Sp5Uk1ph<5R+;9zd<9hdMwk)XqbBZQ4n*zj7|f>k ze>y>N3Kj(lJnsMow%WXI<@Yd}c27`u8p*pAi-l1W);C+DcBm)nQH?>Jr3t8=c^mcG zuE1=1|927O!Y?s5-b5|nFDnmO;3kMhwJU>KKz%E3VddRX{l=J6&Dp3sUW{7k28_bp z=+lbM5NN;$s0p5+I%HkwIut++9B0{xs??|EvzQ$qqPm{BX}t4wR#V=pbt=6yB;<0R@5OriTWhGY(7BU(BIe| zBNn?4qMnP{{~Q$br9d6Wq2BZ9sEKBy7Pi##+p!e+&v6JoL@lt(64!nl>b*`zjk5@~ zifH&7(%%OM(ds0yMEWmU|F4Nwzy!2;L|3*lR+9ax9jfxVa; zub|pLLfz>TGh&7NxnBS)=>1P5$WMa_*c+E%Q%tv#k4bES+VUf)JNO+tpts81X-Di% zwl8wNypyPjd!@Si0jPzIMJ?ogRQ(3kGrzZ$K&N=GRU9!-q8`CH%l~BlhT7t%X4q;s zU?ggyXwq72o}XAYuvBa!C002R@8#-p&pHX zOUo=+2J@o^Zj73^Beugus7Lh3>ciH#1?F4F{%ZlHCS`7 z1-*p2qmigHGtu%3Fdg}osPWfe2HcLCXPmq zhT4%jmT!l;)6Q57hofHG#n=K*U=qe`be|&weFQqqi!ksAP%A!y8u)_ce@3AN8^85RZDz+F=~NiP{Y`PIYd-TWBs<4_aSL)~d2>V^hl5{|I^QS&SGX@K(tTJcTPo&Jfslc-Nz zc`?){WKGP5uc8L-i|Rkv9B<|Cg0}J6!wBSeEj9$cLrZ2-WT<49DMgu>TtPUkWsF z#HTJ_1%t`g!(>cAbv%vQ>Wiq??!J|$-|6Zzp&mg_)VMKbDYF`CXB(i}we}I{jyhu= z9E_SE8Fgn%Q4@cRdjEIfWW0 zed7tVqNx~-^Q>a4`Kh@NwXh?Wzl?dve~Y@4CsrQ3$4!tCHEuT4PQ;@6mqmTf)J6L7 z{uAg~ypMs;Y}DypgX(w;HPCs>-$70M2-PoqubVK+%#S*xMJ!(#wZNK~9}`du>5i@R z{Xc?0Tk-{J!ZYSKsE!XX1OAR$;6JDVg7&$O*hti)iZc^X?K)s#?1K8dn2Z|lFh=7k z4E+250YM}Mk5C;$_qzp!qw?8N3yVTcT-fqeFot|REANWhnPKKk)OWxd)Q%oN-RLc= zzmI|M|KJ1edprkfOJh-6UK#^ihZ;Bm`DpMuqXx=x&@C)4DqkGiU|H0TO~Gb36E)5? z)D7IV{F8(1zd8ng?k3ELy3@QE7!dU}S{8Mut*m^AIT|&v4+~*3YN4A@cYYW(&bL?z zzel}o`3^bD9P+sd>rkKpnqW;FfO?%apa!^vTG$QC|A?CCF=_!3hh4iUGe7E+uZZR2 z%&J(B^4h3J-pNOxtsaV+V6r(IHStn26?MoqqPFk=j>B_So^-^O_rd~{kFoqh%Wp#U z{}QzW-(gYoJtojcZ0@7Zm#_%=-l$Xhj=2uCg@>>l{)u(5_%YY6H)=KAK}>4X~~C#pk?Srj#KY1F`V@C9sQ^~0_F zO>??AAN43!S$-b|zW+}UXiF~RhxiX_AsbJ+Ej@-$$$x`Y)$S{2)>C{YkZ*{3_A|{j z7)O2|-oT%+4Ssdno&F+c+$UoFGwgrPApX%oK`k0A`r5sA7qJTYkhAW83$B5M$sa@w zd|=>Ia|>;dso1vr+w*nrl&S(N@%>JC8N+n&op{a{Xd_1Zq&qtbm%R zI@ZP}s7H~E<#8>J!%JrC%dY*`sB!L~7W5-(p-(KI;fj0qQKVJRo#t?kZ zA$f#4M3*_T8t5tNjtYM3@@23T`4*@h8i$EEA2;DG)FXKJJ9k6#QFp!^RlXhdw(LQb z2j4^=K^_9_KsgLNd(;Y>pgJ};+oC4!Wc4Fa{l;4TRMdjsvHU{RAzhBKxD7S_S@SOX zRPcmA6Gq%}6J|xNFc%iWGN^%@S$zkyJE~t_)ItVeXB>q=*n>Z>1{0)RD&+c%vVEjG zLF~T{-^*m)vC7}buTV$Q4B`PKUE^relCt-368R{skNV{Ml%%UJWgpYVPkKteKl!gn z5yU~5K>Cu@llm;A>%r{*K`L8NsB0pH8!R43{4QmY*cX38UDHUbEe;g$XA^xIQ}#ZV zRZP;EI&bZ2l5b7Yb=VR3yH?Ntwl$i9>u6LAhm!O<{)>ljZ=gBx!B7}gQZpxL|mP8hI|ve ziVLmXr{r@JFT$y$_SPpCaU}69j3wi8<~8d0|Xxw3YYy+-tG6L5Opm{?~x8!oASiE7LeLd_RPw=1xoqnHu-lM;}QNsSrMFoFYEd1186J- zaij2=af(tgrH(oovyi|i%h zCe}EI-hW-INi%3L8e6D<>wD5^8lNDoeQpBPEh9f4&yuPWSEkL!sPBhnq_j(4JTF=1 zMe5sxb`8X0n~pt#dH%Jj=t;$@=LS&6Ui!mz#5(k&K0W!yfl>~SwJ(JFF{Ue# zxHRpPNOwsyNI#Ht4W}*xzD)Xu)Q$WV9n&pja$2KK6h40qp}Zk!C*|#_=tr7NyqL6_ zbd0*}lzl{;cAX`Doy>7;gJHDUXO%th4a$F{Y#Z@nA3=9gyfrvPWoFWR%IcH)lZH{Z zpRzA-GkJbQdM8L*D4RuUK+@G4L#WqPg>;j+J!!txA0;k8(wu3R&R^ha$lp(CSkWp6 zJ=Z9ly27OHqzRP&N=hL0v4P7GH=wRHc0&Ee*0sy(-=@4S=?n7ZNy%1D6F2{5D#I!K zFVM~XUrH3dV|j6$RF-yW*XL=0c^XSHMiLIhsknhOg7{UehuP_WnK%P+Gt%!t%>O=x zpHTP)=_+YE6{AQcNOP#GNLkudlHe+3f8iR^bkYa3yM}LJLDE!GbMihsOWO}I?W#gt z#xk2x|L5?)@7j?xJV|9+^0lqO63U`1evLTo+DK5s@>}Wi5&2-t_qRqB$S)^uWO)%n zDoDCbT1qNI8{aGZd5;uHfv!a2@mQRJ{~->;cK9J>U52Dc+pm8S#KWs zb!1+k-RGn?t)e1vR@c|(6?1|2nRPB}jou~Sn^ctav6T(5HYf2O>08QE=>HO_9Pu;K zaLNmiPiK9a+W7e>A4l0xD_pac^soMkT9PzA*7N(wD?9&_0g%Ivyk? zT8HXbiu?#XO?^*NZqiBeM@U~2@1nj1sgVvz+EtbKZwg0IPy^GhSPR~yY#OO@T7`KJ zyVLhu>dN6BD<5rR{DJ4K>>S>;coq5*_)~^XIcSs%i(2I_GmUH1cO=~)J*MzqQY+F& z1*Q7_zi9P;(hYx@FMwQFOu0x zM%QjqKGGvn9viTZOet3P3x8;Q?;!t_dg+5wmehah|Dr+n2!F+-#X%`IT6FW@YB@BW z|LwM|g8cW}l}PVz-RVr2zjV)6gHxvWzUyDzXINND!NIvx_75)N&o-oBI)9_#ON0G? zjU1ldzkOU(q`%vo>Y?G4%2uclTcLc7%9T=57knR7A!X*mA3}=PPim8rvgmR|@dk-$FE*!wHD-~V8h z|ML|`Gx%q3=ogfdbx_e}Ke?cRT9=Zx>yue`fwc1nrkCH%hQTZ1$HuzBCz&5OTZnVM4b#9;ri r6McgH@uzmD3(@NQ!Dq(?`H!93lRcCM->;nRPrh3^$lvJR<@EmtGq=as From a05bdb172d198904a76b4b166b43fb31a94a0dd3 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:23:11 +0200 Subject: [PATCH 7/9] Vulkan: Add explicit synchronization on frame boundaries (#1290) --- .../Latte/Renderer/Vulkan/SwapchainInfoVk.cpp | 34 ++++++++- .../Latte/Renderer/Vulkan/SwapchainInfoVk.h | 8 ++ src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h | 3 + .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 73 ++++++++++++++++++- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 4 +- 5 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp index 75ff02b..56a3ab1 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp @@ -146,8 +146,17 @@ void SwapchainInfoVk::Create() UnrecoverableError("Failed to create semaphore for swapchain acquire"); } + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + result = vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence); + if (result != VK_SUCCESS) + UnrecoverableError("Failed to create fence for swapchain"); + m_acquireIndex = 0; hasDefinedSwapchainImage = false; + + m_queueDepth = 0; } void SwapchainInfoVk::Cleanup() @@ -177,6 +186,12 @@ void SwapchainInfoVk::Cleanup() m_swapchainFramebuffers.clear(); + if (m_imageAvailableFence) + { + WaitAvailableFence(); + vkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr); + m_imageAvailableFence = nullptr; + } if (m_swapchain) { vkDestroySwapchainKHR(m_logicalDevice, m_swapchain, nullptr); @@ -189,6 +204,18 @@ bool SwapchainInfoVk::IsValid() const return m_swapchain && !m_acquireSemaphores.empty(); } +void SwapchainInfoVk::WaitAvailableFence() +{ + if(m_awaitableFence != VK_NULL_HANDLE) + vkWaitForFences(m_logicalDevice, 1, &m_awaitableFence, VK_TRUE, UINT64_MAX); + m_awaitableFence = VK_NULL_HANDLE; +} + +void SwapchainInfoVk::ResetAvailableFence() const +{ + vkResetFences(m_logicalDevice, 1, &m_imageAvailableFence); +} + VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore() { VkSemaphore ret = m_currentSemaphore; @@ -198,8 +225,10 @@ VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore() bool SwapchainInfoVk::AcquireImage() { + ResetAvailableFence(); + VkSemaphore acquireSemaphore = m_acquireSemaphores[m_acquireIndex]; - VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, nullptr, &swapchainImageIndex); + VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, m_imageAvailableFence, &swapchainImageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) m_shouldRecreate = true; if (result == VK_TIMEOUT) @@ -216,6 +245,7 @@ bool SwapchainInfoVk::AcquireImage() return false; } m_currentSemaphore = acquireSemaphore; + m_awaitableFence = m_imageAvailableFence; m_acquireIndex = (m_acquireIndex + 1) % m_swapchainImages.size(); return true; @@ -319,6 +349,7 @@ VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& cap VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector& modes) { + m_maxQueued = 0; const auto vsyncState = (VSync)GetConfig().vsync.GetValue(); if (vsyncState == VSync::MAILBOX) { @@ -345,6 +376,7 @@ VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector m_acquireSemaphores; // indexed by m_acquireIndex + VkFence m_imageAvailableFence{}; + VkFence m_awaitableFence = VK_NULL_HANDLE; VkSemaphore m_currentSemaphore = VK_NULL_HANDLE; std::array m_swapchainQueueFamilyIndices; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h index 0489bb4..6bde2a0 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h @@ -188,6 +188,9 @@ VKFUNC_DEVICE(vkCmdPipelineBarrier2KHR); VKFUNC_DEVICE(vkCmdBeginRenderingKHR); VKFUNC_DEVICE(vkCmdEndRenderingKHR); +// khr_present_wait +VKFUNC_DEVICE(vkWaitForPresentKHR); + // transform feedback extension VKFUNC_DEVICE(vkCmdBindTransformFeedbackBuffersEXT); VKFUNC_DEVICE(vkCmdBeginTransformFeedbackEXT); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index f464c7a..12d1d97 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -47,7 +47,9 @@ const std::vector kOptionalDeviceExtensions = VK_EXT_FILTER_CUBIC_EXTENSION_NAME, // not supported by any device yet VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, - VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME + VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, + VK_KHR_PRESENT_WAIT_EXTENSION_NAME, + VK_KHR_PRESENT_ID_EXTENSION_NAME }; const std::vector kRequiredDeviceExtensions = @@ -252,12 +254,24 @@ void VulkanRenderer::GetDeviceFeatures() pcc.pNext = prevStruct; prevStruct = &pcc; + VkPhysicalDevicePresentIdFeaturesKHR pidf{}; + pidf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; + pidf.pNext = prevStruct; + prevStruct = &pidf; + + VkPhysicalDevicePresentWaitFeaturesKHR pwf{}; + pwf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; + pwf.pNext = prevStruct; + prevStruct = &pwf; + VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{}; physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; physicalDeviceFeatures2.pNext = prevStruct; vkGetPhysicalDeviceFeatures2(m_physicalDevice, &physicalDeviceFeatures2); + cemuLog_log(LogType::Force, "Vulkan: present_wait extension: {}", (pwf.presentWait && pidf.presentId) ? "supported" : "unsupported"); + /* Get Vulkan device properties and limits */ VkPhysicalDeviceFloatControlsPropertiesKHR pfcp{}; prevStruct = nullptr; @@ -490,6 +504,24 @@ VulkanRenderer::VulkanRenderer() customBorderColorFeature.customBorderColors = VK_TRUE; customBorderColorFeature.customBorderColorWithoutFormat = VK_TRUE; } + // enable VK_KHR_present_id + VkPhysicalDevicePresentIdFeaturesKHR presentIdFeature{}; + if(m_featureControl.deviceExtensions.present_wait) + { + presentIdFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; + presentIdFeature.pNext = deviceExtensionFeatures; + deviceExtensionFeatures = &presentIdFeature; + presentIdFeature.presentId = VK_TRUE; + } + // enable VK_KHR_present_wait + VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeature{}; + if(m_featureControl.deviceExtensions.present_wait) + { + presentWaitFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; + presentWaitFeature.pNext = deviceExtensionFeatures; + deviceExtensionFeatures = &presentWaitFeature; + presentWaitFeature.presentWait = VK_TRUE; + } std::vector used_extensions; VkDeviceCreateInfo createInfo = CreateDeviceCreateInfo(queueCreateInfos, deviceFeatures, deviceExtensionFeatures, used_extensions); @@ -1047,6 +1079,10 @@ VkDeviceCreateInfo VulkanRenderer::CreateDeviceCreateInfo(const std::vector 0); + // wait for the previous frame to finish rendering + WaitCommandBufferFinished(m_commandBufferIDOfPrevFrame); + m_commandBufferIDOfPrevFrame = currentFrameCmdBufferID; + + chainInfo.WaitAvailableFence(); + + VkPresentIdKHR presentId = {}; + VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; @@ -2709,6 +2756,24 @@ void VulkanRenderer::SwapBuffer(bool mainWindow) presentInfo.waitSemaphoreCount = 1; presentInfo.pWaitSemaphores = &presentSemaphore; + // if present_wait is available and enabled, add frame markers to present requests + // and limit the number of queued present operations + if (m_featureControl.deviceExtensions.present_wait && chainInfo.m_maxQueued > 0) + { + presentId.sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR; + presentId.swapchainCount = 1; + presentId.pPresentIds = &chainInfo.m_presentId; + + presentInfo.pNext = &presentId; + + if(chainInfo.m_queueDepth >= chainInfo.m_maxQueued) + { + uint64 waitFrameId = chainInfo.m_presentId - chainInfo.m_queueDepth; + vkWaitForPresentKHR(m_logicalDevice, chainInfo.m_swapchain, waitFrameId, 40'000'000); + chainInfo.m_queueDepth--; + } + } + VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo); if (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR) { @@ -2717,6 +2782,12 @@ void VulkanRenderer::SwapBuffer(bool mainWindow) if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) chainInfo.m_shouldRecreate = true; + if(result >= 0) + { + chainInfo.m_queueDepth++; + chainInfo.m_presentId++; + } + chainInfo.hasDefinedSwapchainImage = false; chainInfo.swapchainImageIndex = -1; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 6df53da..ce97b5e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -450,6 +450,7 @@ private: bool synchronization2 = false; // VK_KHR_synchronization2 bool dynamic_rendering = false; // VK_KHR_dynamic_rendering bool shader_float_controls = false; // VK_KHR_shader_float_controls + bool present_wait = false; // VK_KHR_present_wait }deviceExtensions; struct @@ -457,7 +458,7 @@ private: bool shaderRoundingModeRTEFloat32{ false }; }shaderFloatControls; // from VK_KHR_shader_float_controls - struct + struct { bool debug_utils = false; // VK_EXT_DEBUG_UTILS }instanceExtensions; @@ -635,6 +636,7 @@ private: size_t m_commandBufferIndex = 0; // current buffer being filled size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit) + size_t m_commandBufferIDOfPrevFrame = 0; std::array m_cmd_buffer_fences; std::array m_commandBuffers; std::array m_commandBufferSemaphores; From adffd53dbdc86f54803e79dcf06004e688e3b19d Mon Sep 17 00:00:00 2001 From: Andrea Toska Date: Mon, 16 Sep 2024 12:40:38 +0200 Subject: [PATCH 8/9] boss: Fix BOSS not honoring the proxy_server setting (#1344) --- src/Cafe/IOSU/legacy/iosu_boss.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index 760e5b6..7ab25f6 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -137,6 +137,10 @@ namespace iosu this->task_settings.taskType = settings->taskType; curl = std::shared_ptr(curl_easy_init(), curl_easy_cleanup); + if(GetConfig().proxy_server.GetValue() != "") + { + curl_easy_setopt(curl.get(), CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str()); + } } }; From 8508c625407e80a5a7fcb9cf02c5355d018ff64b Mon Sep 17 00:00:00 2001 From: capitalistspz Date: Tue, 17 Sep 2024 01:00:26 +0100 Subject: [PATCH 9/9] Various smaller code improvements (#1343) --- CMakeLists.txt | 2 +- src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp | 4 +- src/Cafe/OS/libs/nsyshid/Infinity.cpp | 6 +- src/Cafe/OS/libs/ntag/ntag.cpp | 2 +- src/Cafe/OS/libs/snd_core/ax_out.cpp | 8 +- src/Common/MemPtr.h | 160 ++++++++++++------- src/Common/precompiled.h | 48 +++--- src/gui/CemuApp.cpp | 3 + src/util/CMakeLists.txt | 1 - src/util/ThreadPool/ThreadPool.cpp | 0 src/util/containers/robin_hood.h | 2 +- src/util/crypto/crc32.cpp | 55 ++----- src/util/crypto/crc32.h | 4 +- 13 files changed, 153 insertions(+), 142 deletions(-) delete mode 100644 src/util/ThreadPool/ThreadPool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 54e2012..5b5cff6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,7 @@ if (ENABLE_CUBEB) option(BUILD_TOOLS "" OFF) option(BUNDLE_SPEEX "" OFF) set(USE_WINMM OFF CACHE BOOL "") - add_subdirectory("dependencies/cubeb" EXCLUDE_FROM_ALL) + add_subdirectory("dependencies/cubeb" EXCLUDE_FROM_ALL SYSTEM) set_property(TARGET cubeb PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") add_library(cubeb::cubeb ALIAS cubeb) endif() diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp index 309394e..c87cbd3 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp @@ -112,7 +112,7 @@ namespace nn nnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList(coreinit::OSEvent* event, DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param) { - scope_exit _se([&](){coreinit::OSSignalEvent(event);}); + stdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);}); uint64 titleId = CafeSystem::GetForegroundTitleId(); @@ -184,7 +184,7 @@ namespace nn nnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(coreinit::OSEvent* event, DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize) { - scope_exit _se([&](){coreinit::OSSignalEvent(event);}); + stdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);}); if (!_this->TestFlags(_this, DownloadedDataBase::FLAGS::HAS_EXTERNAL_IMAGE)) return OLV_RESULT_MISSING_DATA; diff --git a/src/Cafe/OS/libs/nsyshid/Infinity.cpp b/src/Cafe/OS/libs/nsyshid/Infinity.cpp index ab44ef4..ac79310 100644 --- a/src/Cafe/OS/libs/nsyshid/Infinity.cpp +++ b/src/Cafe/OS/libs/nsyshid/Infinity.cpp @@ -1017,11 +1017,7 @@ namespace nsyshid std::array InfinityUSB::GenerateInfinityFigureKey(const std::vector& sha1Data) { std::array digest = {}; - SHA_CTX ctx; - SHA1_Init(&ctx); - SHA1_Update(&ctx, sha1Data.data(), sha1Data.size()); - SHA1_Final(digest.data(), &ctx); - OPENSSL_cleanse(&ctx, sizeof(ctx)); + SHA1(sha1Data.data(), sha1Data.size(), digest.data()); // Infinity AES keys are the first 16 bytes of the SHA1 Digest, every set of 4 bytes need to be // reversed due to endianness std::array key = {}; diff --git a/src/Cafe/OS/libs/ntag/ntag.cpp b/src/Cafe/OS/libs/ntag/ntag.cpp index 2461779..7c95a1a 100644 --- a/src/Cafe/OS/libs/ntag/ntag.cpp +++ b/src/Cafe/OS/libs/ntag/ntag.cpp @@ -509,7 +509,7 @@ namespace ntag noftHeader->writeCount = _swapEndianU16(_swapEndianU16(noftHeader->writeCount) + 1); } - memcpy(decryptedBuffer + 0x20, noftHeader, sizeof(noftHeader)); + memcpy(decryptedBuffer + 0x20, noftHeader, sizeof(NTAGNoftHeader)); memcpy(decryptedBuffer + _swapEndianU16(rwHeader->offset), data, dataSize); // Encrypt diff --git a/src/Cafe/OS/libs/snd_core/ax_out.cpp b/src/Cafe/OS/libs/snd_core/ax_out.cpp index 68b0516..40b9c64 100644 --- a/src/Cafe/OS/libs/snd_core/ax_out.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_out.cpp @@ -522,10 +522,10 @@ namespace snd_core // called periodically to check for AX updates void AXOut_update() { - constexpr auto kTimeout = std::chrono::duration_cast(std::chrono::milliseconds(((IAudioAPI::kBlockCount * 3) / 4) * (AX_FRAMES_PER_GROUP * 3))); - constexpr auto kWaitDuration = std::chrono::duration_cast(std::chrono::milliseconds(3)); - constexpr auto kWaitDurationFast = std::chrono::duration_cast(std::chrono::microseconds(2900)); - constexpr auto kWaitDurationMinimum = std::chrono::duration_cast(std::chrono::microseconds(1700)); + constexpr static auto kTimeout = std::chrono::duration_cast(std::chrono::milliseconds(((IAudioAPI::kBlockCount * 3) / 4) * (AX_FRAMES_PER_GROUP * 3))); + constexpr static auto kWaitDuration = std::chrono::duration_cast(std::chrono::milliseconds(3)); + constexpr static auto kWaitDurationFast = std::chrono::duration_cast(std::chrono::microseconds(2900)); + constexpr static auto kWaitDurationMinimum = std::chrono::duration_cast(std::chrono::microseconds(1700)); // if we haven't buffered any blocks, we will wait less time than usual bool additional_blocks_required = false; diff --git a/src/Common/MemPtr.h b/src/Common/MemPtr.h index 142da7e..7825e4d 100644 --- a/src/Common/MemPtr.h +++ b/src/Common/MemPtr.h @@ -4,7 +4,7 @@ using MPTR = uint32; // generic address in PowerPC memory space -#define MPTR_NULL (0) +#define MPTR_NULL (0) using VAddr = uint32; // virtual address using PAddr = uint32; // physical address @@ -14,137 +14,175 @@ extern uint8* PPCInterpreterGetStackPointer(); extern uint8* PPCInterpreter_PushAndReturnStackPointer(sint32 offset); extern void PPCInterpreterModifyStackPointer(sint32 offset); -class MEMPTRBase {}; +class MEMPTRBase +{ +}; -template +template class MEMPTR : MEMPTRBase { -public: - constexpr MEMPTR() - : m_value(0) { } + public: + constexpr MEMPTR() noexcept + : m_value(0) {} - explicit constexpr MEMPTR(uint32 offset) - : m_value(offset) { } + explicit constexpr MEMPTR(uint32 offset) noexcept + : m_value(offset) {} - explicit constexpr MEMPTR(const uint32be& offset) - : m_value(offset) { } + explicit constexpr MEMPTR(const uint32be& offset) noexcept + : m_value(offset) {} - constexpr MEMPTR(std::nullptr_t) - : m_value(0) { } + constexpr MEMPTR(std::nullptr_t) noexcept + : m_value(0) {} - MEMPTR(T* ptr) + MEMPTR(T* ptr) noexcept { if (ptr == nullptr) m_value = 0; else - { - cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000); - m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); - } + { + cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000); + m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); + } } - constexpr MEMPTR(const MEMPTR& memptr) - : m_value(memptr.m_value) { } + constexpr MEMPTR(const MEMPTR&) noexcept = default; - constexpr MEMPTR& operator=(const MEMPTR& memptr) - { - m_value = memptr.m_value; - return *this; - } + constexpr MEMPTR& operator=(const MEMPTR&) noexcept = default; - constexpr MEMPTR& operator=(const uint32& offset) + constexpr MEMPTR& operator=(const uint32& offset) noexcept { m_value = offset; return *this; } - constexpr MEMPTR& operator=(const std::nullptr_t rhs) + constexpr MEMPTR& operator=(std::nullptr_t) noexcept { m_value = 0; return *this; } - MEMPTR& operator=(T* ptr) + MEMPTR& operator=(T* ptr) noexcept { - if (ptr == nullptr) + if (ptr == nullptr) m_value = 0; else - { - cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000); - m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); - } + { + cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000); + m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); + } return *this; } - bool atomic_compare_exchange(T* comparePtr, T* newPtr) + bool atomic_compare_exchange(T* comparePtr, T* newPtr) noexcept { MEMPTR mp_compare = comparePtr; MEMPTR mp_new = newPtr; - std::atomic* thisValueAtomic = (std::atomic*)&m_value; + auto* thisValueAtomic = reinterpret_cast*>(&m_value); return thisValueAtomic->compare_exchange_strong(mp_compare.m_value, mp_new.m_value); } - explicit constexpr operator bool() const noexcept { return m_value != 0; } - - constexpr operator T*() const noexcept { return GetPtr(); } // allow implicit cast to wrapped pointer type + explicit constexpr operator bool() const noexcept + { + return m_value != 0; + } + // allow implicit cast to wrapped pointer type + constexpr operator T*() const noexcept + { + return GetPtr(); + } - template - explicit operator MEMPTR() const { return MEMPTR(this->m_value); } + template + explicit operator MEMPTR() const noexcept + { + return MEMPTR(this->m_value); + } - MEMPTR operator+(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() + ptr.GetMPTR()); } - MEMPTR operator-(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() - ptr.GetMPTR()); } + MEMPTR operator+(const MEMPTR& ptr) noexcept + { + return MEMPTR(this->GetMPTR() + ptr.GetMPTR()); + } + MEMPTR operator-(const MEMPTR& ptr) noexcept + { + return MEMPTR(this->GetMPTR() - ptr.GetMPTR()); + } - MEMPTR operator+(sint32 v) + MEMPTR operator+(sint32 v) noexcept { // pointer arithmetic return MEMPTR(this->GetMPTR() + v * 4); } - MEMPTR operator-(sint32 v) + MEMPTR operator-(sint32 v) noexcept { // pointer arithmetic return MEMPTR(this->GetMPTR() - v * 4); } - MEMPTR& operator+=(sint32 v) + MEMPTR& operator+=(sint32 v) noexcept { m_value += v * sizeof(T); return *this; } - template - typename std::enable_if::value, Q>::type& - operator*() const { return *GetPtr(); } + template + std::enable_if_t, Q>& operator*() const noexcept + { + return *GetPtr(); + } - T* operator->() const { return GetPtr(); } + constexpr T* operator->() const noexcept + { + return GetPtr(); + } - template - typename std::enable_if::value, Q>::type& - operator[](int index) { return GetPtr()[index]; } + template + std::enable_if_t, Q>& operator[](int index) noexcept + { + return GetPtr()[index]; + } - T* GetPtr() const { return (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value); } + T* GetPtr() const noexcept + { + return (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value); + } - template - C* GetPtr() const { return (C*)(GetPtr()); } + template + C* GetPtr() const noexcept + { + return static_cast(GetPtr()); + } - constexpr uint32 GetMPTR() const { return m_value.value(); } - constexpr const uint32be& GetBEValue() const { return m_value; } + [[nodiscard]] constexpr uint32 GetMPTR() const noexcept + { + return m_value.value(); + } + [[nodiscard]] constexpr const uint32be& GetBEValue() const noexcept + { + return m_value; + } - constexpr bool IsNull() const { return m_value == 0; } + [[nodiscard]] constexpr bool IsNull() const noexcept + { + return m_value == 0; + } -private: + private: uint32be m_value; }; static_assert(sizeof(MEMPTR) == sizeof(uint32be)); +static_assert(std::is_trivially_copyable_v>); #include "StackAllocator.h" #include "SysAllocator.h" -template +template struct fmt::formatter> : formatter { - template - auto format(const MEMPTR& v, FormatContext& ctx) const -> format_context::iterator { return fmt::format_to(ctx.out(), "{:#x}", v.GetMPTR()); } + template + auto format(const MEMPTR& v, FormatContext& ctx) const -> format_context::iterator + { + return fmt::format_to(ctx.out(), "{:#x}", v.GetMPTR()); + } }; diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index 6170751..d4df434 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -394,16 +394,10 @@ void vectorRemoveByIndex(std::vector& vec, const size_t index) vec.erase(vec.begin() + index); } -template -int match_any_of(T1 value, T2 compareTo) +template +bool match_any_of(T1&& value, Types&&... others) { - return value == compareTo; -} - -template -bool match_any_of(T1 value, T2 compareTo, Types&&... others) -{ - return value == compareTo || match_any_of(value, others...); + return ((value == others) || ...); } // we cache the frequency in a static variable @@ -501,13 +495,6 @@ bool future_is_ready(std::future& f) #endif } -// replace with std::scope_exit once available -struct scope_exit -{ - std::function f_; - explicit scope_exit(std::function f) noexcept : f_(std::move(f)) {} - ~scope_exit() { if (f_) f_(); } -}; // helper function to cast raw pointers to std::atomic // this is technically not legal but works on most platforms as long as alignment restrictions are met and the implementation of atomic doesnt come with additional members @@ -515,6 +502,8 @@ struct scope_exit template std::atomic* _rawPtrToAtomic(T* ptr) { + static_assert(sizeof(T) == sizeof(std::atomic)); + cemu_assert_debug((reinterpret_cast(ptr) % alignof(std::atomic)) == 0); return reinterpret_cast*>(ptr); } @@ -578,13 +567,34 @@ struct fmt::formatter> : fmt::formatter } }; -// useful C++23 stuff that isn't yet widely supported - -// std::to_underlying +// useful future C++ stuff namespace stdx { + // std::to_underlying template {} >> constexpr std::underlying_type_t to_underlying(EnumT e) noexcept { return static_cast>(e); }; + + // std::scope_exit + template + class scope_exit + { + Fn m_func; + bool m_released = false; + public: + explicit scope_exit(Fn&& f) noexcept + : m_func(std::forward(f)) + {} + ~scope_exit() + { + if (!m_released) m_func(); + } + scope_exit(scope_exit&& other) noexcept + : m_func(std::move(other.m_func)), m_released(std::exchange(other.m_released, true)) + {} + scope_exit(const scope_exit&) = delete; + scope_exit& operator=(scope_exit) = delete; + void release() { m_released = true;} + }; } \ No newline at end of file diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index f91c1e3..50ff3b8 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -15,6 +15,9 @@ #if BOOST_OS_LINUX && HAS_WAYLAND #include "gui/helpers/wxWayland.h" #endif +#if __WXGTK__ +#include +#endif #include #include diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 5af8817..5ac5ebf 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -50,7 +50,6 @@ add_library(CemuUtil MemMapper/MemMapper.h SystemInfo/SystemInfo.cpp SystemInfo/SystemInfo.h - ThreadPool/ThreadPool.cpp ThreadPool/ThreadPool.h tinyxml2/tinyxml2.cpp tinyxml2/tinyxml2.h diff --git a/src/util/ThreadPool/ThreadPool.cpp b/src/util/ThreadPool/ThreadPool.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/util/containers/robin_hood.h b/src/util/containers/robin_hood.h index 577521b..4f76519 100644 --- a/src/util/containers/robin_hood.h +++ b/src/util/containers/robin_hood.h @@ -194,7 +194,7 @@ namespace robin_hood { // workaround missing "is_trivially_copyable" in g++ < 5.0 // See https://stackoverflow.com/a/31798726/48181 -#if defined(__GNUC__) && __GNUC__ < 5 +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__) #else # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value diff --git a/src/util/crypto/crc32.cpp b/src/util/crypto/crc32.cpp index 52eb8a8..a5b37a5 100644 --- a/src/util/crypto/crc32.cpp +++ b/src/util/crypto/crc32.cpp @@ -1,29 +1,6 @@ #include "crc32.h" -#if defined(_MSC_VER) || defined(__MINGW32__) -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __BYTE_ORDER __LITTLE_ENDIAN - -#include -#ifdef __MINGW32__ -#define PREFETCH(location) __builtin_prefetch(location) -#else -#define PREFETCH(location) _mm_prefetch(location, _MM_HINT_T0) -#endif -#else -// defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN -#include - -#ifdef __GNUC__ -#define PREFETCH(location) __builtin_prefetch(location) -#else - // no prefetching -#define PREFETCH(location) ; -#endif -#endif - -unsigned int Crc32Lookup[8][256] = +constexpr uint32 Crc32Lookup[8][256] = { { 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, @@ -301,20 +278,7 @@ unsigned int Crc32Lookup[8][256] = } }; -/// swap endianess -static inline uint32_t swap(uint32_t x) -{ -#if defined(__GNUC__) || defined(__clang__) - return __builtin_bswap32(x); -#else - return (x >> 24) | - ((x >> 8) & 0x0000FF00) | - ((x << 8) & 0x00FF0000) | - (x << 24); -#endif -} - -unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, int length) +uint32 crc32_calc_slice_by_8(uint32 previousCrc32, const void* data, size_t length) { uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF const uint32_t* current = (const uint32_t*)data; @@ -323,7 +287,7 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, while (length >= 8) { if constexpr (std::endian::native == std::endian::big){ - uint32_t one = *current++ ^ swap(crc); + uint32_t one = *current++ ^ _swapEndianU32(crc); uint32_t two = *current++; crc = Crc32Lookup[0][two & 0xFF] ^ Crc32Lookup[1][(two >> 8) & 0xFF] ^ @@ -348,13 +312,14 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, Crc32Lookup[7][one & 0xFF]; } else { - cemu_assert(false); + static_assert(std::endian::native == std::endian::big || std::endian::native == std::endian::little, + "Platform byte-order is unsupported"); } length -= 8; } - const uint8_t* currentChar = (const uint8_t*)current; + const uint8* currentChar = (const uint8*)current; // remaining 1 to 7 bytes (standard algorithm) while (length-- != 0) crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; @@ -362,20 +327,20 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, return ~crc; // same as crc ^ 0xFFFFFFFF } -unsigned int crc32_calc(unsigned int c, const void* data, int length) +uint32 crc32_calc(uint32 c, const void* data, size_t length) { if (length >= 16) { return crc32_calc_slice_by_8(c, data, length); } - unsigned char* p = (unsigned char*)data; + const uint8* p = (const uint8*)data; if (length == 0) return c; c ^= 0xFFFFFFFF; while (length) { - unsigned char temp = *p; - temp ^= (unsigned char)c; + uint8 temp = *p; + temp ^= (uint8)c; c = (c >> 8) ^ Crc32Lookup[0][temp]; // next length--; diff --git a/src/util/crypto/crc32.h b/src/util/crypto/crc32.h index b800226..2ab3737 100644 --- a/src/util/crypto/crc32.h +++ b/src/util/crypto/crc32.h @@ -1,8 +1,8 @@ #pragma once -unsigned int crc32_calc(unsigned int c, const void* data, int length); +uint32 crc32_calc(uint32 c, const void* data, size_t length); -inline unsigned int crc32_calc(const void* data, int length) +inline uint32 crc32_calc(const void* data, size_t length) { return crc32_calc(0, data, length); } \ No newline at end of file