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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 delta 23379 zcmex$kmb{6mil`_EK?a67#O6P85m?37#O}tFfgdHFfg1k1c@>*BseiJ@G>wkBswuL z@Gvki#SQ!`?f}9}+ML@;Vof#Me7#J8Tof#M;85kJ4oEaF@7#J9qK*dixGcbrSFfiPK z(jT1}7*rVQ85r1HAR4t@AO_mFFfgz&Ffe$#fL+KCjLp{std#+`7RKL zG(!39P<=C9AP!&P!oVQRz`(E>YR+*Nh(|6#_1y-USI@w}@DM8S8fwu;7f2BQglb@Q zg#;a+E5u?sSBQfQTpfk6TkRZzZ#8^j@wZV-q0 zxj~{b-VG9>DQ*ylXS+c>QtZZ1500}|H;50Xxk2J+8I;})HTZ%XBq(pXK|v2Z7pe-vuaIVk_CJH!F^p!#3BLwv^Q0kJ^X0}>*#9*`)}@_;zR(gR|T zL%jz?L%0V6gFFKRL#7ABXPr>-IUbM@S?2)>>cdcVcRU~#|M7tMklhm!$NZiQ46+Oi z45FS8d1FtA#de;M5b^bdL`|Y614AGK14Dh0Cj$dB0|UbmPe@3dfNH$q2{HIFRO4$; z1_n6>28RDo1LV9I7_1l=81%gu7-|_97_z(|+3tlG#6l)-NR$YAL(G@=W?%?mU|>-8 zhIp{T8*F|(L$@~rLpuWl!(?xWfzmz@hlKe+6sGwwFgStowGRV>3#cIRVPJ4%U|?YM zWni#jU|?|eg@jOpF9U-j0|UcUUr0!7_k~2kUSCKeJnjoI?~E@bO78oDLcE@V;f*f? zgDC?81CJj>p_3m(qq`p@$OHW#KFRU}yO^QE50Z!)pme7nBxol=>19y$yZj(&=Y$`` z!Yh7|D0%1yNu+N;@}T_Bf5FLL=(QF3g2m3>!BGw-ge z7|a+L7`8ygUk5NS_<^c}K#0NqfeZ{c85kJS0~r{y7#J8FgBTbr85kJW1VMcKEQo<2 zl!1ZaQxL=h9>EL@GeJdmFayI31_p*V!H^Ja4PmGUm+gHa5Fbqsfdu8Y5J()J3V{Uq zg%C)pz7Yb6l5bFP{!oZI@lXZ^a|Q+m*-%Jj6ABeCg!0QnA?8dDg;+d06q3f4gw{ji zW(!oo!B7SU1qKF&lc5lYyb5JtuxDUk_!kOE19o8$gM7juaTyW@Q5O%Ti^Cx5+QS$a zrh^h=7z2X=0|SF@I0J(Z0|P@`I0J(_0|UeAaEM1f*M~#mnkNDh1@aLL3|b5f3?>m! zgCih`vp9l*A&!B8VPym)iZ~(}7y=j=7~CTvAu}TqQjTnkggEd-B*cLiA|Yw(b|fTZ z9z{aZ%)dxb>Sti6mxzM+*dhwzkjN;A!8uV33~Lz}81_a%e3Tu{z+er^hS3lMw?;!O z+!GCnf^*T3#Cs(gV$O|dh(lgSLxTJ>RNbFwNFrs50n_yik}(j41~CwWEn*-B+s804 zXfQA^1jaCc+XGcGki=CV12M20s(wlgB;;m8#W%!2Quodn1_n?Y=2Q&C;eTQn7}6LR z7%XBL7;+dG80N=<f$n@sKFdjE97TdpyMasCbC^1@VxQurZ#2K?IcluR%4uj)w##X95F5 zG6Mqxe*y!jre!EjU|{fMU|`sl00|kEM2I@EL`WKuNrYHnkO;BREfEr;k%>Q^)w0M z;}1y;4B89~47|w<3`PtL43^0deoitZ5zk0wU@&H2U^tx2z@W##!0 zT2v_v^$aEq3=Hil5Cit4K=SeX6o^6UsgN`g45gz|A!#8I%1=v$_&hfi5;D!H5DTZK zLQ?z5RERlGQz20%m)a{xEDF=enAgMSZje$Xzfq@|<4PwxwG>DJZ zr7asp5@J6xA&HGO zi-92ploqle4k*fkh*xGoQhj3<1A__!1H+^&NCCpm>3usKIA|Q`kVtP33YNIKD(6*No)^uA!*}tE+lCA z^B_Sjk_WL!ArI0L(#?Z7%q9;Kf?jzL2ZZD?FmQqLe@Y(2!2CQ&+%)Dvd^#r&l1eu~ zH6Ddpa6XTLp$$~<?V%SV0v87eRa+Sp*5fgd&I!Gm9VwmqOLo7D0SA ztq2kl3!wDUB1raJ1=W9`2oe$}iy$F$y@;V6TyQ*t8Z221$$qNE5DPVnAqE;1gA)sb zc`?KRvBi)e%q)hKWR+0$lZzqQYYtT3{$hv+jzIODE`~V#I#m9CaXlo}KPiT|^nEb{ zLo@>e18WJyA&Dgr2c(ujQgK!Z#NukGcy|fJp%Y3VX=Y{#H0nwq4%<)y3G!1V5cBUt z^?faYWZPf$C6M}Dyc7~NVWp64k^<#-mO?C;UJ9{bK`F#xi=q7GP<5+HAr|c@g*fnR zDa0XnOCdr15z1#MgG9AR86>Lf)yg0i+Lu9sCZ!DG(i|wisSJ{uyUHLzKOM?nTn1^f zZ773;;Q2C0P~R$plxz>n7#J=vFfcHeLyF`p<&co%sDPvu-U_hC>KViR6;^vStX<%-%|;Rt6NZY-zygG%!r6 zAR$!%rE9A|7BDb$RY5{vQWc~FbF7Mi!I^=9fxDW4fgP0p{i`8yA6^Y{d1^Jp;GAkm z(DqhCd^Q6rzYxk_0Wtv8ZLfv|?ape5L-$ofO2pgMkSKds4GGC#PK zsXa?;A-Q02Eu_rfTMJDawUBC=xsIV8T+Qm&K^g|Jb&&dhN*x2ZTsTt)>FfQkgT$R< zJ;Z?t^^mx)sE5>^?e&n7b5lK}q&r&=aoE>-h=U~>Abi^fNJu6$K%zLa0ownsZ-7|P z-vCK8>lz?F+R*^XE+-lwQE{sQ630&)AP)G{00{}kMu>s@jgSyfZG_0%G(r-mcOyi9 zOe3T@pWX;b3v=rmA+6j;jS!!4H$eMu1xd~mA?;1GCoL`DXN zo6V5KV%^HXung2#Y=tCJmNrQ4P;6shkY{9IaB72esgl|m75G950ct<^)WCkWnf@<+Xr#!rxqTue5#F5$Nn7tGLPDH%614som;{L%$w`pJs5}W`pwA>o z$b?RU#CiWDh(XgQK@#VRNs!8D?IcL*-#CeZVFd#N!|_RwA)A895C?Cb3<;qNlNlJA zL2bk-3=B;S3=9*eFw}#GT1BQp43?e>NlZFZA&JRuDx^*5Jr$Cuil#y=YMTo2!JMg( zfr;f%@o!L?XBs4Al%_F&TSSJ_AO%kAG>E>9(;(*TnN|-e<1axaK1_oYjlZEZ<8+7* z*r!8+TxB{Wh!dtmf--M9B;;DBL!zjEIwYjFOoycUJ<}l}bQnq>hsvLx&cHC2fq~(2 z{d9sJ1kw4B63<~i z#9==3Ar1?k4~e3P`Je)-o`E3&svvnjBr#>phXnP``4AVMn$N(%$H>5Ne?G(^?-oED z@^1meA-oGA>ZKP#EYyM07Esz{A;d!g3n6JKc_Bn!!$JlISy2A(TL=k(H47m@xqTrd zj?XTHxcL4;NLl}6AtXu|7D3c;E`s<(ei6iA^+k{naDmE4FM^byg^M7AP?Hxy9C`$* z?&=~2hI-JH$eTrw#KyQ7;$yAF5TDvFhFIXg7~?&hQ#$EsQ8M- zkdWBE7?Q{iFNWl@yHNSxiyW-I*m2hhBr4duK^KM8T^i5SRX00tqUyr4R?X zFNIhT0Odz5g%m`|OCeEGz7*oq$x9(c_I#-N<4|=MmqMcE=~75kGA)B7M)qZpkmaji z2Jwm5GKfOGWst<;y$n)z$1Q_c)UpiXpashy)$z(@kPte%4AOA90p)*R28lwZ<&dZm zUk-_L%jFRDUdtg44qXm$NPXgRh=z>iki=8F9Afd5<&Y5BwH#vcmF18$aCbQ*MBYFR z{08MSu7Fs;y#nGuu@w-HSgnAl_gw)=wBait9?o3>4uN`x))kQIwRZ)iq+7QFQf(ez z0rB~l6%dCBtb`;Y^_7sJ7T1*!i}F`OES|g)V$r;n5TC7B2??3?D2U|Pih>J>2vuYzdoS_KJ_iK`%KV;NL@$0~>c`&U6i==>^(kG`&gwB@*0 zGcfdn+6}8A1<-@l5R19jKtfJp4cNyF>T4Jn!a*}9YZw?LK>5ENDzRV<1H)zp28I=D zAVqAHkM+>;|LFCQ`nhsFWR!Z_dPwEMyaAF}*f&6;LU;ox$QT&(H$V(@fXaJqfcP{F zsxBEy*F)9MhSF=G^j@gGa~l}y!IRFnHb8>*JJewIjSvS2ZiG~;q8lMDw%Q2sneRqO zoR@Bdq=kl!3=I09w%Q_Zup&ya^KYzMCLLeCQ@fExQENVF1l)9oYmi;PEC% z!6CdEGCiiZ8PWo3*bH&VuFVV#>7YTS&5-KVeG3D_N6_ro7D$UGW-9}OD@cATBn_!< zgY=}Vwn0L2!!`zn4WLP^Z43;H85kIH>$gJ^o!|~gs+8CPu}FUhB=v^ufW%?(4u}sb zcR+GS;|_=e*6n~q#YL$6?H!O7&*L4Cv|zpyVt(XKh`9+nAyL)36Oyg#C+&n}yV+2Q zEjuAWdvGTtM9%Dl_~g${28Kii1_r@h5Ce*LK`d_A1#wu{E{M8GyC5D}z6)Z`zFiCq zw?Q*1yCALJrMnpzq8Jz$uI~nS`|BBu_CWG=-yVoV*6e{~tD}1$8gB1_L<#R+1_o~i z1_q723=EYF3=Abu{=2;l45mf)F>GUB;BUbn@ zBvJYwW?-n#XJBABdKi+*O^-l)n12M~vxXy(pzAvValrZ`kf?Za1X2+FhpM+d3Q1gk zM(xhWM2BCG2G1P;L-jHJu1*f4B&yGP78SilhhAIXI z2C3r=46&f;wBrm6kqitBpN~UIM&A>V5J^1&ad`F#NG)1(0uqHYPe2mqrW25Cx9bE0 zLk0r_L-t9C_?45;0fIXxAwkV}3X<()PeFWca|$9JdkRt;R-S^y-Q-h{5Sn!gGPAMb z6r_)L{S>4q=06ST=LemJ@HWI@&THp*sJhc7{r0AV-hJnGKfq~)b8AvKuJqwv6 zDm=@;;K9JaaO^B35%HgcI6&eY#0T={AmZxhAVF<#4w49C&Ov&;h36n8=8{IAVq1; z1&F$y3y=cp)CC3xFVLLN1<2@^(?!S-PuWFCVqAL>976RBUoS!ugZ3pzeh<0?iPM%# z5Fd73g7|3CB}kkvhl=mN1W9DaFF``&)g?&c`*;Zwf>M_u=A>PQ~*lPi#t@!b_jNU&aIU@!&cf19h2G*EOE5|`_*LK4-Es}O^qUxirs z?JC3vY}X(T6}|>>sM$4$!yK4h_8tiITXRkhD;C6H??Z zzX>Uz)adV-F!gf9fH`p*J5w40`zx5`rJ0>V7?hMCHGSkRn<15hR3+ z9zn{B;74Ew)iV@7f)p54k03?l@<)(t_vR6#MEms!VzAm{2(AAZk|-@6gAHJ?ehdj2 zr^gTnc|3-snTW>_iwhq^;=1oK#OFI6LqhBnSiYWt;n`zIkTO4k_}uCV#7D7DAZ30k zlwbb@;;{B75Qj{C0*RV=Par;8{{#}Z=b`eqpFpDE$rA>KPYetUVoxFChn&wKAs+sW zfq@g0|6`s(3`~2*z)%eusf6-hKVx7>04>RU1~EAFIfPDp4vFjB=a3L+ehzV1*K>%2 zW4_}t_LB%9g1fcVVq1;i(5 zPG6Dh0jaDMUP8)+%$Ja$ZhQ$bf9^}ji0R6gkh$WQFB$5=^|{|G zNa9=Z3gUy!uOJRM@(MCCdJf8Gd<_XH?$;29ioAySQ06rx4QRiHSY-GbQc2mqh7|4D zuOT7U`5NM(`L7`k-2WQ1{u9(1eGPHIz1NV$^YS$$^)kI-VA#pPz##bsl7BD1fyn=S z14*<(Zy|j9w-AR$K>6KoA&G9uTgVcQb8jJSM$vbWko0>8DdHRIp^WwKASKhicaVBo z=sl!72z(EzMwh&Yv$_z zQ=XrYptt(Tz)-@-z!3ctl1484f~<5>{S6LchMwOL@#DWCX+-7^BoW5`VPL2SEwSqV z1Bt60e;^9(|6yPdWn^Gb_zS56%>F_0_1b?BhkpA9nIVz<&%hAM$iPtWA5yX%V_*bl zXAwq5@M^a_Mn;B>3=9mr85zM#v2vLh!AmyhGckgv{q8U^)`J(7aWON32cg}V8NmyN zT9_HZYd3ZuI+2YLycFv)8zXp)_d7O5 z@G@Rzc1G|*Mk#hi@T$5%c1G}m zgM$&=uQ%dg1TR>u;9vx=if`m#1TRkO=U@b{qMgFQ2wuiJgM*P_Hv*hY`HY<}VM#hf2H<+J%=9+-pwbWdtvFeZUJb zr(TQ?Vu2nXM58YsBM2xSND!hLmv1H&^xMh4J&;ngCLH1I)$ z5!}{P7lot+b5TYHFVOn`BvD9eTr0{59$>gF%E<7Bfq_9?3=+2@;*gM#6o&+*wm3xG zSDX>tnG6z#gurfbNMgM$4)O7Safrj%Bp@`G1VkU71SAm(OE5C9f%3nO1UM)dj3pp0 zv;|2pFfjN^KvHvv1S11z5ox9bB!p&3FoL&Gtd@X8!7ix!vl5J;Efow`pcdShfTWop z5)cpQN3vxnIMH1sJ;Igmk%bHl411Xv7&w_27&;jtL$*nb3=F|c3=DqtObiTG zObiUO85zL2U_BE9gA_9Z!%;>C24Q9f1{EgAU~vTlr1H1`H561Dg7)oLFfuUwfQn6r zS`2aw2!j?bFJfe1kY!?ESP8P2iGiV%k%8eSXc;~zbeI_!>i04-Fq~yzV3@$fz`(}D zz~I8jz+lD5z+eD!9n@fuVV4;o)i8+t3`u+g)Y2tP3=I337#MaiKpGlTKp_ZP`^f+u z8D)f2&mjFEJd1&W!I%*i{tS?gC1^2u7n0#3ObiSW3=9k#7#SE=GeWA}$xsVHdwoDF zqCtioVq#!uV`5-PVqjqCW@KR4&cwj52_(V5z+eM4uZ59;!IY7K;VL5o0}m5q&jBd? zftT1$04<|qf;1?;GeE}iV;LD3&M+}BD1w&KF)=Xw0IdTD`3e*|jF2@vm!XakWoBSF z&cML%2WlC}Zf!;ehIxz(4DpN%44P1J(9WkIMh1ooC?D+q1yDo2GcqvLfU*rE0|Oru z149{9ycen%RH}gt24T>m(_f&q0!$1H983%hF-!~$E1>EZGchpC2W`s%EoOk~tz~3j z@M2_OFlJ%^SIMC908o7aDt|!cF?29O77K$o0?Z5yPeJ*Wk%8egNB}h43L52RWMHUc zWMFv0$iN^5+B5>1tYBbZFkxa~P-bLcU}A>Mlom5U1{y*8L*{|f1t`Rz=71<(CI*IP zMg|5GSp0(~pg|HKe1?&M;T|Ic!vRJHhG|R;46INefaC(17#MCcLB;?NFflMFF)}cC zGBGgR07*h|2&h5A2pJauZB%>A$iT24DhKmzCzSt=u^uv9zKM~6!G(!|feUJx3L~Tq z_mL6OXauQOU}RtbWmgb;DkG$``4*Hm7#SEOnIJtHPpJL|Mo3G^78)h9L2LgR85p#g z7#N-~K)Q8tObiUIAOk^5tw4stFleo|FcSmAI;de6poYNYnV{lojF8R=XnYW~AO$4v z%gDfx3RORqiGkq?0|Ub>CI*J*ObiT}ppg)$-byA0h7cwOhWZw$;tnPThLenthUQ5o z28Jn6anPQ>s|*a_Mv6QW1H*Pk28M5p3=HDT3=H;+3=HQO7#Ji#p~b|&u#k~~p^1rs zVKvAl3=9l_Pw;U^OVLkj}~!!ytVbw&n;TcF?uYhqxKWrVch*CSZ~+V3$3lo%Ny zyYLGBGePL$g&jC_gho z780c~F)+9>LV8CVkt}2fr4i7CBUEe+69ay0I??L(B70StFWMEJOwE-9)OKMgzGB8Yl$_0ab0cGWO9hmem>3wAGcYiGV_;xl0kxJGAU$TN76xxniO9sj;LXUu z&;=Dd0;+tVY!H>m#K7=|k%7ULiGhKMiGd-HiGiU2oc};=I3`Fx4x}&}L_qOHsN*D= z85qPF85qo%7#Mn(7#OOU7#J)-1q#%$cbFI$wnEvlObiTnK+AWbdN(mKFjO-!Fsx#N z^q!9~F)&CnGBDJF%mCNF3=9mHpqfGUUIS%EsOC$c5CI8-_W41@Kzn))ftpkd3=D2e z3=9H{3=A?%3=A`%W;8=-(2kkYP&R0r4lgqU!y+a~5BfA{VKQh)j;Wr3VJ#D6ncZzr zoPz3gP$FYwU|0s#ti!~>@B(Ui3aAmmz`*bdD#s0~2bdTbgcunZj2IahL>L(ut}rn$ zsDhevj0~WaIt&XK7#PZ#7#O}lJpx*qKc5LQ00mzE2NG|CT9C)Uz;FPhfdSID_hN!f zyMngO9cE-;Si=ArB?ajL;T$FghDV?l5(8wp^#`aq{!kjE<}1i?ObiUinHU%}K=nVU zSY~8kcn6AqA!Y`KZBXAxFflOP1FcMEVqmCXVqlod$iVP`iGjhLiGkr4D78Y>DKarI zoJFz#Bs>F@g+UC^d?FJALkXzi%EZ7R3KcU0t)K#>9Z*va)Y1Yi-2~tSSIc*F#mOg_iNz%U0i*#xx=v^fzpCk$H72~s-| zL_o0zBLhPOBLhPUC|beoF9yg!Gf3VXv`q@s_hVvUI0f1|g=A?qBLf376J%2fNUaVd z1H%U<28J$B_GDyWNM~YT5N3qz6=7$F%zA^=f$$+v8-am=VIinN19jvU5DhMWK??>z zEnrY>$H>6&mVtrc3aH@-(h1sf2X%xgD4#PjFx&!ZL@IbxL3{=VhB_z>)dr>xLiK_; zHK5WIss=PmVh1Yra~K&IbQvMzJje4ns75swIpe>l7&BP!Bl0jWEP}YGu3bc6;G#SkSj zUlw;@E^2Rn2CWQo{53M7t}t0+Ody`f#D#ihXb+%G*$Wu zl)piB^yH1s!u8QmWguD5ZXXa`0E!?`WPzHONb=^Oe89xO@R12JkXHmM6`;-n>C<9j zVEDuYS-N5g%DhYr3~L!7OHe@apiTV0q2{dw?X3o7OppW&gLZfyg`N^|o{51W1FHBG zsLjmGz%Y%Gf#D%kYzN5iP&P=v5EEopm9Q0 zq%;mwqzmdgFfcG|hY5hXA5iulMg|6Mu%5}!Toy6~cuuZ!Rh_)sHILsdGbdHoF*!N4 zxLCn4z;m*ko0fHcQEFyhW{HAt07!^I%^5C`nwwu#i6$75QIwjP0u`L>vq*Weo7>9C ztnS8a5k?@<$)@hQe5oZRnR)37#U+VFC8;Ts9Yn@XTlA(#S6;$;{77%+Z`2 z;ccd>kX%|^lAo)Po0F_ikXVwTkXDqRtB|NrP?TDhnO|D0;GCLUI(hC4agntA(!3Of z#Jm)Rw9K5G)D(rxJiW<1-b*)|`P^pQEa?}_s8*tolbTpuqL81Ls*qV+T$-wokyxyd zl$x5S0M^amSelZVznLdsIpgF<%3mDjt=^61y+)plbT$TngVyfB9}|PLS=rbLV03di9$)f zLNQo{LSkNiNk(cB*pK#;ZG(SIt_aPZ%o1i5Q(BOcSdz*B@+ZWiqSV~f+@#bZkTFFV z;ggxCpz7oA?C9ed5a8k%;;5<*)|r-Hq>z_du8^5mT#}fRlL!jqV!h4vVLD8cpF||G zmSOs*hD!u?v7nOY7Gxs?3!yqx^Rl++Z3 z^rFOqj7(7ECTADhGq~jEsh21eXXJwvW)>?XrYC0RO}?9`GubssVY6;h3)AGUDVm%L z`FS~+d8rDyn?+KSStno5x+tfo;F(vJn3I{JkeHmDUz%5s{P~@*^UAV z8ktZfetw=V_L`GlW@k+<%#qMc%*;tm(Nl1QYD~#bEmp|OFM-5qL1J-nd45rfLUC%z z=Jp&x=E>{w!|Mz3i;FXpGIKIZDnZehoROH9o~lrkTAZI#3JP2ug_82r#B2q(fM8JQ zC8ne(Kw`Kov$!-d2PBrBn44OVlUS*co1c=ImYEE8X|W!c3p8}VL6w}Jn_HR(vIQli z_(7I}LLZg^XBWhoC}b8ZRHlNH6)1Fd6pHg9Ne1MXq*R5{;?xv{q)M>4u*5t0XTkHy z;zf#^or=D*u=_YG1SFPZY&I{CVVu0UqL$q+#L?Zz&~&nVWwjQ-sYJ#dl)C@)&1LCUVnwrHxWG}a)o51 z!gD<+V!(k9%J3y1w?hmpO3g_Gl@4i{IjO}8Ihon13dM`R!g}hWyC6ZWFsQ@ZH5{oPI zk~50(^FXC;aYiDjSV+##Ey#ovCVC2v$O@A4bL(MJ3dxCiNGVW{OMxpWwXig^C^ZFP zo0USCcf4yvNPIzNK`JOvV}f^$TCa$<5uYJ75jUP)1Y4i}dvqzD5=7pRB@g)RF*i}TQlU6Mrwo+VGK&>bLFJa-`(#L}D+1z#U$aNz}toys&$ox`JpeQ8f6oYDj5{1N+luS^mk(dK^QL#d1 z9ym_YQ}a@b5_3RB52(5=R>)7A9MqR&4X%#L6N?o}^AeMCQbC155+v=U5UiWl_m$Mc ztJBP4usucj`6UXlvOWzgl$u)#3fdHC+Rw}@NiE7t%uz_oNi5D#C@#q_N=#4HQ}8TN z0L4sVW?r#EVonYu7(j`*SO-?wq^2l9Dltd~cJXnpFV^GoECGdkaY<2rUV2WYLQyKH zq)W|9ffNm(DiWLkQWX*vQc_burDJLe%!#1%m|21)gmZI}V>A`GJku0%QqxKlQgaJR zpp`Yq$50QJXR7ApC?usSKr8^Y6pAxbK_@iFx1xVKdugR(2tUg4Cki#5_<6frijz_F2Z0cg{L7xo!5c$sKciH-DMK z!?=0+yiBIaTrEnIe=nG<9+_WS1S%>F452nF6sM-<7DFR7H?tU2H0g0owwWi-0;+~5 z7xs##Kq?bRF#;|=^tix9PHIH~q{RU$CKNJ@t+=XdxzHOO5RZeS85$;ukTL*8xBcYa zh53^U7uihSw@5_*T&aUoCqrIpS!&T_+r>I8pmZ}iV{sXTad+`;UL##2O9ewCD`Nv~ z1H;Wnm-I7oIRKmFtQ89uhBjK^%E5vusS0YaQYo_-T$(7Pq$;H4 zlvW^gt2q}PUYS~?P@1Pu1divT z)#TKo$){IX>x1PzjLb|J)EqNYQW?}d^OB1Wugpyadfwrc3Mq+spu!>*mM0-$ zk(gIXTDi;y)qM{!epO~Qk(NO)-!52mMY}tgNlUGyi`!pn_60=05iBK zH4ju`fP#Wy^RCU&Op_C~U3LN|hLxa7C9zZ?1=P3#)l;d(3Yp1=x8$W3>nP-;BH~9O zPd%};C{dvxu~;ER9in8i{WXcrcH0dZCqLSyXsM8#k)K(dsi4ReoL`!em|2oqrCSEB zx(=@dwaGI<%?xm)Czh6gybra~eskguX~xNNyPGE;-R)@Ln^~NyaCm`27AV$JAmsz3 zEnb|eP@G>{mYJHDQUofZ6w2~Tic+UflwcGCg}yZ;$g#D>3qWRpD*U|s(z4VX5DQvW zgJY#wZ*%mXRZNrp_m}8_{ZL$-TBVSa2r6emEhA9Xe0TvUxq_NSnaQaNexSlRFC~9- z?g3wx$$3Y(e2Vi+i*;e4n2*R`MWA}O7~(WYhK4lhLGc4=)PoW}C?_U^YC;8YyMEP? zhRxYWgP5T0`oqT$FnOT`YFU0}kpjpg1&PVo#n8&Qur#$;q2%z&oWm=VGZKr^53ej% zuxIc~RVc_QEmlZO17-TuqRCCC?3i*=CySp}oxJ<6)aJjZa+xP@KW8kQ3NjJYHcnMY z%~Qz9OwUW*{N!8~`}FsGjNFs2UAt?io}W~bng_C3{qV|?#1e&+QUy?xqy$tiAsYXn zqzw^P$ji@D0Cy5n73?QpydEy1paE*lp@?fv*XL)Hoa}g`Wb%_6l7@#nlQUA2^%Q(k zp=N{99wgzVD&*#ufJ_H<5mFUW4zEnh%*)*T=f+Rw$$WQvSyJ-z@+Qx}s~69eqMlfq z4k-`7!Q>VYtfP=$s*s|dn3Z2z0!`{D{Qw0}M*)&LKnhdAZ3|F$L60j05vHJ&0SY@6 zeg$x{LKIBt_cB9$pjks9Pd&A`1ng)~<||57fJR8FjsnOEg}hWy8#_@UB|i_;6)RSN z<@Z#GvB-IE^R;_2jFU|tXl~AW5Xi>soRONFnFk7moJ57q+n?=WoZS0jf~s?Bawd|s zrFrl&-p|ch0oJY1dD$-Mn_66)n4VgU(y4GPO)i~$@s;G{S+6B!0uqZ7a}Td5DM~E{ zMR6{uzW`4XZ(nyZ)(7WTrdEM6NO5vzYFGzZBfw&|?ToEd>p9R4J5}Y;Jrj%Cvdk`%=cuJ|8=o zruR!QO4O&MLbc}RBy)jMFLFeInnR!@0gGoyG^gejrKV>VmlT2XUNJ1nilMO!X>F9G z=D@+pPXcx5W#hRJjuR>nFJh%-Q$ zBqtHn+6M*0WWfz$^&l>+Nek&*fvWSOJa8h&NrdElJuc52P)Sq*D&7=IKy^m30w~~+ zG9WDD!I~@3M#bTksmNInY!WD~rR5iuq~@mb=7D=~#i^M&IfqwHpU2E7n*vER$*DPs zpgtCQ=tDbM!O+4jCovP;LP-YKD!By;Wtl0EP=P0fR8aE;ROA$=79}cx+Qx@hPBwfe zJY8Rbk(F7GOJRE(E2AXS_IwV;S&WEk7UW7$*3HR0yb@HJltQ{%+gZ67r*X=Kf}5n^ zk_yxvP0mhC2W3xa|7-dzVMhP$6GRwA7^klkWjs3lxfr9zc0X}OXU6SOl8hG2JYk^r z8q~7M>%J>YpDe?8LSX68<`tHv7U^+Kza_z_IsGsvqgXw9n1dSb zpwtN}^S}*Dq(T&&ob|XsWiibB#FCQKyp&Q1;$eV 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 dd28ceb5..72bbcf52 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 1e92527e..44d69c6c 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 80ac6cf0..54e2012a 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 d97d6dda..686a9d08 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 5d9f84c2..19a7ddd8 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 dd7c9189..5a0ddc59 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 e9081521..b66326d7 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 bd394479..eaada7cb 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 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 OJD+MZZuWS7gB1WXx5wB3 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 75ff02ba..56a3ab12 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 0489bb4e..6bde2a0b 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 f464c7a3..12d1d975 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 6df53da4..ce97b5e9 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 760e5b66..7ab25f68 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 54e2012a..5b5cff6c 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 309394e6..c87cbd39 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 ab44ef4a..ac793109 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 24617791..7c95a1a1 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 68b05165..40b9c643 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 142da7e4..7825e4d5 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 61707519..d4df4343 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 f91c1e3a..50ff3b89 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 5af88176..5ac5ebfd 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 e69de29b..00000000 diff --git a/src/util/containers/robin_hood.h b/src/util/containers/robin_hood.h index 577521b1..4f76519f 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 52eb8a88..a5b37a5e 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 b8002261..2ab37376 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